|
13 | 13 | use Amp\Sql\ResultSet as SqlResultSet;
|
14 | 14 | use Amp\Sql\Statement as SqlStatement;
|
15 | 15 | use Amp\Sql\Transaction as SqlTransaction;
|
16 |
| -use Amp\Success; |
17 | 16 | use cash\LRUCache;
|
18 | 17 | use function Amp\call;
|
19 | 18 |
|
@@ -64,14 +63,18 @@ public function getIterator(): \Iterator
|
64 | 63 | $this->statementWatcher = Loop::repeat(1000, static function () use (&$idleTimeout, $statements) {
|
65 | 64 | $now = \time();
|
66 | 65 |
|
67 |
| - foreach ($statements as $hash => $statement) { |
| 66 | + foreach ($statements as $sql => $statement) { |
| 67 | + if ($statement instanceof Promise) { |
| 68 | + continue; |
| 69 | + } |
| 70 | + |
68 | 71 | \assert($statement instanceof StatementPool);
|
69 | 72 |
|
70 | 73 | if ($statement->getLastUsedAt() + $idleTimeout > $now) {
|
71 | 74 | return;
|
72 | 75 | }
|
73 | 76 |
|
74 |
| - $statements->remove($hash); |
| 77 | + $statements->remove($sql); |
75 | 78 | }
|
76 | 79 | });
|
77 | 80 |
|
@@ -143,18 +146,34 @@ public function prepare(string $sql): Promise
|
143 | 146 | throw new \Error("The pool has been closed");
|
144 | 147 | }
|
145 | 148 |
|
146 |
| - if ($this->statements->containsKey($sql)) { |
147 |
| - $statement = $this->statements->get($sql); |
148 |
| - \assert($statement instanceof SqlStatement); |
149 |
| - if ($statement->isAlive()) { |
150 |
| - return new Success($statement); |
| 149 | + return call(function () use ($sql) { |
| 150 | + if ($this->statements->containsKey($sql)) { |
| 151 | + $statement = $this->statements->get($sql); |
| 152 | + |
| 153 | + if ($statement instanceof Promise) { |
| 154 | + $statement = yield $statement; // Wait for prior request to resolve. |
| 155 | + } |
| 156 | + |
| 157 | + \assert($statement instanceof StatementPool); |
| 158 | + |
| 159 | + if ($statement->isAlive()) { |
| 160 | + return $statement; |
| 161 | + } |
151 | 162 | }
|
152 |
| - } |
153 | 163 |
|
154 |
| - return call(function () use ($sql) { |
155 |
| - $statement = yield parent::prepare($sql); |
156 |
| - \assert($statement instanceof SqlStatement); |
157 |
| - $this->statements->put($sql, $statement); |
| 164 | + $promise = parent::prepare($sql); |
| 165 | + $this->statements->put($sql, $promise); // Insert promise into queue so subsequent requests get promise. |
| 166 | + |
| 167 | + try { |
| 168 | + $statement = yield $promise; |
| 169 | + \assert($statement instanceof StatementPool); |
| 170 | + } catch (\Throwable $exception) { |
| 171 | + $this->statements->remove($sql); |
| 172 | + throw $exception; |
| 173 | + } |
| 174 | + |
| 175 | + $this->statements->put($sql, $statement); // Replace promise in queue with statement object. |
| 176 | + |
158 | 177 | return $statement;
|
159 | 178 | });
|
160 | 179 | }
|
|
0 commit comments