From 629b74e504dc16344a53ef6c300e2b555a83a829 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Thu, 12 Dec 2024 18:58:30 +0100 Subject: [PATCH 01/14] Add a semaphore store based on locks --- .../Component/Semaphore/Store/LockStore.php | 73 +++++++++++++++++++ .../Semaphore/Tests/Store/LockStoreTest.php | 31 ++++++++ 2 files changed, 104 insertions(+) create mode 100644 src/Symfony/Component/Semaphore/Store/LockStore.php create mode 100644 src/Symfony/Component/Semaphore/Tests/Store/LockStoreTest.php diff --git a/src/Symfony/Component/Semaphore/Store/LockStore.php b/src/Symfony/Component/Semaphore/Store/LockStore.php new file mode 100644 index 0000000000000..24a4d12529caf --- /dev/null +++ b/src/Symfony/Component/Semaphore/Store/LockStore.php @@ -0,0 +1,73 @@ +getLock($key, $ttlInSecond); + } + + public function delete(Key $key): void + { + $this->getLock($key, 0)->release(); + $key->setState(__CLASS__, null); + } + + public function exists(Key $key): bool + { + return $key->hasState(__CLASS__); + } + + public function putOffExpiration(Key $key, float $ttlInSecond): void + { + $lock = $this->getLock($key, $ttlInSecond); + + $lock->refresh($ttlInSecond); + } + + private function getLock(Key $key, float $ttlInSecond): LockInterface + { + $lockName = \base64_encode($key->__toString()); + + if (!$key->hasState(__CLASS__)) { + $limit = $key->getLimit(); + + // use a random start point to have a higher chance to catch a free slot directly + $startPoint = \rand(0, $limit - 1); + + $lock = null; + for ($i = 0; $i < $limit; $i++) { + $index = ($startPoint + $i) % $limit; + $lock = $this->lockFactory->createLock($lockName . '_' . $index, $ttlInSecond); + if ($lock->acquire(blocking: false)) { // use lock if we can acquire it else try to catch next lock + break; + } + $lock = null; + } + + if ($lock === null) { + throw new SemaphoreAcquiringException($key, 'There where no free locks found'); + } + + $key->setState(__CLASS__, $lock); + } + + $lock ??= $key->getState(__CLASS__); + \assert($lock instanceof LockInterface); + + return $lock; + } +} diff --git a/src/Symfony/Component/Semaphore/Tests/Store/LockStoreTest.php b/src/Symfony/Component/Semaphore/Tests/Store/LockStoreTest.php new file mode 100644 index 0000000000000..f3ea398c0f4a3 --- /dev/null +++ b/src/Symfony/Component/Semaphore/Tests/Store/LockStoreTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Semaphore\Tests\Store; + +use Symfony\Component\Lock\LockFactory; +use Symfony\Component\Lock\Store\FlockStore; +use Symfony\Component\Semaphore\Store\LockStore; +use Symfony\Component\Semaphore\PersistingStoreInterface; + +/** + * @author Alexander Schranz + */ +class LockStoreTest extends AbstractStoreTestCase +{ + public function getStore(): PersistingStoreInterface + { + $lock = new FlockStore(); + $factory = new LockFactory($lock); + + return new LockStore($factory); + } +} From 7371d7ce8e7317e81cb01ee1139ddff77fdd2ccc Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Thu, 12 Dec 2024 19:11:13 +0100 Subject: [PATCH 02/14] Add handling of weight to lock based semaphore --- .../Component/Semaphore/Store/LockStore.php | 73 +++++++++++++++---- .../Tests/Store/AbstractStoreTestCase.php | 1 - 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/src/Symfony/Component/Semaphore/Store/LockStore.php b/src/Symfony/Component/Semaphore/Store/LockStore.php index 24a4d12529caf..6423876986f60 100644 --- a/src/Symfony/Component/Semaphore/Store/LockStore.php +++ b/src/Symfony/Component/Semaphore/Store/LockStore.php @@ -5,6 +5,7 @@ use Symfony\Component\Lock\LockFactory; use Symfony\Component\Lock\LockInterface; use Symfony\Component\Semaphore\Exception\SemaphoreAcquiringException; +use Symfony\Component\Semaphore\Exception\SemaphoreExpiredException; use Symfony\Component\Semaphore\Key; use Symfony\Component\Semaphore\PersistingStoreInterface; @@ -17,57 +18,97 @@ public function __construct( public function save(Key $key, float $ttlInSecond): void { - $this->getLock($key, $ttlInSecond); + $this->getLocks($key, $ttlInSecond, create: true); } public function delete(Key $key): void { - $this->getLock($key, 0)->release(); + foreach ($this->getLocks($key, 0, create: false) as $lock) { + $lock->release(); + } $key->setState(__CLASS__, null); } public function exists(Key $key): bool { - return $key->hasState(__CLASS__); + $locks = $this->getLocks($key, 0, create: false); + + if (\count($locks) !== $key->getWeight()) { + foreach ($locks as $lock) { + $lock->release(); + } + + return false; + } + + return true; } public function putOffExpiration(Key $key, float $ttlInSecond): void { - $lock = $this->getLock($key, $ttlInSecond); + $locks = $this->getLocks($key, $ttlInSecond, create: false); + foreach ($locks as $lock) { + if ($lock->isExpired()) { + foreach ($locks as $lock) { + $lock->release(); + } + + throw new SemaphoreExpiredException($key, 'One or multiple locks are already expired.'); + } + + $lock->refresh($ttlInSecond); + } + + if (\count($locks) !== $key->getWeight()) { - $lock->refresh($ttlInSecond); + foreach ($locks as $lock) { + $lock->release(); + } + + throw new SemaphoreExpiredException($key, 'One or multiple locks were not even acquired.'); + } } - private function getLock(Key $key, float $ttlInSecond): LockInterface + /** + * @return iterable + */ + private function getLocks(Key $key, float $ttlInSecond, bool $create): iterable { $lockName = \base64_encode($key->__toString()); - if (!$key->hasState(__CLASS__)) { + $locks = []; + if (!$key->hasState(__CLASS__) && $create) { $limit = $key->getLimit(); // use a random start point to have a higher chance to catch a free slot directly $startPoint = \rand(0, $limit - 1); - $lock = null; for ($i = 0; $i < $limit; $i++) { $index = ($startPoint + $i) % $limit; + $lock = $this->lockFactory->createLock($lockName . '_' . $index, $ttlInSecond); if ($lock->acquire(blocking: false)) { // use lock if we can acquire it else try to catch next lock - break; + $locks[] = $lock; + + if (\count($locks) === $key->getWeight()) { + break; + } } - $lock = null; } - if ($lock === null) { + if (\count($locks) !== $key->getWeight()) { + foreach ($locks as $lock) { + $lock->release(); + } + throw new SemaphoreAcquiringException($key, 'There where no free locks found'); } - $key->setState(__CLASS__, $lock); + $key->setState(__CLASS__, $locks); + } elseif ($key->hasState(__CLASS__)) { + $locks = $key->getState(__CLASS__); } - $lock ??= $key->getState(__CLASS__); - \assert($lock instanceof LockInterface); - - return $lock; + return $locks; } } diff --git a/src/Symfony/Component/Semaphore/Tests/Store/AbstractStoreTestCase.php b/src/Symfony/Component/Semaphore/Tests/Store/AbstractStoreTestCase.php index 4cd89458f5d92..aafd59adf93bd 100644 --- a/src/Symfony/Component/Semaphore/Tests/Store/AbstractStoreTestCase.php +++ b/src/Symfony/Component/Semaphore/Tests/Store/AbstractStoreTestCase.php @@ -204,7 +204,6 @@ public function testPutOffExpirationWhenSaveHasNotBeenCalled() $key1 = new Key(__METHOD__, 4, 2); $this->expectException(SemaphoreExpiredException::class); - $this->expectExceptionMessage('The semaphore "Symfony\Component\Semaphore\Tests\Store\AbstractStoreTestCase::testPutOffExpirationWhenSaveHasNotBeenCalled" has expired: the script returns a positive number.'); $store->putOffExpiration($key1, 20); } From ca585f7d6e459f13c1b121c574f4214a80781d2a Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Thu, 12 Dec 2024 19:27:00 +0100 Subject: [PATCH 03/14] Add license header, update code style --- .../Component/Semaphore/Store/LockStore.php | 18 +++++++++++++----- .../Semaphore/Tests/Store/LockStoreTest.php | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Semaphore/Store/LockStore.php b/src/Symfony/Component/Semaphore/Store/LockStore.php index 6423876986f60..2535b848b18eb 100644 --- a/src/Symfony/Component/Semaphore/Store/LockStore.php +++ b/src/Symfony/Component/Semaphore/Store/LockStore.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Component\Semaphore\Store; use Symfony\Component\Lock\LockFactory; @@ -60,7 +69,6 @@ public function putOffExpiration(Key $key, float $ttlInSecond): void } if (\count($locks) !== $key->getWeight()) { - foreach ($locks as $lock) { $lock->release(); } @@ -74,19 +82,19 @@ public function putOffExpiration(Key $key, float $ttlInSecond): void */ private function getLocks(Key $key, float $ttlInSecond, bool $create): iterable { - $lockName = \base64_encode($key->__toString()); + $lockName = base64_encode($key->__toString()); $locks = []; if (!$key->hasState(__CLASS__) && $create) { $limit = $key->getLimit(); // use a random start point to have a higher chance to catch a free slot directly - $startPoint = \rand(0, $limit - 1); + $startPoint = rand(0, $limit - 1); - for ($i = 0; $i < $limit; $i++) { + for ($i = 0; $i < $limit; ++$i) { $index = ($startPoint + $i) % $limit; - $lock = $this->lockFactory->createLock($lockName . '_' . $index, $ttlInSecond); + $lock = $this->lockFactory->createLock($lockName.'_'.$index, $ttlInSecond); if ($lock->acquire(blocking: false)) { // use lock if we can acquire it else try to catch next lock $locks[] = $lock; diff --git a/src/Symfony/Component/Semaphore/Tests/Store/LockStoreTest.php b/src/Symfony/Component/Semaphore/Tests/Store/LockStoreTest.php index f3ea398c0f4a3..f84ecfafd6870 100644 --- a/src/Symfony/Component/Semaphore/Tests/Store/LockStoreTest.php +++ b/src/Symfony/Component/Semaphore/Tests/Store/LockStoreTest.php @@ -13,8 +13,8 @@ use Symfony\Component\Lock\LockFactory; use Symfony\Component\Lock\Store\FlockStore; -use Symfony\Component\Semaphore\Store\LockStore; use Symfony\Component\Semaphore\PersistingStoreInterface; +use Symfony\Component\Semaphore\Store\LockStore; /** * @author Alexander Schranz From 4f7ca2044c986a5da1a5f971c51c30fac3492635 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Thu, 12 Dec 2024 19:31:58 +0100 Subject: [PATCH 04/14] Define optional requirement to symfony/lock --- src/Symfony/Component/Semaphore/Store/LockStore.php | 3 +++ src/Symfony/Component/Semaphore/composer.json | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Semaphore/Store/LockStore.php b/src/Symfony/Component/Semaphore/Store/LockStore.php index 2535b848b18eb..ba0b7c152779f 100644 --- a/src/Symfony/Component/Semaphore/Store/LockStore.php +++ b/src/Symfony/Component/Semaphore/Store/LockStore.php @@ -18,6 +18,9 @@ use Symfony\Component\Semaphore\Key; use Symfony\Component\Semaphore\PersistingStoreInterface; +/** + * @author Alexander Schranz + */ class LockStore implements PersistingStoreInterface { public function __construct( diff --git a/src/Symfony/Component/Semaphore/composer.json b/src/Symfony/Component/Semaphore/composer.json index a620c60cca25a..dbda8ea22412a 100644 --- a/src/Symfony/Component/Semaphore/composer.json +++ b/src/Symfony/Component/Semaphore/composer.json @@ -27,7 +27,8 @@ "predis/predis": "^1.1|^2.0" }, "conflict": { - "symfony/cache": "<6.4" + "symfony/cache": "<6.4", + "symfony/lock": "<5.4 || >=8.0" }, "autoload": { "psr-4": { "Symfony\\Component\\Semaphore\\": "" }, From 79c5b8449cd531ddd8e83cf1ae9d52ca0ee4aa6a Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Thu, 12 Dec 2024 19:42:36 +0100 Subject: [PATCH 05/14] Add validation of the returned locks --- src/Symfony/Component/Semaphore/Store/LockStore.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Semaphore/Store/LockStore.php b/src/Symfony/Component/Semaphore/Store/LockStore.php index ba0b7c152779f..42043fecbc805 100644 --- a/src/Symfony/Component/Semaphore/Store/LockStore.php +++ b/src/Symfony/Component/Semaphore/Store/LockStore.php @@ -81,9 +81,9 @@ public function putOffExpiration(Key $key, float $ttlInSecond): void } /** - * @return iterable + * @return array */ - private function getLocks(Key $key, float $ttlInSecond, bool $create): iterable + private function getLocks(Key $key, float $ttlInSecond, bool $create): array { $lockName = base64_encode($key->__toString()); @@ -118,6 +118,15 @@ private function getLocks(Key $key, float $ttlInSecond, bool $create): iterable $key->setState(__CLASS__, $locks); } elseif ($key->hasState(__CLASS__)) { $locks = $key->getState(__CLASS__); + \assert((function () use ($locks) { + foreach ($locks as $lock) { + if (!$lock instanceof LockInterface) { + return false; + } + } + + return true; + })() === true, 'Locks must be an array of LockInterface'); } return $locks; From f4a3cb1463742ee9def36cf03f14913863f19126 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Thu, 12 Dec 2024 19:50:25 +0100 Subject: [PATCH 06/14] Require dev symfony/lock component --- src/Symfony/Component/Semaphore/composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Semaphore/composer.json b/src/Symfony/Component/Semaphore/composer.json index dbda8ea22412a..8b67730598e81 100644 --- a/src/Symfony/Component/Semaphore/composer.json +++ b/src/Symfony/Component/Semaphore/composer.json @@ -24,7 +24,8 @@ "psr/log": "^1|^2|^3" }, "require-dev": { - "predis/predis": "^1.1|^2.0" + "predis/predis": "^1.1|^2.0", + "symfony/lock": "^5.4 || ^6.0 || ^7.0" }, "conflict": { "symfony/cache": "<6.4", From 2d18f6cb0f9fe2545f1f4fcf93ecf6ec3fe1de00 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Fri, 13 Dec 2024 09:43:12 +0100 Subject: [PATCH 07/14] Add early return if we can not get enough locks --- src/Symfony/Component/Semaphore/Store/LockStore.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Symfony/Component/Semaphore/Store/LockStore.php b/src/Symfony/Component/Semaphore/Store/LockStore.php index 42043fecbc805..1c6982daaed5f 100644 --- a/src/Symfony/Component/Semaphore/Store/LockStore.php +++ b/src/Symfony/Component/Semaphore/Store/LockStore.php @@ -104,10 +104,20 @@ private function getLocks(Key $key, float $ttlInSecond, bool $create): array if (\count($locks) === $key->getWeight()) { break; } + + continue; + } + + $acquired = \count($locks); + $required = $key->getWeight(); + $remaining = $key->getLimit() - $i; + if (($acquired + $remaining) < $required) { // no chance to get enough locks + break; } } if (\count($locks) !== $key->getWeight()) { + // release already acquired locks not get the amount which is required foreach ($locks as $lock) { $lock->release(); } From 84e0607598b3976e8ea64a8b4c63682279d517aa Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Fri, 13 Dec 2024 10:32:53 +0100 Subject: [PATCH 08/14] Remove type check for array LockInterface --- src/Symfony/Component/Semaphore/Store/LockStore.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/Symfony/Component/Semaphore/Store/LockStore.php b/src/Symfony/Component/Semaphore/Store/LockStore.php index 1c6982daaed5f..82d54000a8d56 100644 --- a/src/Symfony/Component/Semaphore/Store/LockStore.php +++ b/src/Symfony/Component/Semaphore/Store/LockStore.php @@ -128,15 +128,6 @@ private function getLocks(Key $key, float $ttlInSecond, bool $create): array $key->setState(__CLASS__, $locks); } elseif ($key->hasState(__CLASS__)) { $locks = $key->getState(__CLASS__); - \assert((function () use ($locks) { - foreach ($locks as $lock) { - if (!$lock instanceof LockInterface) { - return false; - } - } - - return true; - })() === true, 'Locks must be an array of LockInterface'); } return $locks; From 50b835e28e0f1af66b33317cfd76313859b9a330 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Wed, 8 Jan 2025 13:15:58 +0100 Subject: [PATCH 09/14] Split createLock in getExistingLocks and createLocks methods and releaseLocks correctly on failing semphore acquired --- .../Component/Semaphore/Store/LockStore.php | 118 ++++++++++-------- 1 file changed, 66 insertions(+), 52 deletions(-) diff --git a/src/Symfony/Component/Semaphore/Store/LockStore.php b/src/Symfony/Component/Semaphore/Store/LockStore.php index 82d54000a8d56..9581807fed720 100644 --- a/src/Symfony/Component/Semaphore/Store/LockStore.php +++ b/src/Symfony/Component/Semaphore/Store/LockStore.php @@ -30,40 +30,41 @@ public function __construct( public function save(Key $key, float $ttlInSecond): void { - $this->getLocks($key, $ttlInSecond, create: true); + $locks = $this->getExistingLocks($key); + + if ([] !== $locks) { + return; + } + + $locks = $this->createLocks($key, $ttlInSecond); + + $key->setState(__CLASS__, $locks); } public function delete(Key $key): void { - foreach ($this->getLocks($key, 0, create: false) as $lock) { - $lock->release(); - } - $key->setState(__CLASS__, null); + $this->releaseLocks($this->getExistingLocks($key) , $key); } public function exists(Key $key): bool { - $locks = $this->getLocks($key, 0, create: false); + $locks = $this->getExistingLocks($key); - if (\count($locks) !== $key->getWeight()) { - foreach ($locks as $lock) { - $lock->release(); - } - - return false; + if (\count($locks) === $key->getWeight()) { + return true; } - return true; + $this->releaseLocks($this->getExistingLocks($key) , $key); + + return false; } public function putOffExpiration(Key $key, float $ttlInSecond): void { - $locks = $this->getLocks($key, $ttlInSecond, create: false); + $locks = $this->getExistingLocks($key); foreach ($locks as $lock) { if ($lock->isExpired()) { - foreach ($locks as $lock) { - $lock->release(); - } + $this->releaseLocks($locks, $key); throw new SemaphoreExpiredException($key, 'One or multiple locks are already expired.'); } @@ -72,62 +73,75 @@ public function putOffExpiration(Key $key, float $ttlInSecond): void } if (\count($locks) !== $key->getWeight()) { - foreach ($locks as $lock) { - $lock->release(); - } + $this->releaseLocks($locks, $key); throw new SemaphoreExpiredException($key, 'One or multiple locks were not even acquired.'); } } /** - * @return array + * @param array $locks */ - private function getLocks(Key $key, float $ttlInSecond, bool $create): array + private function releaseLocks(array $locks, Key $key): void { - $lockName = base64_encode($key->__toString()); + foreach ($locks as $lock) { + $lock->release(); + } - $locks = []; - if (!$key->hasState(__CLASS__) && $create) { - $limit = $key->getLimit(); + $key->setState(__CLASS__, null); + } - // use a random start point to have a higher chance to catch a free slot directly - $startPoint = rand(0, $limit - 1); + /** + * @return array + */ + private function getExistingLocks(Key $key): array + { + if ($key->hasState(__CLASS__)) { + return $key->getState(__CLASS__); + } - for ($i = 0; $i < $limit; ++$i) { - $index = ($startPoint + $i) % $limit; + return []; + } + + /** + * @return array + */ + private function createLocks(Key $key, float $ttlInSecond): array + { + $locks = []; + $lockName = base64_encode($key->__toString()); + $limit = $key->getLimit(); - $lock = $this->lockFactory->createLock($lockName.'_'.$index, $ttlInSecond); - if ($lock->acquire(blocking: false)) { // use lock if we can acquire it else try to catch next lock - $locks[] = $lock; + // use a random start point to have a higher chance to catch a free slot directly + $startPoint = rand(0, $limit - 1); - if (\count($locks) === $key->getWeight()) { - break; - } + for ($i = 0; $i < $limit; ++$i) { + $index = ($startPoint + $i) % $limit; - continue; - } + $lock = $this->lockFactory->createLock($lockName.'_'.$index, $ttlInSecond); + if ($lock->acquire(blocking: false)) { // use lock if we can acquire it else try to catch next lock + $locks[] = $lock; - $acquired = \count($locks); - $required = $key->getWeight(); - $remaining = $key->getLimit() - $i; - if (($acquired + $remaining) < $required) { // no chance to get enough locks + if (\count($locks) === $key->getWeight()) { break; } - } - if (\count($locks) !== $key->getWeight()) { - // release already acquired locks not get the amount which is required - foreach ($locks as $lock) { - $lock->release(); - } + continue; + } - throw new SemaphoreAcquiringException($key, 'There where no free locks found'); + $acquired = \count($locks); + $required = $key->getWeight(); + $remaining = $key->getLimit() - $i; + if (($acquired + $remaining) < $required) { // no chance to get enough locks + break; } + } + + if (\count($locks) !== $key->getWeight()) { + // release already acquired locks not get the amount which is required + $this->releaseLocks($locks, $key); - $key->setState(__CLASS__, $locks); - } elseif ($key->hasState(__CLASS__)) { - $locks = $key->getState(__CLASS__); + throw new SemaphoreAcquiringException($key, 'There were no free locks found'); } return $locks; From 387f6b312a23620458af453767d95b8d17303a0d Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Wed, 8 Jan 2025 13:16:10 +0100 Subject: [PATCH 10/14] Remove conflict to symfony/lock --- src/Symfony/Component/Semaphore/composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Symfony/Component/Semaphore/composer.json b/src/Symfony/Component/Semaphore/composer.json index 8b67730598e81..6c736a6e466c3 100644 --- a/src/Symfony/Component/Semaphore/composer.json +++ b/src/Symfony/Component/Semaphore/composer.json @@ -28,8 +28,7 @@ "symfony/lock": "^5.4 || ^6.0 || ^7.0" }, "conflict": { - "symfony/cache": "<6.4", - "symfony/lock": "<5.4 || >=8.0" + "symfony/cache": "<6.4" }, "autoload": { "psr-4": { "Symfony\\Component\\Semaphore\\": "" }, From 2e1159ca5dde065bde0ce47740da8eb1a5424596 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Wed, 8 Jan 2025 13:18:23 +0100 Subject: [PATCH 11/14] Remove duplicated call to getExistingLocks --- src/Symfony/Component/Semaphore/Store/LockStore.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Semaphore/Store/LockStore.php b/src/Symfony/Component/Semaphore/Store/LockStore.php index 9581807fed720..b2f9697db63ef 100644 --- a/src/Symfony/Component/Semaphore/Store/LockStore.php +++ b/src/Symfony/Component/Semaphore/Store/LockStore.php @@ -54,7 +54,7 @@ public function exists(Key $key): bool return true; } - $this->releaseLocks($this->getExistingLocks($key) , $key); + $this->releaseLocks($locks , $key); return false; } From 6a3c484f89a41118700e5f0bff18745339521393 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Wed, 8 Jan 2025 14:25:43 +0100 Subject: [PATCH 12/14] Make final, remove named arguments, update comment for release already acquired locks --- src/Symfony/Component/Semaphore/Store/LockStore.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Semaphore/Store/LockStore.php b/src/Symfony/Component/Semaphore/Store/LockStore.php index b2f9697db63ef..5c01154a21429 100644 --- a/src/Symfony/Component/Semaphore/Store/LockStore.php +++ b/src/Symfony/Component/Semaphore/Store/LockStore.php @@ -21,7 +21,7 @@ /** * @author Alexander Schranz */ -class LockStore implements PersistingStoreInterface +final class LockStore implements PersistingStoreInterface { public function __construct( private readonly LockFactory $lockFactory, @@ -119,7 +119,7 @@ private function createLocks(Key $key, float $ttlInSecond): array $index = ($startPoint + $i) % $limit; $lock = $this->lockFactory->createLock($lockName.'_'.$index, $ttlInSecond); - if ($lock->acquire(blocking: false)) { // use lock if we can acquire it else try to catch next lock + if ($lock->acquire(false)) { // use lock if we can acquire it else try to catch next lock $locks[] = $lock; if (\count($locks) === $key->getWeight()) { @@ -138,7 +138,7 @@ private function createLocks(Key $key, float $ttlInSecond): array } if (\count($locks) !== $key->getWeight()) { - // release already acquired locks not get the amount which is required + // release already acquired locks because not got the amount of locks which were required $this->releaseLocks($locks, $key); throw new SemaphoreAcquiringException($key, 'There were no free locks found'); From 92a1d0b267bd1f4994c15f373c93d5de03b83197 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Thu, 9 Jan 2025 09:50:22 +0100 Subject: [PATCH 13/14] Fix coding standards --- src/Symfony/Component/Semaphore/Store/LockStore.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Semaphore/Store/LockStore.php b/src/Symfony/Component/Semaphore/Store/LockStore.php index 5c01154a21429..726323564f47e 100644 --- a/src/Symfony/Component/Semaphore/Store/LockStore.php +++ b/src/Symfony/Component/Semaphore/Store/LockStore.php @@ -43,7 +43,7 @@ public function save(Key $key, float $ttlInSecond): void public function delete(Key $key): void { - $this->releaseLocks($this->getExistingLocks($key) , $key); + $this->releaseLocks($this->getExistingLocks($key), $key); } public function exists(Key $key): bool @@ -54,7 +54,7 @@ public function exists(Key $key): bool return true; } - $this->releaseLocks($locks , $key); + $this->releaseLocks($locks, $key); return false; } From 2f035bcb89657309f331466b8f070a22b7e9ba47 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Wed, 30 Apr 2025 09:40:22 +0200 Subject: [PATCH 14/14] Do not auto release locks of semaphore --- src/Symfony/Component/Semaphore/Store/LockStore.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Semaphore/Store/LockStore.php b/src/Symfony/Component/Semaphore/Store/LockStore.php index 726323564f47e..5cc77ff7ca1b2 100644 --- a/src/Symfony/Component/Semaphore/Store/LockStore.php +++ b/src/Symfony/Component/Semaphore/Store/LockStore.php @@ -118,7 +118,7 @@ private function createLocks(Key $key, float $ttlInSecond): array for ($i = 0; $i < $limit; ++$i) { $index = ($startPoint + $i) % $limit; - $lock = $this->lockFactory->createLock($lockName.'_'.$index, $ttlInSecond); + $lock = $this->lockFactory->createLock($lockName.'_'.$index, $ttlInSecond, false); if ($lock->acquire(false)) { // use lock if we can acquire it else try to catch next lock $locks[] = $lock;