|
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