diff options
| author | root <root@kabir-PC> | 2016-03-23 11:31:51 +0100 |
|---|---|---|
| committer | root <root@kabir-PC> | 2016-03-23 11:31:51 +0100 |
| commit | a26989103d70fb0dd3ff6834de107cae246778c3 (patch) | |
| tree | 0f243c83b790ffb57f19261fc2a509131f6776ce /server/vendor/guzzlehttp/promises | |
| parent | 1342db60283cb61a1c3810993575d35b9fb33ac0 (diff) | |
| parent | 6e78d76f887d1149ea85bfb06db7ee7ad7435f5a (diff) | |
Merge branch 'develop' of https://github.com/manzerbredes/istic-openstack into develop
Diffstat (limited to 'server/vendor/guzzlehttp/promises')
7 files changed, 100 insertions, 22 deletions
diff --git a/server/vendor/guzzlehttp/promises/CHANGELOG.md b/server/vendor/guzzlehttp/promises/CHANGELOG.md index 4031cb8..3871ac7 100644 --- a/server/vendor/guzzlehttp/promises/CHANGELOG.md +++ b/server/vendor/guzzlehttp/promises/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## 1.1.0 - 2016-03-07 + +* Update EachPromise to prevent recurring on a iterator when advancing, as this + could trigger fatal generator errors. +* Update Promise to allow recursive waiting without unwrapping exceptions. + ## 1.0.3 - 2015-10-15 * Update EachPromise to immediately resolve when the underlying promise iterator diff --git a/server/vendor/guzzlehttp/promises/src/EachPromise.php b/server/vendor/guzzlehttp/promises/src/EachPromise.php index 5918429..0344686 100644 --- a/server/vendor/guzzlehttp/promises/src/EachPromise.php +++ b/server/vendor/guzzlehttp/promises/src/EachPromise.php @@ -24,6 +24,9 @@ class EachPromise implements PromisorInterface /** @var Promise */ private $aggregate; + /** @var bool */ + private $mutex; + /** * Configuration hash can include the following key value pairs: * @@ -81,6 +84,7 @@ class EachPromise implements PromisorInterface private function createPromise() { + $this->mutex = false; $this->aggregate = new Promise(function () { reset($this->pending); if (empty($this->pending) && !$this->iterable->valid()) { @@ -169,11 +173,21 @@ class EachPromise implements PromisorInterface private function advanceIterator() { + // Place a lock on the iterator so that we ensure to not recurse, + // preventing fatal generator errors. + if ($this->mutex) { + return false; + } + + $this->mutex = true; + try { $this->iterable->next(); + $this->mutex = false; return true; } catch (\Exception $e) { $this->aggregate->reject($e); + $this->mutex = false; return false; } } @@ -186,9 +200,11 @@ class EachPromise implements PromisorInterface } unset($this->pending[$idx]); - $this->advanceIterator(); - if (!$this->checkIfFinished()) { + // Only refill pending promises if we are not locked, preventing the + // EachPromise to recursively invoke the provided iterator, which + // cause a fatal error: "Cannot resume an already running generator" + if ($this->advanceIterator() && !$this->checkIfFinished()) { // Add more pending promises if possible. $this->refillPending(); } diff --git a/server/vendor/guzzlehttp/promises/src/Promise.php b/server/vendor/guzzlehttp/promises/src/Promise.php index c2cf969..86820b2 100644 --- a/server/vendor/guzzlehttp/promises/src/Promise.php +++ b/server/vendor/guzzlehttp/promises/src/Promise.php @@ -61,17 +61,19 @@ class Promise implements PromiseInterface { $this->waitIfPending(); - if (!$unwrap) { - return null; - } + $inner = $this->result instanceof PromiseInterface + ? $this->result->wait($unwrap) + : $this->result; - if ($this->result instanceof PromiseInterface) { - return $this->result->wait($unwrap); - } elseif ($this->state === self::FULFILLED) { - return $this->result; - } else { - // It's rejected so "unwrap" and throw an exception. - throw exception_for($this->result); + if ($unwrap) { + if ($this->result instanceof PromiseInterface + || $this->state === self::FULFILLED + ) { + return $inner; + } else { + // It's rejected so "unwrap" and throw an exception. + throw exception_for($inner); + } } } @@ -257,11 +259,10 @@ class Promise implements PromiseInterface $this->waitList = null; foreach ($waitList as $result) { - descend: $result->waitIfPending(); - if ($result->result instanceof Promise) { + while ($result->result instanceof Promise) { $result = $result->result; - goto descend; + $result->waitIfPending(); } } } diff --git a/server/vendor/guzzlehttp/promises/src/TaskQueue.php b/server/vendor/guzzlehttp/promises/src/TaskQueue.php index 5026363..39fe5bb 100644 --- a/server/vendor/guzzlehttp/promises/src/TaskQueue.php +++ b/server/vendor/guzzlehttp/promises/src/TaskQueue.php @@ -56,6 +56,7 @@ class TaskQueue */ public function run() { + /** @var callable $task */ while ($task = array_shift($this->queue)) { $task(); } diff --git a/server/vendor/guzzlehttp/promises/src/functions.php b/server/vendor/guzzlehttp/promises/src/functions.php index 89c6569..2fe61b7 100644 --- a/server/vendor/guzzlehttp/promises/src/functions.php +++ b/server/vendor/guzzlehttp/promises/src/functions.php @@ -146,9 +146,9 @@ function inspect(PromiseInterface $promise) 'value' => $promise->wait() ]; } catch (RejectionException $e) { - return ['state' => 'rejected', 'reason' => $e->getReason()]; + return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()]; } catch (\Exception $e) { - return ['state' => 'rejected', 'reason' => $e]; + return ['state' => PromiseInterface::REJECTED, 'reason' => $e]; } } @@ -304,10 +304,10 @@ function settle($promises) return each( $promises, function ($value, $idx) use (&$results) { - $results[$idx] = ['state' => 'fulfilled', 'value' => $value]; + $results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value]; }, function ($reason, $idx) use (&$results) { - $results[$idx] = ['state' => 'rejected', 'reason' => $reason]; + $results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason]; } )->then(function () use (&$results) { ksort($results); diff --git a/server/vendor/guzzlehttp/promises/tests/EachPromiseTest.php b/server/vendor/guzzlehttp/promises/tests/EachPromiseTest.php index 0a0a851..08af2a0 100644 --- a/server/vendor/guzzlehttp/promises/tests/EachPromiseTest.php +++ b/server/vendor/guzzlehttp/promises/tests/EachPromiseTest.php @@ -39,8 +39,8 @@ class EachPromiseTest extends \PHPUnit_Framework_TestCase public function testIsWaitable() { - $a = new Promise(function () use (&$a) { $a->resolve('a'); }); - $b = new Promise(function () use (&$b) { $b->resolve('b'); }); + $a = $this->createSelfResolvingPromise('a'); + $b = $this->createSelfResolvingPromise('b'); $called = []; $each = new EachPromise([$a, $b], [ 'fulfilled' => function ($value) use (&$called) { $called[] = $value; } @@ -54,7 +54,7 @@ class EachPromiseTest extends \PHPUnit_Framework_TestCase public function testCanResolveBeforeConsumingAll() { $called = 0; - $a = new Promise(function () use (&$a) { $a->resolve('a'); }); + $a = $this->createSelfResolvingPromise('a'); $b = new Promise(function () { $this->fail(); }); $each = new EachPromise([$a, $b], [ 'fulfilled' => function ($value, $idx, Promise $aggregate) use (&$called) { @@ -291,4 +291,46 @@ class EachPromiseTest extends \PHPUnit_Framework_TestCase } $this->assertEquals(range(0, 9), $results); } + + private function createSelfResolvingPromise($value) + { + $p = new Promise(function () use (&$p, $value) { + $p->resolve($value); + }); + + return $p; + } + + public function testMutexPreventsGeneratorRecursion() + { + $results = $promises = []; + for ($i = 0; $i < 20; $i++) { + $p = $this->createSelfResolvingPromise($i); + $pending[] = $p; + $promises[] = $p; + } + + $iter = function () use (&$promises, &$pending) { + foreach ($promises as $promise) { + // Resolve a promises, which will trigger the then() function, + // which would cause the EachPromise to try to add more + // promises to the queue. Without a lock, this would trigger + // a "Cannot resume an already running generator" fatal error. + if ($p = array_pop($pending)) { + $p->wait(); + } + yield $promise; + } + }; + + $each = new EachPromise($iter(), [ + 'concurrency' => 5, + 'fulfilled' => function ($r) use (&$results, &$pending) { + $results[] = $r; + } + ]); + + $each->promise()->wait(); + $this->assertCount(20, $results); + } } diff --git a/server/vendor/guzzlehttp/promises/tests/PromiseTest.php b/server/vendor/guzzlehttp/promises/tests/PromiseTest.php index 946c627..599d8ae 100644 --- a/server/vendor/guzzlehttp/promises/tests/PromiseTest.php +++ b/server/vendor/guzzlehttp/promises/tests/PromiseTest.php @@ -172,6 +172,18 @@ class PromiseTest extends \PHPUnit_Framework_TestCase $this->assertEquals('Whoop', $p->wait()); } + public function testWaitsOnAPromiseChainEvenWhenNotUnwrapped() + { + $p2 = new Promise(function () use (&$p2) { + $p2->reject('Fail'); + }); + $p = new Promise(function () use ($p2, &$p) { + $p->resolve($p2); + }); + $p->wait(false); + $this->assertSame(Promise::REJECTED, $p2->getState()); + } + public function testCannotCancelNonPending() { $p = new Promise(); |
