From acd390d1a988199fb295591b86d993add5307491 Mon Sep 17 00:00:00 2001 From: Anton Komarev Date: Mon, 28 Jul 2025 10:41:00 +0300 Subject: [PATCH 01/13] Rewrite locker API --- README.md | 10 +- src/LockId/LockId.php | 35 ---- ....php => PostgresAdvisoryLockLevelEnum.php} | 4 +- src/Locker/PostgresAdvisoryLocker.php | 159 +++++++++++------- .../Locker/PostgresAdvisoryLockerTest.php | 153 +++++++---------- test/Unit/LockId/PostgresLockIdTest.php | 8 +- 6 files changed, 165 insertions(+), 204 deletions(-) delete mode 100644 src/LockId/LockId.php rename src/Locker/{PostgresAdvisoryLockScopeEnum.php => PostgresAdvisoryLockLevelEnum.php} (84%) diff --git a/README.md b/README.md index adb440a..47c38af 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,10 @@ $postgresLocker = new \Cog\DbLocker\Locker\PostgresAdvisoryLocker(); $postgresLockId = \Cog\DbLocker\LockId\PostgresLockId::fromKeyValue('user', '4'); $dbConnection->beginTransaction(); -$isLockAcquired = $postgresLocker->acquireLock( +$isLockAcquired = $postgresLocker->acquireTransactionLevelLock( $dbConnection, $postgresLockId, - \Cog\DbLocker\Locker\PostgresAdvisoryLockScopeEnum::Transaction, + \Cog\DbLocker\Locker\PostgresAdvisoryLockLevelEnum::Transaction, \Cog\DbLocker\Locker\PostgresAdvisoryLockTypeEnum::NonBlocking, \Cog\DbLocker\Locker\PostgresLockModeEnum::Exclusive, ); @@ -61,10 +61,10 @@ $dbConnection = new PDO($dsn, $username, $password); $postgresLocker = new \Cog\DbLocker\Locker\PostgresAdvisoryLocker(); $postgresLockId = \Cog\DbLocker\LockId\PostgresLockId::fromKeyValue('user', '4'); -$isLockAcquired = $postgresLocker->acquireLock( +$isLockAcquired = $postgresLocker->acquireSessionLevelLock( $dbConnection, $postgresLockId, - \Cog\DbLocker\Locker\PostgresAdvisoryLockScopeEnum::Session, + \Cog\DbLocker\Locker\PostgresAdvisoryLockLevelEnum::Session, \Cog\DbLocker\Locker\PostgresAdvisoryLockTypeEnum::NonBlocking, \Cog\DbLocker\Locker\PostgresLockModeEnum::Exclusive, ); @@ -73,7 +73,7 @@ if ($isLockAcquired) { } else { // Execute logic if lock acquisition has been failed } -$postgresLocker->releaseLock($dbConnection, $postgresLockId); +$postgresLocker->releaseSessionLevelLock($dbConnection, $postgresLockId); ``` ## Changelog diff --git a/src/LockId/LockId.php b/src/LockId/LockId.php deleted file mode 100644 index 6f51925..0000000 --- a/src/LockId/LockId.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Cog\DbLocker\LockId; - -use InvalidArgumentException; - -final class LockId -{ - public function __construct( - public readonly string $key, - public readonly string $value = '', - ) { - if ($key === '') { - throw new InvalidArgumentException('LockId key is empty'); - } - } - - public function __toString(): string - { - return $this->value !== '' - ? $this->key . ':' . $this->value - : $this->key; - } -} diff --git a/src/Locker/PostgresAdvisoryLockScopeEnum.php b/src/Locker/PostgresAdvisoryLockLevelEnum.php similarity index 84% rename from src/Locker/PostgresAdvisoryLockScopeEnum.php rename to src/Locker/PostgresAdvisoryLockLevelEnum.php index efd2e99..859cb6a 100644 --- a/src/Locker/PostgresAdvisoryLockScopeEnum.php +++ b/src/Locker/PostgresAdvisoryLockLevelEnum.php @@ -5,7 +5,7 @@ namespace Cog\DbLocker\Locker; /** - * PostgresAdvisoryLockScopeEnum defines the scope of advisory lock acquisition. + * PostgresAdvisoryLockLevelEnum defines the level of advisory lock acquisition. * * - Session. Session-level advisory lock (without _XACT_): * - PG_ADVISORY_LOCK @@ -18,7 +18,7 @@ * - PG_TRY_ADVISORY_XACT_LOCK * - PG_TRY_ADVISORY_XACT_LOCK_SHARED */ -enum PostgresAdvisoryLockScopeEnum +enum PostgresAdvisoryLockLevelEnum { case Session; case Transaction; diff --git a/src/Locker/PostgresAdvisoryLocker.php b/src/Locker/PostgresAdvisoryLocker.php index 46e4fda..83227bd 100644 --- a/src/Locker/PostgresAdvisoryLocker.php +++ b/src/Locker/PostgresAdvisoryLocker.php @@ -20,59 +20,143 @@ final class PostgresAdvisoryLocker { /** - * Acquire an advisory lock with configurable scope, mode and behavior. + * Acquire a transaction-level advisory lock with a configurable acquisition type and mode. */ - public function acquireLock( + public function acquireTransactionLevelLock( PDO $dbConnection, PostgresLockId $postgresLockId, - PostgresAdvisoryLockScopeEnum $scope = PostgresAdvisoryLockScopeEnum::Transaction, PostgresAdvisoryLockTypeEnum $type = PostgresAdvisoryLockTypeEnum::NonBlocking, PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive, ): bool { - if ($scope === PostgresAdvisoryLockScopeEnum::Transaction && $dbConnection->inTransaction() === false) { + return $this->acquireLock( + $dbConnection, + $postgresLockId, + PostgresAdvisoryLockLevelEnum::Transaction, + $type, + $mode, + ); + } + + /** + * Acquire a session-level advisory lock with a configurable acquisition type and mode. + * + * TODO: Write that transaction-level is recommended. + */ + public function acquireSessionLevelLock( + PDO $dbConnection, + PostgresLockId $postgresLockId, + PostgresAdvisoryLockTypeEnum $type = PostgresAdvisoryLockTypeEnum::NonBlocking, + PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive, + ): bool { + return $this->acquireLock( + $dbConnection, + $postgresLockId, + PostgresAdvisoryLockLevelEnum::Session, + $type, + $mode, + ); + } + + /** + * Release session level advisory lock. + */ + public function releaseSessionLevelLock( + PDO $dbConnection, + PostgresLockId $postgresLockId, + PostgresAdvisoryLockLevelEnum $level = PostgresAdvisoryLockLevelEnum::Session, + PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive, + ): bool { + if ($level === PostgresAdvisoryLockLevelEnum::Transaction) { + throw new \InvalidArgumentException('Transaction-level advisory lock cannot be released'); + } + + $sql = match ($mode) { + PostgresLockModeEnum::Exclusive => 'SELECT PG_ADVISORY_UNLOCK(:class_id, :object_id);', + PostgresLockModeEnum::Share => 'SELECT PG_ADVISORY_UNLOCK_SHARED(:class_id, :object_id);', + }; + $sql .= " -- $postgresLockId->humanReadableValue"; + + $statement = $dbConnection->prepare($sql); + $statement->execute( + [ + 'class_id' => $postgresLockId->classId, + 'object_id' => $postgresLockId->objectId, + ], + ); + + return $statement->fetchColumn(0); + } + + /** + * Release all session level advisory locks held by the current session. + */ + public function releaseAllSessionLevelLocks( + PDO $dbConnection, + PostgresAdvisoryLockLevelEnum $level = PostgresAdvisoryLockLevelEnum::Session, + ): void { + if ($level === PostgresAdvisoryLockLevelEnum::Transaction) { + throw new \InvalidArgumentException('Transaction-level advisory lock cannot be released'); + } + + $statement = $dbConnection->prepare( + <<<'SQL' + SELECT PG_ADVISORY_UNLOCK_ALL(); + SQL, + ); + $statement->execute(); + } + + private function acquireLock( + PDO $dbConnection, + PostgresLockId $postgresLockId, + PostgresAdvisoryLockLevelEnum $level, + PostgresAdvisoryLockTypeEnum $type = PostgresAdvisoryLockTypeEnum::NonBlocking, + PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive, + ): bool { + if ($level === PostgresAdvisoryLockLevelEnum::Transaction && $dbConnection->inTransaction() === false) { throw new LogicException( "Transaction-level advisory lock `$postgresLockId->humanReadableValue` cannot be acquired outside of transaction", ); } - $sql = match ([$scope, $type, $mode]) { + $sql = match ([$level, $type, $mode]) { [ - PostgresAdvisoryLockScopeEnum::Transaction, + PostgresAdvisoryLockLevelEnum::Transaction, PostgresAdvisoryLockTypeEnum::NonBlocking, PostgresLockModeEnum::Exclusive, ] => 'SELECT PG_TRY_ADVISORY_XACT_LOCK(:class_id, :object_id);', [ - PostgresAdvisoryLockScopeEnum::Transaction, + PostgresAdvisoryLockLevelEnum::Transaction, PostgresAdvisoryLockTypeEnum::Blocking, PostgresLockModeEnum::Exclusive, ] => 'SELECT PG_ADVISORY_XACT_LOCK(:class_id, :object_id);', [ - PostgresAdvisoryLockScopeEnum::Transaction, + PostgresAdvisoryLockLevelEnum::Transaction, PostgresAdvisoryLockTypeEnum::NonBlocking, PostgresLockModeEnum::Share, ] => 'SELECT PG_TRY_ADVISORY_XACT_LOCK_SHARED(:class_id, :object_id);', [ - PostgresAdvisoryLockScopeEnum::Transaction, + PostgresAdvisoryLockLevelEnum::Transaction, PostgresAdvisoryLockTypeEnum::Blocking, PostgresLockModeEnum::Share, ] => 'SELECT PG_ADVISORY_XACT_LOCK_SHARED(:class_id, :object_id);', [ - PostgresAdvisoryLockScopeEnum::Session, + PostgresAdvisoryLockLevelEnum::Session, PostgresAdvisoryLockTypeEnum::NonBlocking, PostgresLockModeEnum::Exclusive, ] => 'SELECT PG_TRY_ADVISORY_LOCK(:class_id, :object_id);', [ - PostgresAdvisoryLockScopeEnum::Session, + PostgresAdvisoryLockLevelEnum::Session, PostgresAdvisoryLockTypeEnum::Blocking, PostgresLockModeEnum::Exclusive, ] => 'SELECT PG_ADVISORY_LOCK(:class_id, :object_id);', [ - PostgresAdvisoryLockScopeEnum::Session, + PostgresAdvisoryLockLevelEnum::Session, PostgresAdvisoryLockTypeEnum::NonBlocking, PostgresLockModeEnum::Share, ] => 'SELECT PG_TRY_ADVISORY_LOCK_SHARED(:class_id, :object_id);', [ - PostgresAdvisoryLockScopeEnum::Session, + PostgresAdvisoryLockLevelEnum::Session, PostgresAdvisoryLockTypeEnum::Blocking, PostgresLockModeEnum::Share, ] => 'SELECT PG_ADVISORY_LOCK_SHARED(:class_id, :object_id);', @@ -89,53 +173,4 @@ public function acquireLock( return $statement->fetchColumn(0); } - - /** - * Release session level advisory lock. - */ - public function releaseLock( - PDO $dbConnection, - PostgresLockId $postgresLockId, - PostgresAdvisoryLockScopeEnum $scope = PostgresAdvisoryLockScopeEnum::Session, - PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive, - ): bool { - if ($scope === PostgresAdvisoryLockScopeEnum::Transaction) { - throw new \InvalidArgumentException('Transaction-level advisory lock cannot be released'); - } - - $sql = match ($mode) { - PostgresLockModeEnum::Exclusive => 'SELECT PG_ADVISORY_UNLOCK(:class_id, :object_id);', - PostgresLockModeEnum::Share => 'SELECT PG_ADVISORY_UNLOCK_SHARED(:class_id, :object_id);', - }; - $sql .= " -- $postgresLockId->humanReadableValue"; - - $statement = $dbConnection->prepare($sql); - $statement->execute( - [ - 'class_id' => $postgresLockId->classId, - 'object_id' => $postgresLockId->objectId, - ], - ); - - return $statement->fetchColumn(0); - } - - /** - * Release all session level advisory locks held by the current session. - */ - public function releaseAllLocks( - PDO $dbConnection, - PostgresAdvisoryLockScopeEnum $scope = PostgresAdvisoryLockScopeEnum::Session, - ): void { - if ($scope === PostgresAdvisoryLockScopeEnum::Transaction) { - throw new \InvalidArgumentException('Transaction-level advisory lock cannot be released'); - } - - $statement = $dbConnection->prepare( - <<<'SQL' - SELECT PG_ADVISORY_UNLOCK_ALL(); - SQL, - ); - $statement->execute(); - } } diff --git a/test/Integration/Locker/PostgresAdvisoryLockerTest.php b/test/Integration/Locker/PostgresAdvisoryLockerTest.php index 3a6400b..28ba67c 100644 --- a/test/Integration/Locker/PostgresAdvisoryLockerTest.php +++ b/test/Integration/Locker/PostgresAdvisoryLockerTest.php @@ -14,7 +14,7 @@ namespace Cog\Test\DbLocker\Integration\Locker; use Cog\DbLocker\Locker\PostgresAdvisoryLocker; -use Cog\DbLocker\Locker\PostgresAdvisoryLockScopeEnum; +use Cog\DbLocker\Locker\PostgresAdvisoryLockLevelEnum; use Cog\DbLocker\Locker\PostgresLockModeEnum; use Cog\DbLocker\LockId\PostgresLockId; use Cog\Test\DbLocker\Integration\AbstractIntegrationTestCase; @@ -34,10 +34,9 @@ public function testItCanTryAcquireLockWithinSession( $dbConnection = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); - $isLockAcquired = $locker->acquireLock( + $isLockAcquired = $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, - scope: PostgresAdvisoryLockScopeEnum::Session, mode: $mode, ); @@ -67,10 +66,9 @@ public function testItCanTryAcquireLockWithinTransaction( $postgresLockId = PostgresLockId::fromKeyValue('test'); $dbConnection->beginTransaction(); - $isLockAcquired = $locker->acquireLock( + $isLockAcquired = $locker->acquireTransactionLevelLock( $dbConnection, $postgresLockId, - scope: PostgresAdvisoryLockScopeEnum::Transaction, mode: $mode, ); @@ -98,10 +96,9 @@ public function testItCanTryAcquireLockFromIntKeysCornerCases(): void $dbConnection = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromIntKeys(self::DB_INT32_VALUE_MIN, 0); - $isLockAcquired = $locker->acquireLock( + $isLockAcquired = $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, - scope: PostgresAdvisoryLockScopeEnum::Session, ); $this->assertTrue($isLockAcquired); @@ -137,15 +134,13 @@ public function testItCanTryAcquireLockInSameConnectionOnlyOnce(): void $dbConnection = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); - $isLockAcquired1 = $locker->acquireLock( + $isLockAcquired1 = $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Session, ); - $isLockAcquired2 = $locker->acquireLock( + $isLockAcquired2 = $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Session, ); $this->assertTrue($isLockAcquired1); @@ -161,15 +156,13 @@ public function testItCanTryAcquireMultipleLocksInOneConnection(): void $postgresLockId1 = PostgresLockId::fromKeyValue('test1'); $postgresLockId2 = PostgresLockId::fromKeyValue('test2'); - $isLock1Acquired = $locker->acquireLock( + $isLock1Acquired = $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId1, - PostgresAdvisoryLockScopeEnum::Session, ); - $isLock2Acquired = $locker->acquireLock( + $isLock2Acquired = $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId2, - PostgresAdvisoryLockScopeEnum::Session, ); $this->assertTrue($isLock1Acquired); @@ -185,16 +178,14 @@ public function testItCannotAcquireSameLockInTwoConnections(): void $dbConnection1 = $this->initPostgresPdoConnection(); $dbConnection2 = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection1, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Session, ); - $isLockAcquired = $locker->acquireLock( + $isLockAcquired = $locker->acquireSessionLevelLock( $dbConnection2, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Session, ); $this->assertFalse($isLockAcquired); @@ -209,14 +200,13 @@ public function testItCanReleaseLock( $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, - scope: PostgresAdvisoryLockScopeEnum::Session, mode: $mode, ); - $isLockReleased = $locker->releaseLock( + $isLockReleased = $locker->releaseSessionLevelLock( $dbConnection, $postgresLockId, mode: $mode, @@ -246,14 +236,13 @@ public function testItCanNotReleaseLockOfDifferentModes( $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, - scope: PostgresAdvisoryLockScopeEnum::Session, mode: $acquireMode, ); - $isLockReleased = $locker->releaseLock( + $isLockReleased = $locker->releaseSessionLevelLock( $dbConnection, $postgresLockId, mode: $releaseMode, @@ -283,19 +272,17 @@ public function testItCanReleaseLockTwiceIfAcquiredTwice(): void $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Session, ); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Session, ); - $isLockReleased1 = $locker->releaseLock($dbConnection, $postgresLockId); - $isLockReleased2 = $locker->releaseLock($dbConnection, $postgresLockId); + $isLockReleased1 = $locker->releaseSessionLevelLock($dbConnection, $postgresLockId); + $isLockReleased2 = $locker->releaseSessionLevelLock($dbConnection, $postgresLockId); $this->assertTrue($isLockReleased1); $this->assertTrue($isLockReleased2); @@ -308,20 +295,18 @@ public function testItCanTryAcquireLockInSecondConnectionAfterRelease(): void $dbConnection1 = $this->initPostgresPdoConnection(); $dbConnection2 = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection1, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Session, ); - $locker->releaseLock( + $locker->releaseSessionLevelLock( $dbConnection1, $postgresLockId, ); - $isLockAcquired = $locker->acquireLock( + $isLockAcquired = $locker->acquireSessionLevelLock( $dbConnection2, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Session, ); $this->assertTrue($isLockAcquired); @@ -335,22 +320,19 @@ public function testItCannotAcquireLockInSecondConnectionAfterOneReleaseTwiceLoc $dbConnection1 = $this->initPostgresPdoConnection(); $dbConnection2 = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection1, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Session, ); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection1, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Session, ); - $isLockReleased = $locker->releaseLock($dbConnection1, $postgresLockId); - $isLockAcquired = $locker->acquireLock( + $isLockReleased = $locker->releaseSessionLevelLock($dbConnection1, $postgresLockId); + $isLockAcquired = $locker->acquireSessionLevelLock( $dbConnection2, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Session, ); $this->assertTrue($isLockReleased); @@ -366,7 +348,7 @@ public function testItCannotReleaseLockIfNotAcquired(): void $dbConnection = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); - $isLockReleased = $locker->releaseLock($dbConnection, $postgresLockId); + $isLockReleased = $locker->releaseSessionLevelLock($dbConnection, $postgresLockId); $this->assertFalse($isLockReleased); $this->assertPgAdvisoryLocksCount(0); @@ -378,13 +360,12 @@ public function testItCannotReleaseLockIfAcquiredInOtherConnection(): void $dbConnection1 = $this->initPostgresPdoConnection(); $dbConnection2 = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection1, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Session, ); - $isLockReleased = $locker->releaseLock($dbConnection2, $postgresLockId); + $isLockReleased = $locker->releaseSessionLevelLock($dbConnection2, $postgresLockId); $this->assertFalse($isLockReleased); $this->assertPgAdvisoryLocksCount(1); @@ -395,23 +376,20 @@ public function testItCanReleaseAllLocksInConnection(): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection, PostgresLockId::fromKeyValue('test'), - PostgresAdvisoryLockScopeEnum::Session, ); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection, PostgresLockId::fromKeyValue('test'), - PostgresAdvisoryLockScopeEnum::Session, ); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection, PostgresLockId::fromKeyValue('test2'), - PostgresAdvisoryLockScopeEnum::Session, ); - $locker->releaseAllLocks($dbConnection); + $locker->releaseAllSessionLevelLocks($dbConnection); $this->assertPgAdvisoryLocksCount(0); } @@ -421,7 +399,7 @@ public function testItCanReleaseAllLocksInConnectionIfNoLocksWereAcquired(): voi $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $locker->releaseAllLocks($dbConnection); + $locker->releaseAllSessionLevelLocks($dbConnection); $this->assertPgAdvisoryLocksCount(0); } @@ -435,28 +413,24 @@ public function testItCanReleaseAllLocksInConnectionButKeepsOtherConnectionLocks $postgresLockId2 = PostgresLockId::fromKeyValue('test2'); $postgresLockId3 = PostgresLockId::fromKeyValue('test3'); $postgresLockId4 = PostgresLockId::fromKeyValue('test4'); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection1, $postgresLockId1, - PostgresAdvisoryLockScopeEnum::Session, ); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection1, $postgresLockId2, - PostgresAdvisoryLockScopeEnum::Session, ); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection2, $postgresLockId3, - PostgresAdvisoryLockScopeEnum::Session, ); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection2, $postgresLockId4, - PostgresAdvisoryLockScopeEnum::Session, ); - $locker->releaseAllLocks($dbConnection1); + $locker->releaseAllSessionLevelLocks($dbConnection1); $this->assertPgAdvisoryLocksCount(2); $this->assertPgAdvisoryLockExistsInConnection($dbConnection2, $postgresLockId3); @@ -474,10 +448,9 @@ public function testItCannotAcquireLockWithinTransactionNotInTransaction(): void $dbConnection = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); - $locker->acquireLock( + $locker->acquireTransactionLevelLock( $dbConnection, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Transaction, ); } @@ -488,16 +461,14 @@ public function testItCannotAcquireLockInSecondConnectionIfTakenWithinTransactio $dbConnection2 = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); $dbConnection1->beginTransaction(); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection1, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Session, ); - $isLockAcquired = $locker->acquireLock( + $isLockAcquired = $locker->acquireSessionLevelLock( $dbConnection2, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Session, ); $this->assertFalse($isLockAcquired); @@ -511,10 +482,9 @@ public function testItCanAutoReleaseLockAcquiredWithinTransactionOnCommit(): voi $dbConnection = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); $dbConnection->beginTransaction(); - $locker->acquireLock( + $locker->acquireTransactionLevelLock( $dbConnection, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Transaction, ); $dbConnection->commit(); @@ -529,10 +499,9 @@ public function testItCanAutoReleaseLockAcquiredWithinTransactionOnRollback(): v $dbConnection = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); $dbConnection->beginTransaction(); - $locker->acquireLock( + $locker->acquireTransactionLevelLock( $dbConnection, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Transaction, ); $dbConnection->rollBack(); @@ -547,10 +516,9 @@ public function testItCanAutoReleaseLockAcquiredWithinTransactionOnConnectionKil $dbConnection = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); $dbConnection->beginTransaction(); - $locker->acquireLock( + $locker->acquireTransactionLevelLock( $dbConnection, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Transaction, ); $dbConnection = null; @@ -564,13 +532,12 @@ public function testItCannotReleaseLockAcquiredWithinTransaction(): void $dbConnection = $this->initPostgresPdoConnection(); $postgresLockId = PostgresLockId::fromKeyValue('test'); $dbConnection->beginTransaction(); - $locker->acquireLock( + $locker->acquireTransactionLevelLock( $dbConnection, $postgresLockId, - PostgresAdvisoryLockScopeEnum::Transaction, ); - $isLockReleased = $locker->releaseLock($dbConnection, $postgresLockId); + $isLockReleased = $locker->releaseSessionLevelLock($dbConnection, $postgresLockId); $this->assertFalse($isLockReleased); $this->assertPgAdvisoryLocksCount(1); @@ -583,19 +550,17 @@ public function testItCannotReleaseAllLocksAcquiredWithinTransaction(): void $dbConnection = $this->initPostgresPdoConnection(); $postgresLockId1 = PostgresLockId::fromKeyValue('test'); $postgresLockId2 = PostgresLockId::fromKeyValue('test2'); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId1, - PostgresAdvisoryLockScopeEnum::Session, ); $dbConnection->beginTransaction(); - $locker->acquireLock( + $locker->acquireTransactionLevelLock( $dbConnection, $postgresLockId2, - PostgresAdvisoryLockScopeEnum::Transaction, ); - $locker->releaseAllLocks($dbConnection); + $locker->releaseAllSessionLevelLocks($dbConnection); $this->assertPgAdvisoryLocksCount(1); $this->assertPgAdvisoryLockMissingInConnection($dbConnection, $postgresLockId1); @@ -608,23 +573,21 @@ public function testItCannotReleaseLockWithTransactionScope(): void $dbConnection = $this->initPostgresPdoConnection(); $postgresLockId1 = PostgresLockId::fromKeyValue('test'); $postgresLockId2 = PostgresLockId::fromKeyValue('test2'); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId1, - PostgresAdvisoryLockScopeEnum::Session, ); $dbConnection->beginTransaction(); - $locker->acquireLock( + $locker->acquireTransactionLevelLock( $dbConnection, $postgresLockId2, - PostgresAdvisoryLockScopeEnum::Transaction, ); try { - $locker->releaseLock( + $locker->releaseSessionLevelLock( $dbConnection, $postgresLockId2, - PostgresAdvisoryLockScopeEnum::Transaction, + PostgresAdvisoryLockLevelEnum::Transaction, ); } catch (\InvalidArgumentException $exception) { $this->assertSame( @@ -640,22 +603,20 @@ public function testItCannotReleaseAllLocksWithTransactionScope(): void $dbConnection = $this->initPostgresPdoConnection(); $postgresLockId1 = PostgresLockId::fromKeyValue('test'); $postgresLockId2 = PostgresLockId::fromKeyValue('test2'); - $locker->acquireLock( + $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId1, - PostgresAdvisoryLockScopeEnum::Session, ); $dbConnection->beginTransaction(); - $locker->acquireLock( + $locker->acquireTransactionLevelLock( $dbConnection, $postgresLockId2, - PostgresAdvisoryLockScopeEnum::Transaction, ); try { - $locker->releaseAllLocks( + $locker->releaseAllSessionLevelLocks( $dbConnection, - PostgresAdvisoryLockScopeEnum::Transaction, + PostgresAdvisoryLockLevelEnum::Transaction, ); } catch (\InvalidArgumentException $exception) { $this->assertSame( diff --git a/test/Unit/LockId/PostgresLockIdTest.php b/test/Unit/LockId/PostgresLockIdTest.php index d8ff576..0febc49 100644 --- a/test/Unit/LockId/PostgresLockIdTest.php +++ b/test/Unit/LockId/PostgresLockIdTest.php @@ -107,22 +107,22 @@ public static function provideItCanCreatePostgresLockIdFromOutOfRangeIntKeysData 'min class_id' => [ self::DB_INT32_VALUE_MIN - 1, 0, - "Out of bound exception (classId=-2147483649 is too small)" + "Out of bound exception (classId=-2147483649 is too small)", ], 'max class_id' => [ self::DB_INT32_VALUE_MAX + 1, 0, - "Out of bound exception (classId=2147483648 is too big)" + "Out of bound exception (classId=2147483648 is too big)", ], 'min object_id' => [ 0, self::DB_INT32_VALUE_MIN - 1, - "Out of bound exception (objectId=-2147483649 is too small)" + "Out of bound exception (objectId=-2147483649 is too small)", ], 'max object_id' => [ 0, self::DB_INT32_VALUE_MAX + 1, - "Out of bound exception (objectId=2147483648 is too big)" + "Out of bound exception (objectId=2147483648 is too big)", ], ]; } From 715c5c783130cd35158386fc0ff5ee253546d0cb Mon Sep 17 00:00:00 2001 From: Anton Komarev Date: Mon, 28 Jul 2025 10:43:28 +0300 Subject: [PATCH 02/13] Rewrite locker API --- README.md | 18 ++++++------ src/Locker/PostgresAdvisoryLocker.php | 5 ---- .../Locker/PostgresAdvisoryLockerTest.php | 29 ------------------- 3 files changed, 9 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 47c38af..b7ff11a 100644 --- a/README.md +++ b/README.md @@ -34,13 +34,13 @@ composer require cybercog/php-db-locker ```php $dbConnection = new PDO($dsn, $username, $password); -$postgresLocker = new \Cog\DbLocker\Locker\PostgresAdvisoryLocker(); -$postgresLockId = \Cog\DbLocker\LockId\PostgresLockId::fromKeyValue('user', '4'); +$locker = new \Cog\DbLocker\Locker\PostgresAdvisoryLocker(); +$lockId = \Cog\DbLocker\LockId\PostgresLockId::fromKeyValue('user', '4'); $dbConnection->beginTransaction(); -$isLockAcquired = $postgresLocker->acquireTransactionLevelLock( +$isLockAcquired = $locker->acquireTransactionLevelLock( $dbConnection, - $postgresLockId, + $lockId, \Cog\DbLocker\Locker\PostgresAdvisoryLockLevelEnum::Transaction, \Cog\DbLocker\Locker\PostgresAdvisoryLockTypeEnum::NonBlocking, \Cog\DbLocker\Locker\PostgresLockModeEnum::Exclusive, @@ -58,12 +58,12 @@ $dbConnection->commit(); ```php $dbConnection = new PDO($dsn, $username, $password); -$postgresLocker = new \Cog\DbLocker\Locker\PostgresAdvisoryLocker(); -$postgresLockId = \Cog\DbLocker\LockId\PostgresLockId::fromKeyValue('user', '4'); +$locker = new \Cog\DbLocker\Locker\PostgresAdvisoryLocker(); +$lockId = \Cog\DbLocker\LockId\PostgresLockId::fromKeyValue('user', '4'); -$isLockAcquired = $postgresLocker->acquireSessionLevelLock( +$isLockAcquired = $locker->acquireSessionLevelLock( $dbConnection, - $postgresLockId, + $lockId, \Cog\DbLocker\Locker\PostgresAdvisoryLockLevelEnum::Session, \Cog\DbLocker\Locker\PostgresAdvisoryLockTypeEnum::NonBlocking, \Cog\DbLocker\Locker\PostgresLockModeEnum::Exclusive, @@ -73,7 +73,7 @@ if ($isLockAcquired) { } else { // Execute logic if lock acquisition has been failed } -$postgresLocker->releaseSessionLevelLock($dbConnection, $postgresLockId); +$locker->releaseSessionLevelLock($dbConnection, $lockId); ``` ## Changelog diff --git a/src/Locker/PostgresAdvisoryLocker.php b/src/Locker/PostgresAdvisoryLocker.php index 83227bd..6654c10 100644 --- a/src/Locker/PostgresAdvisoryLocker.php +++ b/src/Locker/PostgresAdvisoryLocker.php @@ -92,12 +92,7 @@ public function releaseSessionLevelLock( */ public function releaseAllSessionLevelLocks( PDO $dbConnection, - PostgresAdvisoryLockLevelEnum $level = PostgresAdvisoryLockLevelEnum::Session, ): void { - if ($level === PostgresAdvisoryLockLevelEnum::Transaction) { - throw new \InvalidArgumentException('Transaction-level advisory lock cannot be released'); - } - $statement = $dbConnection->prepare( <<<'SQL' SELECT PG_ADVISORY_UNLOCK_ALL(); diff --git a/test/Integration/Locker/PostgresAdvisoryLockerTest.php b/test/Integration/Locker/PostgresAdvisoryLockerTest.php index 28ba67c..40e0751 100644 --- a/test/Integration/Locker/PostgresAdvisoryLockerTest.php +++ b/test/Integration/Locker/PostgresAdvisoryLockerTest.php @@ -597,35 +597,6 @@ public function testItCannotReleaseLockWithTransactionScope(): void } } - public function testItCannotReleaseAllLocksWithTransactionScope(): void - { - $locker = $this->initLocker(); - $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId1 = PostgresLockId::fromKeyValue('test'); - $postgresLockId2 = PostgresLockId::fromKeyValue('test2'); - $locker->acquireSessionLevelLock( - $dbConnection, - $postgresLockId1, - ); - $dbConnection->beginTransaction(); - $locker->acquireTransactionLevelLock( - $dbConnection, - $postgresLockId2, - ); - - try { - $locker->releaseAllSessionLevelLocks( - $dbConnection, - PostgresAdvisoryLockLevelEnum::Transaction, - ); - } catch (\InvalidArgumentException $exception) { - $this->assertSame( - 'Transaction-level advisory lock cannot be released', - $exception->getMessage(), - ); - } - } - private function initLocker(): PostgresAdvisoryLocker { return new PostgresAdvisoryLocker(); From 893f0567b3692247f49e950b3411d8c01aae1c60 Mon Sep 17 00:00:00 2001 From: Anton Komarev Date: Mon, 28 Jul 2025 10:50:51 +0300 Subject: [PATCH 03/13] Rewrite locker API --- README.md | 8 +-- ...p => PostgresAdvisoryLockWaitModeEnum.php} | 4 +- src/Locker/PostgresAdvisoryLocker.php | 62 +++++++++---------- ...num.php => PostgresLockAccessModeEnum.php} | 4 +- .../AbstractIntegrationTestCase.php | 8 +-- .../Locker/PostgresAdvisoryLockerTest.php | 44 ++++++------- 6 files changed, 65 insertions(+), 65 deletions(-) rename src/Locker/{PostgresAdvisoryLockTypeEnum.php => PostgresAdvisoryLockWaitModeEnum.php} (82%) rename src/Locker/{PostgresLockModeEnum.php => PostgresLockAccessModeEnum.php} (53%) diff --git a/README.md b/README.md index b7ff11a..2ed4e3b 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,8 @@ $isLockAcquired = $locker->acquireTransactionLevelLock( $dbConnection, $lockId, \Cog\DbLocker\Locker\PostgresAdvisoryLockLevelEnum::Transaction, - \Cog\DbLocker\Locker\PostgresAdvisoryLockTypeEnum::NonBlocking, - \Cog\DbLocker\Locker\PostgresLockModeEnum::Exclusive, + \Cog\DbLocker\Locker\PostgresAdvisoryLockWaitModeEnum::NonBlocking, + \Cog\DbLocker\Locker\PostgresLockAccessModeEnum::Exclusive, ); if ($isLockAcquired) { // Execute logic if lock was successful @@ -65,8 +65,8 @@ $isLockAcquired = $locker->acquireSessionLevelLock( $dbConnection, $lockId, \Cog\DbLocker\Locker\PostgresAdvisoryLockLevelEnum::Session, - \Cog\DbLocker\Locker\PostgresAdvisoryLockTypeEnum::NonBlocking, - \Cog\DbLocker\Locker\PostgresLockModeEnum::Exclusive, + \Cog\DbLocker\Locker\PostgresAdvisoryLockWaitModeEnum::NonBlocking, + \Cog\DbLocker\Locker\PostgresLockAccessModeEnum::Exclusive, ); if ($isLockAcquired) { // Execute logic if lock was successful diff --git a/src/Locker/PostgresAdvisoryLockTypeEnum.php b/src/Locker/PostgresAdvisoryLockWaitModeEnum.php similarity index 82% rename from src/Locker/PostgresAdvisoryLockTypeEnum.php rename to src/Locker/PostgresAdvisoryLockWaitModeEnum.php index 51100e1..4dac098 100644 --- a/src/Locker/PostgresAdvisoryLockTypeEnum.php +++ b/src/Locker/PostgresAdvisoryLockWaitModeEnum.php @@ -5,7 +5,7 @@ namespace Cog\DbLocker\Locker; /** - * PostgresAdvisoryLockTypeEnum defines the type of advisory lock acquisition. + * PostgresAdvisoryLockWaitModeEnum defines the type of advisory lock acquisition. * * - NonBlocking. Attempt to acquire the lock without blocking (with _TRY_): * - PG_TRY_ADVISORY_LOCK @@ -18,7 +18,7 @@ * - PG_ADVISORY_XACT_LOCK * - PG_ADVISORY_XACT_LOCK_SHARED */ -enum PostgresAdvisoryLockTypeEnum +enum PostgresAdvisoryLockWaitModeEnum { case NonBlocking; case Blocking; diff --git a/src/Locker/PostgresAdvisoryLocker.php b/src/Locker/PostgresAdvisoryLocker.php index 6654c10..ee7c627 100644 --- a/src/Locker/PostgresAdvisoryLocker.php +++ b/src/Locker/PostgresAdvisoryLocker.php @@ -25,15 +25,15 @@ final class PostgresAdvisoryLocker public function acquireTransactionLevelLock( PDO $dbConnection, PostgresLockId $postgresLockId, - PostgresAdvisoryLockTypeEnum $type = PostgresAdvisoryLockTypeEnum::NonBlocking, - PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive, + PostgresAdvisoryLockWaitModeEnum $waitMode = PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, ): bool { return $this->acquireLock( $dbConnection, $postgresLockId, PostgresAdvisoryLockLevelEnum::Transaction, - $type, - $mode, + $waitMode, + $accessMode, ); } @@ -45,15 +45,15 @@ public function acquireTransactionLevelLock( public function acquireSessionLevelLock( PDO $dbConnection, PostgresLockId $postgresLockId, - PostgresAdvisoryLockTypeEnum $type = PostgresAdvisoryLockTypeEnum::NonBlocking, - PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive, + PostgresAdvisoryLockWaitModeEnum $waitMode = PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, ): bool { return $this->acquireLock( $dbConnection, $postgresLockId, PostgresAdvisoryLockLevelEnum::Session, - $type, - $mode, + $waitMode, + $accessMode, ); } @@ -64,15 +64,15 @@ public function releaseSessionLevelLock( PDO $dbConnection, PostgresLockId $postgresLockId, PostgresAdvisoryLockLevelEnum $level = PostgresAdvisoryLockLevelEnum::Session, - PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive, + PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, ): bool { if ($level === PostgresAdvisoryLockLevelEnum::Transaction) { throw new \InvalidArgumentException('Transaction-level advisory lock cannot be released'); } - $sql = match ($mode) { - PostgresLockModeEnum::Exclusive => 'SELECT PG_ADVISORY_UNLOCK(:class_id, :object_id);', - PostgresLockModeEnum::Share => 'SELECT PG_ADVISORY_UNLOCK_SHARED(:class_id, :object_id);', + $sql = match ($accessMode) { + PostgresLockAccessModeEnum::Exclusive => 'SELECT PG_ADVISORY_UNLOCK(:class_id, :object_id);', + PostgresLockAccessModeEnum::Share => 'SELECT PG_ADVISORY_UNLOCK_SHARED(:class_id, :object_id);', }; $sql .= " -- $postgresLockId->humanReadableValue"; @@ -105,8 +105,8 @@ private function acquireLock( PDO $dbConnection, PostgresLockId $postgresLockId, PostgresAdvisoryLockLevelEnum $level, - PostgresAdvisoryLockTypeEnum $type = PostgresAdvisoryLockTypeEnum::NonBlocking, - PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive, + PostgresAdvisoryLockWaitModeEnum $waitMode = PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, ): bool { if ($level === PostgresAdvisoryLockLevelEnum::Transaction && $dbConnection->inTransaction() === false) { throw new LogicException( @@ -114,46 +114,46 @@ private function acquireLock( ); } - $sql = match ([$level, $type, $mode]) { + $sql = match ([$level, $waitMode, $accessMode]) { [ PostgresAdvisoryLockLevelEnum::Transaction, - PostgresAdvisoryLockTypeEnum::NonBlocking, - PostgresLockModeEnum::Exclusive, + PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockAccessModeEnum::Exclusive, ] => 'SELECT PG_TRY_ADVISORY_XACT_LOCK(:class_id, :object_id);', [ PostgresAdvisoryLockLevelEnum::Transaction, - PostgresAdvisoryLockTypeEnum::Blocking, - PostgresLockModeEnum::Exclusive, + PostgresAdvisoryLockWaitModeEnum::Blocking, + PostgresLockAccessModeEnum::Exclusive, ] => 'SELECT PG_ADVISORY_XACT_LOCK(:class_id, :object_id);', [ PostgresAdvisoryLockLevelEnum::Transaction, - PostgresAdvisoryLockTypeEnum::NonBlocking, - PostgresLockModeEnum::Share, + PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockAccessModeEnum::Share, ] => 'SELECT PG_TRY_ADVISORY_XACT_LOCK_SHARED(:class_id, :object_id);', [ PostgresAdvisoryLockLevelEnum::Transaction, - PostgresAdvisoryLockTypeEnum::Blocking, - PostgresLockModeEnum::Share, + PostgresAdvisoryLockWaitModeEnum::Blocking, + PostgresLockAccessModeEnum::Share, ] => 'SELECT PG_ADVISORY_XACT_LOCK_SHARED(:class_id, :object_id);', [ PostgresAdvisoryLockLevelEnum::Session, - PostgresAdvisoryLockTypeEnum::NonBlocking, - PostgresLockModeEnum::Exclusive, + PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockAccessModeEnum::Exclusive, ] => 'SELECT PG_TRY_ADVISORY_LOCK(:class_id, :object_id);', [ PostgresAdvisoryLockLevelEnum::Session, - PostgresAdvisoryLockTypeEnum::Blocking, - PostgresLockModeEnum::Exclusive, + PostgresAdvisoryLockWaitModeEnum::Blocking, + PostgresLockAccessModeEnum::Exclusive, ] => 'SELECT PG_ADVISORY_LOCK(:class_id, :object_id);', [ PostgresAdvisoryLockLevelEnum::Session, - PostgresAdvisoryLockTypeEnum::NonBlocking, - PostgresLockModeEnum::Share, + PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockAccessModeEnum::Share, ] => 'SELECT PG_TRY_ADVISORY_LOCK_SHARED(:class_id, :object_id);', [ PostgresAdvisoryLockLevelEnum::Session, - PostgresAdvisoryLockTypeEnum::Blocking, - PostgresLockModeEnum::Share, + PostgresAdvisoryLockWaitModeEnum::Blocking, + PostgresLockAccessModeEnum::Share, ] => 'SELECT PG_ADVISORY_LOCK_SHARED(:class_id, :object_id);', }; $sql .= " -- $postgresLockId->humanReadableValue"; diff --git a/src/Locker/PostgresLockModeEnum.php b/src/Locker/PostgresLockAccessModeEnum.php similarity index 53% rename from src/Locker/PostgresLockModeEnum.php rename to src/Locker/PostgresLockAccessModeEnum.php index 21900a3..7a264cc 100644 --- a/src/Locker/PostgresLockModeEnum.php +++ b/src/Locker/PostgresLockAccessModeEnum.php @@ -5,9 +5,9 @@ namespace Cog\DbLocker\Locker; /** - * PostgresLockModeEnum defines the access mode of advisory lock acquisition. + * PostgresLockAccessModeEnum defines the access mode of advisory lock acquisition. */ -enum PostgresLockModeEnum: string +enum PostgresLockAccessModeEnum: string { case Exclusive = 'ExclusiveLock'; case Share = 'ShareLock'; diff --git a/test/Integration/AbstractIntegrationTestCase.php b/test/Integration/AbstractIntegrationTestCase.php index bdafc8e..cfa7099 100644 --- a/test/Integration/AbstractIntegrationTestCase.php +++ b/test/Integration/AbstractIntegrationTestCase.php @@ -13,7 +13,7 @@ namespace Cog\Test\DbLocker\Integration; -use Cog\DbLocker\Locker\PostgresLockModeEnum; +use Cog\DbLocker\Locker\PostgresLockAccessModeEnum; use Cog\DbLocker\LockId\PostgresLockId; use PDO; use PHPUnit\Framework\TestCase; @@ -45,7 +45,7 @@ protected function initPostgresPdoConnection(): PDO protected function assertPgAdvisoryLockExistsInConnection( PDO $dbConnection, PostgresLockId $postgresLockId, - PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive, + PostgresLockAccessModeEnum $mode = PostgresLockAccessModeEnum::Exclusive, ): void { $row = $this->findPostgresAdvisoryLockInConnection( $dbConnection, @@ -64,7 +64,7 @@ protected function assertPgAdvisoryLockExistsInConnection( protected function assertPgAdvisoryLockMissingInConnection( PDO $dbConnection, PostgresLockId $postgresLockId, - PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive, + PostgresLockAccessModeEnum $mode = PostgresLockAccessModeEnum::Exclusive, ): void { $row = $this->findPostgresAdvisoryLockInConnection( $dbConnection, @@ -96,7 +96,7 @@ protected function assertPgAdvisoryLocksCount( private function findPostgresAdvisoryLockInConnection( PDO $dbConnection, PostgresLockId $postgresLockId, - PostgresLockModeEnum $mode, + PostgresLockAccessModeEnum $mode, ): object | null { $statement = $dbConnection->prepare( <<<'SQL' diff --git a/test/Integration/Locker/PostgresAdvisoryLockerTest.php b/test/Integration/Locker/PostgresAdvisoryLockerTest.php index 40e0751..1e54aee 100644 --- a/test/Integration/Locker/PostgresAdvisoryLockerTest.php +++ b/test/Integration/Locker/PostgresAdvisoryLockerTest.php @@ -15,7 +15,7 @@ use Cog\DbLocker\Locker\PostgresAdvisoryLocker; use Cog\DbLocker\Locker\PostgresAdvisoryLockLevelEnum; -use Cog\DbLocker\Locker\PostgresLockModeEnum; +use Cog\DbLocker\Locker\PostgresLockAccessModeEnum; use Cog\DbLocker\LockId\PostgresLockId; use Cog\Test\DbLocker\Integration\AbstractIntegrationTestCase; use LogicException; @@ -28,7 +28,7 @@ final class PostgresAdvisoryLockerTest extends AbstractIntegrationTestCase #[DataProvider('provideItCanTryAcquireLockWithinSessionData')] public function testItCanTryAcquireLockWithinSession( - PostgresLockModeEnum $mode, + PostgresLockAccessModeEnum $mode, ): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); @@ -37,7 +37,7 @@ public function testItCanTryAcquireLockWithinSession( $isLockAcquired = $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, - mode: $mode, + accessMode: $mode, ); $this->assertTrue($isLockAcquired); @@ -49,17 +49,17 @@ public static function provideItCanTryAcquireLockWithinSessionData(): array { return [ 'exclusive lock' => [ - PostgresLockModeEnum::Exclusive, + PostgresLockAccessModeEnum::Exclusive, ], 'share lock' => [ - PostgresLockModeEnum::Share, + PostgresLockAccessModeEnum::Share, ], ]; } #[DataProvider('provideItCanTryAcquireLockWithinTransactionData')] public function testItCanTryAcquireLockWithinTransaction( - PostgresLockModeEnum $mode, + PostgresLockAccessModeEnum $mode, ): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); @@ -69,7 +69,7 @@ public function testItCanTryAcquireLockWithinTransaction( $isLockAcquired = $locker->acquireTransactionLevelLock( $dbConnection, $postgresLockId, - mode: $mode, + accessMode: $mode, ); $this->assertTrue($isLockAcquired); @@ -81,10 +81,10 @@ public static function provideItCanTryAcquireLockWithinTransactionData(): array { return [ 'exclusive lock' => [ - PostgresLockModeEnum::Exclusive, + PostgresLockAccessModeEnum::Exclusive, ], 'share lock' => [ - PostgresLockModeEnum::Share, + PostgresLockAccessModeEnum::Share, ], ]; } @@ -195,7 +195,7 @@ public function testItCannotAcquireSameLockInTwoConnections(): void #[DataProvider('provideItCanReleaseLockData')] public function testItCanReleaseLock( - PostgresLockModeEnum $mode, + PostgresLockAccessModeEnum $mode, ): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); @@ -203,13 +203,13 @@ public function testItCanReleaseLock( $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, - mode: $mode, + accessMode: $mode, ); $isLockReleased = $locker->releaseSessionLevelLock( $dbConnection, $postgresLockId, - mode: $mode, + accessMode: $mode, ); $this->assertTrue($isLockReleased); @@ -220,18 +220,18 @@ public static function provideItCanReleaseLockData(): array { return [ 'exclusive lock' => [ - PostgresLockModeEnum::Exclusive, + PostgresLockAccessModeEnum::Exclusive, ], 'share lock' => [ - PostgresLockModeEnum::Share, + PostgresLockAccessModeEnum::Share, ], ]; } #[DataProvider('provideItCanNotReleaseLockOfDifferentModesData')] public function testItCanNotReleaseLockOfDifferentModes( - PostgresLockModeEnum $acquireMode, - PostgresLockModeEnum $releaseMode, + PostgresLockAccessModeEnum $acquireMode, + PostgresLockAccessModeEnum $releaseMode, ): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); @@ -239,13 +239,13 @@ public function testItCanNotReleaseLockOfDifferentModes( $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, - mode: $acquireMode, + accessMode: $acquireMode, ); $isLockReleased = $locker->releaseSessionLevelLock( $dbConnection, $postgresLockId, - mode: $releaseMode, + accessMode: $releaseMode, ); $this->assertFalse($isLockReleased); @@ -257,12 +257,12 @@ public static function provideItCanNotReleaseLockOfDifferentModesData(): array { return [ 'release exclusive lock as share' => [ - 'acquireMode' => PostgresLockModeEnum::Exclusive, - 'releaseMode' => PostgresLockModeEnum::Share, + 'acquireMode' => PostgresLockAccessModeEnum::Exclusive, + 'releaseMode' => PostgresLockAccessModeEnum::Share, ], 'release share lock as exclusive' => [ - 'acquireMode' => PostgresLockModeEnum::Share, - 'releaseMode' => PostgresLockModeEnum::Exclusive, + 'acquireMode' => PostgresLockAccessModeEnum::Share, + 'releaseMode' => PostgresLockAccessModeEnum::Exclusive, ], ]; } From 9440bf6d2c356bc57d3c9ef7bd3c0085608d108b Mon Sep 17 00:00:00 2001 From: Anton Komarev Date: Mon, 28 Jul 2025 10:53:53 +0300 Subject: [PATCH 04/13] Rewrite locker API --- src/Locker/PostgresAdvisoryLockWaitModeEnum.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Locker/PostgresAdvisoryLockWaitModeEnum.php b/src/Locker/PostgresAdvisoryLockWaitModeEnum.php index 4dac098..e5229d5 100644 --- a/src/Locker/PostgresAdvisoryLockWaitModeEnum.php +++ b/src/Locker/PostgresAdvisoryLockWaitModeEnum.php @@ -20,6 +20,6 @@ */ enum PostgresAdvisoryLockWaitModeEnum { - case NonBlocking; case Blocking; + case NonBlocking; } From 8f479dbfc7b55b76b84bc4c56c7ea9671fea1e44 Mon Sep 17 00:00:00 2001 From: Anton Komarev Date: Mon, 28 Jul 2025 11:23:22 +0300 Subject: [PATCH 05/13] Rewrite locker API --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 2ed4e3b..827a049 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,6 @@ $dbConnection->beginTransaction(); $isLockAcquired = $locker->acquireTransactionLevelLock( $dbConnection, $lockId, - \Cog\DbLocker\Locker\PostgresAdvisoryLockLevelEnum::Transaction, \Cog\DbLocker\Locker\PostgresAdvisoryLockWaitModeEnum::NonBlocking, \Cog\DbLocker\Locker\PostgresLockAccessModeEnum::Exclusive, ); @@ -64,7 +63,6 @@ $lockId = \Cog\DbLocker\LockId\PostgresLockId::fromKeyValue('user', '4'); $isLockAcquired = $locker->acquireSessionLevelLock( $dbConnection, $lockId, - \Cog\DbLocker\Locker\PostgresAdvisoryLockLevelEnum::Session, \Cog\DbLocker\Locker\PostgresAdvisoryLockWaitModeEnum::NonBlocking, \Cog\DbLocker\Locker\PostgresLockAccessModeEnum::Exclusive, ); From 43ac0ceaa6ae827ae2b23baebc7546f6df6b46c8 Mon Sep 17 00:00:00 2001 From: Anton Komarev Date: Mon, 28 Jul 2025 11:30:02 +0300 Subject: [PATCH 06/13] Rewrite locker API --- src/Locker/PostgresAdvisoryLocker.php | 5 --- .../Locker/PostgresAdvisoryLockerTest.php | 31 ------------------- 2 files changed, 36 deletions(-) diff --git a/src/Locker/PostgresAdvisoryLocker.php b/src/Locker/PostgresAdvisoryLocker.php index ee7c627..e583631 100644 --- a/src/Locker/PostgresAdvisoryLocker.php +++ b/src/Locker/PostgresAdvisoryLocker.php @@ -63,13 +63,8 @@ public function acquireSessionLevelLock( public function releaseSessionLevelLock( PDO $dbConnection, PostgresLockId $postgresLockId, - PostgresAdvisoryLockLevelEnum $level = PostgresAdvisoryLockLevelEnum::Session, PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, ): bool { - if ($level === PostgresAdvisoryLockLevelEnum::Transaction) { - throw new \InvalidArgumentException('Transaction-level advisory lock cannot be released'); - } - $sql = match ($accessMode) { PostgresLockAccessModeEnum::Exclusive => 'SELECT PG_ADVISORY_UNLOCK(:class_id, :object_id);', PostgresLockAccessModeEnum::Share => 'SELECT PG_ADVISORY_UNLOCK_SHARED(:class_id, :object_id);', diff --git a/test/Integration/Locker/PostgresAdvisoryLockerTest.php b/test/Integration/Locker/PostgresAdvisoryLockerTest.php index 1e54aee..2a823b2 100644 --- a/test/Integration/Locker/PostgresAdvisoryLockerTest.php +++ b/test/Integration/Locker/PostgresAdvisoryLockerTest.php @@ -14,7 +14,6 @@ namespace Cog\Test\DbLocker\Integration\Locker; use Cog\DbLocker\Locker\PostgresAdvisoryLocker; -use Cog\DbLocker\Locker\PostgresAdvisoryLockLevelEnum; use Cog\DbLocker\Locker\PostgresLockAccessModeEnum; use Cog\DbLocker\LockId\PostgresLockId; use Cog\Test\DbLocker\Integration\AbstractIntegrationTestCase; @@ -567,36 +566,6 @@ public function testItCannotReleaseAllLocksAcquiredWithinTransaction(): void $this->assertPgAdvisoryLockExistsInConnection($dbConnection, $postgresLockId2); } - public function testItCannotReleaseLockWithTransactionScope(): void - { - $locker = $this->initLocker(); - $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId1 = PostgresLockId::fromKeyValue('test'); - $postgresLockId2 = PostgresLockId::fromKeyValue('test2'); - $locker->acquireSessionLevelLock( - $dbConnection, - $postgresLockId1, - ); - $dbConnection->beginTransaction(); - $locker->acquireTransactionLevelLock( - $dbConnection, - $postgresLockId2, - ); - - try { - $locker->releaseSessionLevelLock( - $dbConnection, - $postgresLockId2, - PostgresAdvisoryLockLevelEnum::Transaction, - ); - } catch (\InvalidArgumentException $exception) { - $this->assertSame( - 'Transaction-level advisory lock cannot be released', - $exception->getMessage(), - ); - } - } - private function initLocker(): PostgresAdvisoryLocker { return new PostgresAdvisoryLocker(); From 35ec74789f4e680fad3ee8e7b1cd450c128859b5 Mon Sep 17 00:00:00 2001 From: Anton Komarev Date: Mon, 28 Jul 2025 15:45:44 +0300 Subject: [PATCH 07/13] Rewrite locker API --- src/Locker/AdvisoryLockSessionLevel.php | 65 +++++++++++++++++++++++++ src/Locker/PostgresAdvisoryLocker.php | 29 ++++++++++- 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 src/Locker/AdvisoryLockSessionLevel.php diff --git a/src/Locker/AdvisoryLockSessionLevel.php b/src/Locker/AdvisoryLockSessionLevel.php new file mode 100644 index 0000000..1682822 --- /dev/null +++ b/src/Locker/AdvisoryLockSessionLevel.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Cog\DbLocker\Locker; + +use Cog\DbLocker\LockId\PostgresLockId; +use PDO; + +final class AdvisoryLockSessionLevel +{ + private bool $isReleased = false; + + public function __construct( + private readonly PDO $dbConnection, + private readonly PostgresAdvisoryLocker $locker, + public readonly PostgresLockId $lockId, + public readonly PostgresLockAccessModeEnum $accessMode, + public readonly bool $wasAcquired, + ) {} + + /** + * Explicitly release the lock if it was acquired and not yet released. + * + * @return bool True if the lock was released, false if it wasn't acquired or already released + */ + public function release(): bool + { + /** + * This code is mimicking the behavior of DB lock release. + */ + if (!$this->wasAcquired || $this->isReleased) { + return false; + } + + $wasReleased = $this->locker->releaseSessionLevelLock( + $this->dbConnection, + $this->lockId, + ); + + if ($wasReleased) { + $this->isReleased = true; + } + + return $wasReleased; + } + + /** + * Automatically release the lock when the handle is destroyed. + */ + public function __destruct() + { + // TODO: Do we need to + $this->release(); + } +} \ No newline at end of file diff --git a/src/Locker/PostgresAdvisoryLocker.php b/src/Locker/PostgresAdvisoryLocker.php index e583631..8a4e796 100644 --- a/src/Locker/PostgresAdvisoryLocker.php +++ b/src/Locker/PostgresAdvisoryLocker.php @@ -38,7 +38,34 @@ public function acquireTransactionLevelLock( } /** - * Acquire a session-level advisory lock with a configurable acquisition type and mode. + * Acquire a session-level advisory lock with a configurable wait & access modes. + * + * TODO: Write that transaction-level is recommended. + * TODO: Cover with tests + */ + public function acquireSessionLevelLockHandler( + PDO $dbConnection, + PostgresLockId $postgresLockId, + PostgresAdvisoryLockWaitModeEnum $waitMode = PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, + ): AdvisoryLockSessionLevel { + return new AdvisoryLockSessionLevel( + $dbConnection, + $this, + $postgresLockId, + $accessMode, + wasAcquired: $this->acquireLock( + $dbConnection, + $postgresLockId, + PostgresAdvisoryLockLevelEnum::Session, + $waitMode, + $accessMode, + ), + ); + } + + /** + * Acquire a session-level advisory lock with a configurable wait & access modes. * * TODO: Write that transaction-level is recommended. */ From 6d6ef317cd4356c64c5d7e1d4f357dc50401e9d9 Mon Sep 17 00:00:00 2001 From: Anton Komarev Date: Mon, 28 Jul 2025 15:49:11 +0300 Subject: [PATCH 08/13] Rewrite locker API --- src/LockId/PostgresLockId.php | 2 ++ .../Locker/PostgresAdvisoryLockerTest.php | 26 +++++++++---------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/LockId/PostgresLockId.php b/src/LockId/PostgresLockId.php index 344e617..70d2d01 100644 --- a/src/LockId/PostgresLockId.php +++ b/src/LockId/PostgresLockId.php @@ -46,6 +46,8 @@ public static function fromKeyValue( return new self( classId: self::convertStringToSignedInt32($key), objectId: self::convertStringToSignedInt32($value), + // TODO: Do we need to sanitize it? + // TODO: Do we need to omit ":" on end if no value is passed humanReadableValue: "$key:$value", ); } diff --git a/test/Integration/Locker/PostgresAdvisoryLockerTest.php b/test/Integration/Locker/PostgresAdvisoryLockerTest.php index 2a823b2..1d72eb6 100644 --- a/test/Integration/Locker/PostgresAdvisoryLockerTest.php +++ b/test/Integration/Locker/PostgresAdvisoryLockerTest.php @@ -27,7 +27,7 @@ final class PostgresAdvisoryLockerTest extends AbstractIntegrationTestCase #[DataProvider('provideItCanTryAcquireLockWithinSessionData')] public function testItCanTryAcquireLockWithinSession( - PostgresLockAccessModeEnum $mode, + PostgresLockAccessModeEnum $accessMode, ): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); @@ -36,12 +36,12 @@ public function testItCanTryAcquireLockWithinSession( $isLockAcquired = $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, - accessMode: $mode, + accessMode: $accessMode, ); $this->assertTrue($isLockAcquired); $this->assertPgAdvisoryLocksCount(1); - $this->assertPgAdvisoryLockExistsInConnection($dbConnection, $postgresLockId, $mode); + $this->assertPgAdvisoryLockExistsInConnection($dbConnection, $postgresLockId, $accessMode); } public static function provideItCanTryAcquireLockWithinSessionData(): array @@ -58,7 +58,7 @@ public static function provideItCanTryAcquireLockWithinSessionData(): array #[DataProvider('provideItCanTryAcquireLockWithinTransactionData')] public function testItCanTryAcquireLockWithinTransaction( - PostgresLockAccessModeEnum $mode, + PostgresLockAccessModeEnum $accessMode, ): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); @@ -68,12 +68,12 @@ public function testItCanTryAcquireLockWithinTransaction( $isLockAcquired = $locker->acquireTransactionLevelLock( $dbConnection, $postgresLockId, - accessMode: $mode, + accessMode: $accessMode, ); $this->assertTrue($isLockAcquired); $this->assertPgAdvisoryLocksCount(1); - $this->assertPgAdvisoryLockExistsInConnection($dbConnection, $postgresLockId, $mode); + $this->assertPgAdvisoryLockExistsInConnection($dbConnection, $postgresLockId, $accessMode); } public static function provideItCanTryAcquireLockWithinTransactionData(): array @@ -194,7 +194,7 @@ public function testItCannotAcquireSameLockInTwoConnections(): void #[DataProvider('provideItCanReleaseLockData')] public function testItCanReleaseLock( - PostgresLockAccessModeEnum $mode, + PostgresLockAccessModeEnum $accessMode, ): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); @@ -202,13 +202,13 @@ public function testItCanReleaseLock( $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, - accessMode: $mode, + accessMode: $accessMode, ); $isLockReleased = $locker->releaseSessionLevelLock( $dbConnection, $postgresLockId, - accessMode: $mode, + accessMode: $accessMode, ); $this->assertTrue($isLockReleased); @@ -256,12 +256,12 @@ public static function provideItCanNotReleaseLockOfDifferentModesData(): array { return [ 'release exclusive lock as share' => [ - 'acquireMode' => PostgresLockAccessModeEnum::Exclusive, - 'releaseMode' => PostgresLockAccessModeEnum::Share, + 'acquireAccessMode' => PostgresLockAccessModeEnum::Exclusive, + 'releaseAccessMode' => PostgresLockAccessModeEnum::Share, ], 'release share lock as exclusive' => [ - 'acquireMode' => PostgresLockAccessModeEnum::Share, - 'releaseMode' => PostgresLockAccessModeEnum::Exclusive, + 'acquireAccessMode' => PostgresLockAccessModeEnum::Share, + 'releaseAccessMode' => PostgresLockAccessModeEnum::Exclusive, ], ]; } From ebe53638ac289e61078cac9194eb71b48810f0c6 Mon Sep 17 00:00:00 2001 From: Anton Komarev Date: Mon, 28 Jul 2025 18:53:29 +0300 Subject: [PATCH 09/13] Rewrite locker API --- src/Locker/AdvisoryLockSessionLevel.php | 3 +++ src/Locker/AdvisoryLockTransactionLevel.php | 24 ++++++++++++++++++ src/Locker/PostgresAdvisoryLocker.php | 28 ++++++++++++++++++--- 3 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 src/Locker/AdvisoryLockTransactionLevel.php diff --git a/src/Locker/AdvisoryLockSessionLevel.php b/src/Locker/AdvisoryLockSessionLevel.php index 1682822..0bcf423 100644 --- a/src/Locker/AdvisoryLockSessionLevel.php +++ b/src/Locker/AdvisoryLockSessionLevel.php @@ -16,6 +16,9 @@ use Cog\DbLocker\LockId\PostgresLockId; use PDO; +/** + * @internal + */ final class AdvisoryLockSessionLevel { private bool $isReleased = false; diff --git a/src/Locker/AdvisoryLockTransactionLevel.php b/src/Locker/AdvisoryLockTransactionLevel.php new file mode 100644 index 0000000..e9ce65b --- /dev/null +++ b/src/Locker/AdvisoryLockTransactionLevel.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Cog\DbLocker\Locker; + +/** + * @internal + */ +final class AdvisoryLockTransactionLevel +{ + public function __construct( + public readonly bool $wasAcquired, + ) {} +} \ No newline at end of file diff --git a/src/Locker/PostgresAdvisoryLocker.php b/src/Locker/PostgresAdvisoryLocker.php index 8a4e796..01772c5 100644 --- a/src/Locker/PostgresAdvisoryLocker.php +++ b/src/Locker/PostgresAdvisoryLocker.php @@ -20,7 +20,29 @@ final class PostgresAdvisoryLocker { /** - * Acquire a transaction-level advisory lock with a configurable acquisition type and mode. + * Acquire a transaction-level advisory lock with configurable wait and access modes. + * + * TODO: Cover with tests + */ + public function acquireTransactionLevelLockHandler( + PDO $dbConnection, + PostgresLockId $postgresLockId, + PostgresAdvisoryLockWaitModeEnum $waitMode = PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, + ): AdvisoryLockTransactionLevel { + return new AdvisoryLockTransactionLevel( + wasAcquired: $this->acquireLock( + $dbConnection, + $postgresLockId, + PostgresAdvisoryLockLevelEnum::Transaction, + $waitMode, + $accessMode, + ), + ); + } + + /** + * Acquire a transaction-level advisory lock with configurable wait and access modes. */ public function acquireTransactionLevelLock( PDO $dbConnection, @@ -38,7 +60,7 @@ public function acquireTransactionLevelLock( } /** - * Acquire a session-level advisory lock with a configurable wait & access modes. + * Acquire a session-level advisory lock with configurable wait and access modes. * * TODO: Write that transaction-level is recommended. * TODO: Cover with tests @@ -65,7 +87,7 @@ public function acquireSessionLevelLockHandler( } /** - * Acquire a session-level advisory lock with a configurable wait & access modes. + * Acquire a session-level advisory lock with configurable wait and access modes. * * TODO: Write that transaction-level is recommended. */ From e5ac8441cc4b699518e4606dee01dc6b342abfb0 Mon Sep 17 00:00:00 2001 From: Anton Komarev Date: Mon, 28 Jul 2025 18:55:14 +0300 Subject: [PATCH 10/13] Rewrite locker API --- README.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 827a049..5830da2 100644 --- a/README.md +++ b/README.md @@ -38,13 +38,13 @@ $locker = new \Cog\DbLocker\Locker\PostgresAdvisoryLocker(); $lockId = \Cog\DbLocker\LockId\PostgresLockId::fromKeyValue('user', '4'); $dbConnection->beginTransaction(); -$isLockAcquired = $locker->acquireTransactionLevelLock( +$lock = $locker->acquireSessionLevelLockHandler( $dbConnection, $lockId, \Cog\DbLocker\Locker\PostgresAdvisoryLockWaitModeEnum::NonBlocking, \Cog\DbLocker\Locker\PostgresLockAccessModeEnum::Exclusive, ); -if ($isLockAcquired) { +if ($lock->wasAcquired) { // Execute logic if lock was successful } else { // Execute logic if lock acquisition has been failed @@ -60,18 +60,21 @@ $dbConnection = new PDO($dsn, $username, $password); $locker = new \Cog\DbLocker\Locker\PostgresAdvisoryLocker(); $lockId = \Cog\DbLocker\LockId\PostgresLockId::fromKeyValue('user', '4'); -$isLockAcquired = $locker->acquireSessionLevelLock( - $dbConnection, - $lockId, - \Cog\DbLocker\Locker\PostgresAdvisoryLockWaitModeEnum::NonBlocking, - \Cog\DbLocker\Locker\PostgresLockAccessModeEnum::Exclusive, -); -if ($isLockAcquired) { - // Execute logic if lock was successful -} else { - // Execute logic if lock acquisition has been failed +try { + $lock = $locker->acquireSessionLevelLockHandler( + $dbConnection, + $lockId, + \Cog\DbLocker\Locker\PostgresAdvisoryLockWaitModeEnum::NonBlocking, + \Cog\DbLocker\Locker\PostgresLockAccessModeEnum::Exclusive, + ); + if ($lock->wasAcquired) { + // Execute logic if lock was successful + } else { + // Execute logic if lock acquisition has been failed + } +} finally { + $lock->release(); } -$locker->releaseSessionLevelLock($dbConnection, $lockId); ``` ## Changelog From 0a3c22733e843d952bb376945073389e954f0781 Mon Sep 17 00:00:00 2001 From: Anton Komarev Date: Mon, 28 Jul 2025 19:01:54 +0300 Subject: [PATCH 11/13] Rewrite locker API --- README.md | 16 ++--- .../Enum}/PostgresLockAccessModeEnum.php | 2 +- .../Enum/PostgresLockLevelEnum.php} | 6 +- .../Enum/PostgresLockWaitModeEnum.php} | 6 +- .../PostgresSessionLevelLockHandle.php} | 8 ++- .../PostgresTransactionLevelLockHandle.php} | 4 +- .../PostgresAdvisoryLocker.php | 70 ++++++++++--------- src/{LockId => Postgres}/PostgresLockId.php | 2 +- .../AbstractIntegrationTestCase.php | 4 +- .../PostgresAdvisoryLockerTest.php | 8 +-- .../PostgresLockIdTest.php | 4 +- 11 files changed, 68 insertions(+), 62 deletions(-) rename src/{Locker => Postgres/Enum}/PostgresLockAccessModeEnum.php (86%) rename src/{Locker/PostgresAdvisoryLockLevelEnum.php => Postgres/Enum/PostgresLockLevelEnum.php} (77%) rename src/{Locker/PostgresAdvisoryLockWaitModeEnum.php => Postgres/Enum/PostgresLockWaitModeEnum.php} (77%) rename src/{Locker/AdvisoryLockSessionLevel.php => Postgres/LockHandle/PostgresSessionLevelLockHandle.php} (86%) rename src/{Locker/AdvisoryLockTransactionLevel.php => Postgres/LockHandle/PostgresTransactionLevelLockHandle.php} (80%) rename src/{Locker => Postgres}/PostgresAdvisoryLocker.php (73%) rename src/{LockId => Postgres}/PostgresLockId.php (98%) rename test/Integration/{Locker => Postgres}/PostgresAdvisoryLockerTest.php (98%) rename test/Unit/{LockId => Postgres}/PostgresLockIdTest.php (97%) diff --git a/README.md b/README.md index 5830da2..86c66b8 100644 --- a/README.md +++ b/README.md @@ -34,15 +34,15 @@ composer require cybercog/php-db-locker ```php $dbConnection = new PDO($dsn, $username, $password); -$locker = new \Cog\DbLocker\Locker\PostgresAdvisoryLocker(); -$lockId = \Cog\DbLocker\LockId\PostgresLockId::fromKeyValue('user', '4'); +$locker = new \Cog\DbLocker\Postgres\PostgresAdvisoryLocker(); +$lockId = \Cog\DbLocker\Postgres\PostgresLockId::fromKeyValue('user', '4'); $dbConnection->beginTransaction(); $lock = $locker->acquireSessionLevelLockHandler( $dbConnection, $lockId, - \Cog\DbLocker\Locker\PostgresAdvisoryLockWaitModeEnum::NonBlocking, - \Cog\DbLocker\Locker\PostgresLockAccessModeEnum::Exclusive, + \Cog\DbLocker\Postgres\Enum\PostgresLockWaitModeEnum::NonBlocking, + \Cog\DbLocker\Postgres\Enum\PostgresLockAccessModeEnum::Exclusive, ); if ($lock->wasAcquired) { // Execute logic if lock was successful @@ -57,15 +57,15 @@ $dbConnection->commit(); ```php $dbConnection = new PDO($dsn, $username, $password); -$locker = new \Cog\DbLocker\Locker\PostgresAdvisoryLocker(); -$lockId = \Cog\DbLocker\LockId\PostgresLockId::fromKeyValue('user', '4'); +$locker = new \Cog\DbLocker\Postgres\PostgresAdvisoryLocker(); +$lockId = \Cog\DbLocker\Postgres\PostgresLockId::fromKeyValue('user', '4'); try { $lock = $locker->acquireSessionLevelLockHandler( $dbConnection, $lockId, - \Cog\DbLocker\Locker\PostgresAdvisoryLockWaitModeEnum::NonBlocking, - \Cog\DbLocker\Locker\PostgresLockAccessModeEnum::Exclusive, + \Cog\DbLocker\Postgres\Enum\PostgresLockWaitModeEnum::NonBlocking, + \Cog\DbLocker\Postgres\Enum\PostgresLockAccessModeEnum::Exclusive, ); if ($lock->wasAcquired) { // Execute logic if lock was successful diff --git a/src/Locker/PostgresLockAccessModeEnum.php b/src/Postgres/Enum/PostgresLockAccessModeEnum.php similarity index 86% rename from src/Locker/PostgresLockAccessModeEnum.php rename to src/Postgres/Enum/PostgresLockAccessModeEnum.php index 7a264cc..1482be6 100644 --- a/src/Locker/PostgresLockAccessModeEnum.php +++ b/src/Postgres/Enum/PostgresLockAccessModeEnum.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Cog\DbLocker\Locker; +namespace Cog\DbLocker\Postgres\Enum; /** * PostgresLockAccessModeEnum defines the access mode of advisory lock acquisition. diff --git a/src/Locker/PostgresAdvisoryLockLevelEnum.php b/src/Postgres/Enum/PostgresLockLevelEnum.php similarity index 77% rename from src/Locker/PostgresAdvisoryLockLevelEnum.php rename to src/Postgres/Enum/PostgresLockLevelEnum.php index 859cb6a..3b983c2 100644 --- a/src/Locker/PostgresAdvisoryLockLevelEnum.php +++ b/src/Postgres/Enum/PostgresLockLevelEnum.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Cog\DbLocker\Locker; +namespace Cog\DbLocker\Postgres\Enum; /** - * PostgresAdvisoryLockLevelEnum defines the level of advisory lock acquisition. + * PostgresLockLevelEnum defines the level of advisory lock acquisition. * * - Session. Session-level advisory lock (without _XACT_): * - PG_ADVISORY_LOCK @@ -18,7 +18,7 @@ * - PG_TRY_ADVISORY_XACT_LOCK * - PG_TRY_ADVISORY_XACT_LOCK_SHARED */ -enum PostgresAdvisoryLockLevelEnum +enum PostgresLockLevelEnum { case Session; case Transaction; diff --git a/src/Locker/PostgresAdvisoryLockWaitModeEnum.php b/src/Postgres/Enum/PostgresLockWaitModeEnum.php similarity index 77% rename from src/Locker/PostgresAdvisoryLockWaitModeEnum.php rename to src/Postgres/Enum/PostgresLockWaitModeEnum.php index e5229d5..401ac89 100644 --- a/src/Locker/PostgresAdvisoryLockWaitModeEnum.php +++ b/src/Postgres/Enum/PostgresLockWaitModeEnum.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Cog\DbLocker\Locker; +namespace Cog\DbLocker\Postgres\Enum; /** - * PostgresAdvisoryLockWaitModeEnum defines the type of advisory lock acquisition. + * PostgresLockWaitModeEnum defines the type of advisory lock acquisition. * * - NonBlocking. Attempt to acquire the lock without blocking (with _TRY_): * - PG_TRY_ADVISORY_LOCK @@ -18,7 +18,7 @@ * - PG_ADVISORY_XACT_LOCK * - PG_ADVISORY_XACT_LOCK_SHARED */ -enum PostgresAdvisoryLockWaitModeEnum +enum PostgresLockWaitModeEnum { case Blocking; case NonBlocking; diff --git a/src/Locker/AdvisoryLockSessionLevel.php b/src/Postgres/LockHandle/PostgresSessionLevelLockHandle.php similarity index 86% rename from src/Locker/AdvisoryLockSessionLevel.php rename to src/Postgres/LockHandle/PostgresSessionLevelLockHandle.php index 0bcf423..1518b8e 100644 --- a/src/Locker/AdvisoryLockSessionLevel.php +++ b/src/Postgres/LockHandle/PostgresSessionLevelLockHandle.php @@ -11,15 +11,17 @@ declare(strict_types=1); -namespace Cog\DbLocker\Locker; +namespace Cog\DbLocker\Postgres\LockHandle; -use Cog\DbLocker\LockId\PostgresLockId; +use Cog\DbLocker\Postgres\Enum\PostgresLockAccessModeEnum; +use Cog\DbLocker\Postgres\PostgresAdvisoryLocker; +use Cog\DbLocker\Postgres\PostgresLockId; use PDO; /** * @internal */ -final class AdvisoryLockSessionLevel +final class PostgresSessionLevelLockHandle { private bool $isReleased = false; diff --git a/src/Locker/AdvisoryLockTransactionLevel.php b/src/Postgres/LockHandle/PostgresTransactionLevelLockHandle.php similarity index 80% rename from src/Locker/AdvisoryLockTransactionLevel.php rename to src/Postgres/LockHandle/PostgresTransactionLevelLockHandle.php index e9ce65b..4733f44 100644 --- a/src/Locker/AdvisoryLockTransactionLevel.php +++ b/src/Postgres/LockHandle/PostgresTransactionLevelLockHandle.php @@ -11,12 +11,12 @@ declare(strict_types=1); -namespace Cog\DbLocker\Locker; +namespace Cog\DbLocker\Postgres\LockHandle; /** * @internal */ -final class AdvisoryLockTransactionLevel +final class PostgresTransactionLevelLockHandle { public function __construct( public readonly bool $wasAcquired, diff --git a/src/Locker/PostgresAdvisoryLocker.php b/src/Postgres/PostgresAdvisoryLocker.php similarity index 73% rename from src/Locker/PostgresAdvisoryLocker.php rename to src/Postgres/PostgresAdvisoryLocker.php index 01772c5..8fb2770 100644 --- a/src/Locker/PostgresAdvisoryLocker.php +++ b/src/Postgres/PostgresAdvisoryLocker.php @@ -11,9 +11,13 @@ declare(strict_types=1); -namespace Cog\DbLocker\Locker; +namespace Cog\DbLocker\Postgres; -use Cog\DbLocker\LockId\PostgresLockId; +use Cog\DbLocker\Postgres\Enum\PostgresLockAccessModeEnum; +use Cog\DbLocker\Postgres\Enum\PostgresLockLevelEnum; +use Cog\DbLocker\Postgres\Enum\PostgresLockWaitModeEnum; +use Cog\DbLocker\Postgres\LockHandle\PostgresSessionLevelLockHandle; +use Cog\DbLocker\Postgres\LockHandle\PostgresTransactionLevelLockHandle; use LogicException; use PDO; @@ -27,14 +31,14 @@ final class PostgresAdvisoryLocker public function acquireTransactionLevelLockHandler( PDO $dbConnection, PostgresLockId $postgresLockId, - PostgresAdvisoryLockWaitModeEnum $waitMode = PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockWaitModeEnum $waitMode = PostgresLockWaitModeEnum::NonBlocking, PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, - ): AdvisoryLockTransactionLevel { - return new AdvisoryLockTransactionLevel( + ): PostgresTransactionLevelLockHandle { + return new PostgresTransactionLevelLockHandle( wasAcquired: $this->acquireLock( $dbConnection, $postgresLockId, - PostgresAdvisoryLockLevelEnum::Transaction, + PostgresLockLevelEnum::Transaction, $waitMode, $accessMode, ), @@ -47,13 +51,13 @@ public function acquireTransactionLevelLockHandler( public function acquireTransactionLevelLock( PDO $dbConnection, PostgresLockId $postgresLockId, - PostgresAdvisoryLockWaitModeEnum $waitMode = PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockWaitModeEnum $waitMode = PostgresLockWaitModeEnum::NonBlocking, PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, ): bool { return $this->acquireLock( $dbConnection, $postgresLockId, - PostgresAdvisoryLockLevelEnum::Transaction, + PostgresLockLevelEnum::Transaction, $waitMode, $accessMode, ); @@ -68,10 +72,10 @@ public function acquireTransactionLevelLock( public function acquireSessionLevelLockHandler( PDO $dbConnection, PostgresLockId $postgresLockId, - PostgresAdvisoryLockWaitModeEnum $waitMode = PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockWaitModeEnum $waitMode = PostgresLockWaitModeEnum::NonBlocking, PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, - ): AdvisoryLockSessionLevel { - return new AdvisoryLockSessionLevel( + ): PostgresSessionLevelLockHandle { + return new PostgresSessionLevelLockHandle( $dbConnection, $this, $postgresLockId, @@ -79,7 +83,7 @@ public function acquireSessionLevelLockHandler( wasAcquired: $this->acquireLock( $dbConnection, $postgresLockId, - PostgresAdvisoryLockLevelEnum::Session, + PostgresLockLevelEnum::Session, $waitMode, $accessMode, ), @@ -94,13 +98,13 @@ public function acquireSessionLevelLockHandler( public function acquireSessionLevelLock( PDO $dbConnection, PostgresLockId $postgresLockId, - PostgresAdvisoryLockWaitModeEnum $waitMode = PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockWaitModeEnum $waitMode = PostgresLockWaitModeEnum::NonBlocking, PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, ): bool { return $this->acquireLock( $dbConnection, $postgresLockId, - PostgresAdvisoryLockLevelEnum::Session, + PostgresLockLevelEnum::Session, $waitMode, $accessMode, ); @@ -148,11 +152,11 @@ public function releaseAllSessionLevelLocks( private function acquireLock( PDO $dbConnection, PostgresLockId $postgresLockId, - PostgresAdvisoryLockLevelEnum $level, - PostgresAdvisoryLockWaitModeEnum $waitMode = PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockLevelEnum $level, + PostgresLockWaitModeEnum $waitMode = PostgresLockWaitModeEnum::NonBlocking, PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, ): bool { - if ($level === PostgresAdvisoryLockLevelEnum::Transaction && $dbConnection->inTransaction() === false) { + if ($level === PostgresLockLevelEnum::Transaction && $dbConnection->inTransaction() === false) { throw new LogicException( "Transaction-level advisory lock `$postgresLockId->humanReadableValue` cannot be acquired outside of transaction", ); @@ -160,43 +164,43 @@ private function acquireLock( $sql = match ([$level, $waitMode, $accessMode]) { [ - PostgresAdvisoryLockLevelEnum::Transaction, - PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockLevelEnum::Transaction, + PostgresLockWaitModeEnum::NonBlocking, PostgresLockAccessModeEnum::Exclusive, ] => 'SELECT PG_TRY_ADVISORY_XACT_LOCK(:class_id, :object_id);', [ - PostgresAdvisoryLockLevelEnum::Transaction, - PostgresAdvisoryLockWaitModeEnum::Blocking, + PostgresLockLevelEnum::Transaction, + PostgresLockWaitModeEnum::Blocking, PostgresLockAccessModeEnum::Exclusive, ] => 'SELECT PG_ADVISORY_XACT_LOCK(:class_id, :object_id);', [ - PostgresAdvisoryLockLevelEnum::Transaction, - PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockLevelEnum::Transaction, + PostgresLockWaitModeEnum::NonBlocking, PostgresLockAccessModeEnum::Share, ] => 'SELECT PG_TRY_ADVISORY_XACT_LOCK_SHARED(:class_id, :object_id);', [ - PostgresAdvisoryLockLevelEnum::Transaction, - PostgresAdvisoryLockWaitModeEnum::Blocking, + PostgresLockLevelEnum::Transaction, + PostgresLockWaitModeEnum::Blocking, PostgresLockAccessModeEnum::Share, ] => 'SELECT PG_ADVISORY_XACT_LOCK_SHARED(:class_id, :object_id);', [ - PostgresAdvisoryLockLevelEnum::Session, - PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockLevelEnum::Session, + PostgresLockWaitModeEnum::NonBlocking, PostgresLockAccessModeEnum::Exclusive, ] => 'SELECT PG_TRY_ADVISORY_LOCK(:class_id, :object_id);', [ - PostgresAdvisoryLockLevelEnum::Session, - PostgresAdvisoryLockWaitModeEnum::Blocking, + PostgresLockLevelEnum::Session, + PostgresLockWaitModeEnum::Blocking, PostgresLockAccessModeEnum::Exclusive, ] => 'SELECT PG_ADVISORY_LOCK(:class_id, :object_id);', [ - PostgresAdvisoryLockLevelEnum::Session, - PostgresAdvisoryLockWaitModeEnum::NonBlocking, + PostgresLockLevelEnum::Session, + PostgresLockWaitModeEnum::NonBlocking, PostgresLockAccessModeEnum::Share, ] => 'SELECT PG_TRY_ADVISORY_LOCK_SHARED(:class_id, :object_id);', [ - PostgresAdvisoryLockLevelEnum::Session, - PostgresAdvisoryLockWaitModeEnum::Blocking, + PostgresLockLevelEnum::Session, + PostgresLockWaitModeEnum::Blocking, PostgresLockAccessModeEnum::Share, ] => 'SELECT PG_ADVISORY_LOCK_SHARED(:class_id, :object_id);', }; diff --git a/src/LockId/PostgresLockId.php b/src/Postgres/PostgresLockId.php similarity index 98% rename from src/LockId/PostgresLockId.php rename to src/Postgres/PostgresLockId.php index 70d2d01..3d12a83 100644 --- a/src/LockId/PostgresLockId.php +++ b/src/Postgres/PostgresLockId.php @@ -11,7 +11,7 @@ declare(strict_types=1); -namespace Cog\DbLocker\LockId; +namespace Cog\DbLocker\Postgres; use InvalidArgumentException; diff --git a/test/Integration/AbstractIntegrationTestCase.php b/test/Integration/AbstractIntegrationTestCase.php index cfa7099..6477e90 100644 --- a/test/Integration/AbstractIntegrationTestCase.php +++ b/test/Integration/AbstractIntegrationTestCase.php @@ -13,8 +13,8 @@ namespace Cog\Test\DbLocker\Integration; -use Cog\DbLocker\Locker\PostgresLockAccessModeEnum; -use Cog\DbLocker\LockId\PostgresLockId; +use Cog\DbLocker\Postgres\Enum\PostgresLockAccessModeEnum; +use Cog\DbLocker\Postgres\PostgresLockId; use PDO; use PHPUnit\Framework\TestCase; diff --git a/test/Integration/Locker/PostgresAdvisoryLockerTest.php b/test/Integration/Postgres/PostgresAdvisoryLockerTest.php similarity index 98% rename from test/Integration/Locker/PostgresAdvisoryLockerTest.php rename to test/Integration/Postgres/PostgresAdvisoryLockerTest.php index 1d72eb6..07cb2b1 100644 --- a/test/Integration/Locker/PostgresAdvisoryLockerTest.php +++ b/test/Integration/Postgres/PostgresAdvisoryLockerTest.php @@ -11,11 +11,11 @@ declare(strict_types=1); -namespace Cog\Test\DbLocker\Integration\Locker; +namespace Cog\Test\DbLocker\Integration\Postgres; -use Cog\DbLocker\Locker\PostgresAdvisoryLocker; -use Cog\DbLocker\Locker\PostgresLockAccessModeEnum; -use Cog\DbLocker\LockId\PostgresLockId; +use Cog\DbLocker\Postgres\Enum\PostgresLockAccessModeEnum; +use Cog\DbLocker\Postgres\PostgresAdvisoryLocker; +use Cog\DbLocker\Postgres\PostgresLockId; use Cog\Test\DbLocker\Integration\AbstractIntegrationTestCase; use LogicException; use PHPUnit\Framework\Attributes\DataProvider; diff --git a/test/Unit/LockId/PostgresLockIdTest.php b/test/Unit/Postgres/PostgresLockIdTest.php similarity index 97% rename from test/Unit/LockId/PostgresLockIdTest.php rename to test/Unit/Postgres/PostgresLockIdTest.php index 0febc49..c24b7e4 100644 --- a/test/Unit/LockId/PostgresLockIdTest.php +++ b/test/Unit/Postgres/PostgresLockIdTest.php @@ -11,9 +11,9 @@ declare(strict_types=1); -namespace Cog\Test\DbLocker\Unit\LockId; +namespace Cog\Test\DbLocker\Unit\Postgres; -use Cog\DbLocker\LockId\PostgresLockId; +use Cog\DbLocker\Postgres\PostgresLockId; use Cog\Test\DbLocker\Unit\AbstractUnitTestCase; use PHPUnit\Framework\Attributes\DataProvider; From 7b7d50244e2eb5aa392a7af002e8ed1e586c47db Mon Sep 17 00:00:00 2001 From: Anton Komarev Date: Mon, 28 Jul 2025 19:03:00 +0300 Subject: [PATCH 12/13] Rewrite locker API --- src/Postgres/Enum/PostgresLockAccessModeEnum.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Postgres/Enum/PostgresLockAccessModeEnum.php b/src/Postgres/Enum/PostgresLockAccessModeEnum.php index 1482be6..8319ead 100644 --- a/src/Postgres/Enum/PostgresLockAccessModeEnum.php +++ b/src/Postgres/Enum/PostgresLockAccessModeEnum.php @@ -6,6 +6,8 @@ /** * PostgresLockAccessModeEnum defines the access mode of advisory lock acquisition. + * + * TODO: Need string values only for tests, should add match to tests instead. */ enum PostgresLockAccessModeEnum: string { From bbc13cf060bb5866c7d15eee575e0f1f9e6789c3 Mon Sep 17 00:00:00 2001 From: Anton Komarev Date: Mon, 28 Jul 2025 19:08:59 +0300 Subject: [PATCH 13/13] Rewrite locker API --- README.md | 4 +- ...kHandle.php => SessionLevelLockHandle.php} | 6 +- ...dle.php => TransactionLevelLockHandle.php} | 2 +- src/Postgres/PostgresAdvisoryLocker.php | 24 ++++---- ...PostgresLockId.php => PostgresLockKey.php} | 12 ++-- .../AbstractIntegrationTestCase.php | 8 +-- .../Postgres/PostgresAdvisoryLockerTest.php | 60 +++++++++---------- ...LockIdTest.php => PostgresLockKeyTest.php} | 10 ++-- 8 files changed, 63 insertions(+), 63 deletions(-) rename src/Postgres/LockHandle/{PostgresSessionLevelLockHandle.php => SessionLevelLockHandle.php} (92%) rename src/Postgres/LockHandle/{PostgresTransactionLevelLockHandle.php => TransactionLevelLockHandle.php} (89%) rename src/Postgres/{PostgresLockId.php => PostgresLockKey.php} (90%) rename test/Unit/Postgres/{PostgresLockIdTest.php => PostgresLockKeyTest.php} (91%) diff --git a/README.md b/README.md index 86c66b8..4ef4186 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ composer require cybercog/php-db-locker $dbConnection = new PDO($dsn, $username, $password); $locker = new \Cog\DbLocker\Postgres\PostgresAdvisoryLocker(); -$lockId = \Cog\DbLocker\Postgres\PostgresLockId::fromKeyValue('user', '4'); +$lockId = \Cog\DbLocker\Postgres\PostgresLockKey::create('user', '4'); $dbConnection->beginTransaction(); $lock = $locker->acquireSessionLevelLockHandler( @@ -58,7 +58,7 @@ $dbConnection->commit(); $dbConnection = new PDO($dsn, $username, $password); $locker = new \Cog\DbLocker\Postgres\PostgresAdvisoryLocker(); -$lockId = \Cog\DbLocker\Postgres\PostgresLockId::fromKeyValue('user', '4'); +$lockId = \Cog\DbLocker\Postgres\PostgresLockKey::create('user', '4'); try { $lock = $locker->acquireSessionLevelLockHandler( diff --git a/src/Postgres/LockHandle/PostgresSessionLevelLockHandle.php b/src/Postgres/LockHandle/SessionLevelLockHandle.php similarity index 92% rename from src/Postgres/LockHandle/PostgresSessionLevelLockHandle.php rename to src/Postgres/LockHandle/SessionLevelLockHandle.php index 1518b8e..e3298c3 100644 --- a/src/Postgres/LockHandle/PostgresSessionLevelLockHandle.php +++ b/src/Postgres/LockHandle/SessionLevelLockHandle.php @@ -15,20 +15,20 @@ use Cog\DbLocker\Postgres\Enum\PostgresLockAccessModeEnum; use Cog\DbLocker\Postgres\PostgresAdvisoryLocker; -use Cog\DbLocker\Postgres\PostgresLockId; +use Cog\DbLocker\Postgres\PostgresLockKey; use PDO; /** * @internal */ -final class PostgresSessionLevelLockHandle +final class SessionLevelLockHandle { private bool $isReleased = false; public function __construct( private readonly PDO $dbConnection, private readonly PostgresAdvisoryLocker $locker, - public readonly PostgresLockId $lockId, + public readonly PostgresLockKey $lockId, public readonly PostgresLockAccessModeEnum $accessMode, public readonly bool $wasAcquired, ) {} diff --git a/src/Postgres/LockHandle/PostgresTransactionLevelLockHandle.php b/src/Postgres/LockHandle/TransactionLevelLockHandle.php similarity index 89% rename from src/Postgres/LockHandle/PostgresTransactionLevelLockHandle.php rename to src/Postgres/LockHandle/TransactionLevelLockHandle.php index 4733f44..999b12f 100644 --- a/src/Postgres/LockHandle/PostgresTransactionLevelLockHandle.php +++ b/src/Postgres/LockHandle/TransactionLevelLockHandle.php @@ -16,7 +16,7 @@ /** * @internal */ -final class PostgresTransactionLevelLockHandle +final class TransactionLevelLockHandle { public function __construct( public readonly bool $wasAcquired, diff --git a/src/Postgres/PostgresAdvisoryLocker.php b/src/Postgres/PostgresAdvisoryLocker.php index 8fb2770..9b55507 100644 --- a/src/Postgres/PostgresAdvisoryLocker.php +++ b/src/Postgres/PostgresAdvisoryLocker.php @@ -16,8 +16,8 @@ use Cog\DbLocker\Postgres\Enum\PostgresLockAccessModeEnum; use Cog\DbLocker\Postgres\Enum\PostgresLockLevelEnum; use Cog\DbLocker\Postgres\Enum\PostgresLockWaitModeEnum; -use Cog\DbLocker\Postgres\LockHandle\PostgresSessionLevelLockHandle; -use Cog\DbLocker\Postgres\LockHandle\PostgresTransactionLevelLockHandle; +use Cog\DbLocker\Postgres\LockHandle\SessionLevelLockHandle; +use Cog\DbLocker\Postgres\LockHandle\TransactionLevelLockHandle; use LogicException; use PDO; @@ -30,11 +30,11 @@ final class PostgresAdvisoryLocker */ public function acquireTransactionLevelLockHandler( PDO $dbConnection, - PostgresLockId $postgresLockId, + PostgresLockKey $postgresLockId, PostgresLockWaitModeEnum $waitMode = PostgresLockWaitModeEnum::NonBlocking, PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, - ): PostgresTransactionLevelLockHandle { - return new PostgresTransactionLevelLockHandle( + ): TransactionLevelLockHandle { + return new TransactionLevelLockHandle( wasAcquired: $this->acquireLock( $dbConnection, $postgresLockId, @@ -50,7 +50,7 @@ public function acquireTransactionLevelLockHandler( */ public function acquireTransactionLevelLock( PDO $dbConnection, - PostgresLockId $postgresLockId, + PostgresLockKey $postgresLockId, PostgresLockWaitModeEnum $waitMode = PostgresLockWaitModeEnum::NonBlocking, PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, ): bool { @@ -71,11 +71,11 @@ public function acquireTransactionLevelLock( */ public function acquireSessionLevelLockHandler( PDO $dbConnection, - PostgresLockId $postgresLockId, + PostgresLockKey $postgresLockId, PostgresLockWaitModeEnum $waitMode = PostgresLockWaitModeEnum::NonBlocking, PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, - ): PostgresSessionLevelLockHandle { - return new PostgresSessionLevelLockHandle( + ): SessionLevelLockHandle { + return new SessionLevelLockHandle( $dbConnection, $this, $postgresLockId, @@ -97,7 +97,7 @@ public function acquireSessionLevelLockHandler( */ public function acquireSessionLevelLock( PDO $dbConnection, - PostgresLockId $postgresLockId, + PostgresLockKey $postgresLockId, PostgresLockWaitModeEnum $waitMode = PostgresLockWaitModeEnum::NonBlocking, PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, ): bool { @@ -115,7 +115,7 @@ public function acquireSessionLevelLock( */ public function releaseSessionLevelLock( PDO $dbConnection, - PostgresLockId $postgresLockId, + PostgresLockKey $postgresLockId, PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, ): bool { $sql = match ($accessMode) { @@ -151,7 +151,7 @@ public function releaseAllSessionLevelLocks( private function acquireLock( PDO $dbConnection, - PostgresLockId $postgresLockId, + PostgresLockKey $postgresLockId, PostgresLockLevelEnum $level, PostgresLockWaitModeEnum $waitMode = PostgresLockWaitModeEnum::NonBlocking, PostgresLockAccessModeEnum $accessMode = PostgresLockAccessModeEnum::Exclusive, diff --git a/src/Postgres/PostgresLockId.php b/src/Postgres/PostgresLockKey.php similarity index 90% rename from src/Postgres/PostgresLockId.php rename to src/Postgres/PostgresLockKey.php index 3d12a83..3537284 100644 --- a/src/Postgres/PostgresLockId.php +++ b/src/Postgres/PostgresLockKey.php @@ -15,7 +15,7 @@ use InvalidArgumentException; -final class PostgresLockId +final class PostgresLockKey { private const DB_INT32_VALUE_MIN = -2_147_483_648; private const DB_INT32_VALUE_MAX = 2_147_483_647; @@ -39,20 +39,20 @@ private function __construct( } } - public static function fromKeyValue( - string $key, + public static function create( + string $namespace, string $value = '', ): self { return new self( - classId: self::convertStringToSignedInt32($key), + classId: self::convertStringToSignedInt32($namespace), objectId: self::convertStringToSignedInt32($value), // TODO: Do we need to sanitize it? // TODO: Do we need to omit ":" on end if no value is passed - humanReadableValue: "$key:$value", + humanReadableValue: "$namespace:$value", ); } - public static function fromIntKeys( + public static function createFromInternalIds( int $classId, int $objectId, ): self { diff --git a/test/Integration/AbstractIntegrationTestCase.php b/test/Integration/AbstractIntegrationTestCase.php index 6477e90..cbc1e73 100644 --- a/test/Integration/AbstractIntegrationTestCase.php +++ b/test/Integration/AbstractIntegrationTestCase.php @@ -14,7 +14,7 @@ namespace Cog\Test\DbLocker\Integration; use Cog\DbLocker\Postgres\Enum\PostgresLockAccessModeEnum; -use Cog\DbLocker\Postgres\PostgresLockId; +use Cog\DbLocker\Postgres\PostgresLockKey; use PDO; use PHPUnit\Framework\TestCase; @@ -44,7 +44,7 @@ protected function initPostgresPdoConnection(): PDO protected function assertPgAdvisoryLockExistsInConnection( PDO $dbConnection, - PostgresLockId $postgresLockId, + PostgresLockKey $postgresLockId, PostgresLockAccessModeEnum $mode = PostgresLockAccessModeEnum::Exclusive, ): void { $row = $this->findPostgresAdvisoryLockInConnection( @@ -63,7 +63,7 @@ protected function assertPgAdvisoryLockExistsInConnection( protected function assertPgAdvisoryLockMissingInConnection( PDO $dbConnection, - PostgresLockId $postgresLockId, + PostgresLockKey $postgresLockId, PostgresLockAccessModeEnum $mode = PostgresLockAccessModeEnum::Exclusive, ): void { $row = $this->findPostgresAdvisoryLockInConnection( @@ -95,7 +95,7 @@ protected function assertPgAdvisoryLocksCount( private function findPostgresAdvisoryLockInConnection( PDO $dbConnection, - PostgresLockId $postgresLockId, + PostgresLockKey $postgresLockId, PostgresLockAccessModeEnum $mode, ): object | null { $statement = $dbConnection->prepare( diff --git a/test/Integration/Postgres/PostgresAdvisoryLockerTest.php b/test/Integration/Postgres/PostgresAdvisoryLockerTest.php index 07cb2b1..c7ec210 100644 --- a/test/Integration/Postgres/PostgresAdvisoryLockerTest.php +++ b/test/Integration/Postgres/PostgresAdvisoryLockerTest.php @@ -15,7 +15,7 @@ use Cog\DbLocker\Postgres\Enum\PostgresLockAccessModeEnum; use Cog\DbLocker\Postgres\PostgresAdvisoryLocker; -use Cog\DbLocker\Postgres\PostgresLockId; +use Cog\DbLocker\Postgres\PostgresLockKey; use Cog\Test\DbLocker\Integration\AbstractIntegrationTestCase; use LogicException; use PHPUnit\Framework\Attributes\DataProvider; @@ -31,7 +31,7 @@ public function testItCanTryAcquireLockWithinSession( ): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $isLockAcquired = $locker->acquireSessionLevelLock( $dbConnection, @@ -62,7 +62,7 @@ public function testItCanTryAcquireLockWithinTransaction( ): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $dbConnection->beginTransaction(); $isLockAcquired = $locker->acquireTransactionLevelLock( @@ -93,7 +93,7 @@ public function testItCanTryAcquireLockFromIntKeysCornerCases(): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromIntKeys(self::DB_INT32_VALUE_MIN, 0); + $postgresLockId = PostgresLockKey::createFromInternalIds(self::DB_INT32_VALUE_MIN, 0); $isLockAcquired = $locker->acquireSessionLevelLock( $dbConnection, @@ -131,7 +131,7 @@ public function testItCanTryAcquireLockInSameConnectionOnlyOnce(): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $isLockAcquired1 = $locker->acquireSessionLevelLock( $dbConnection, @@ -152,8 +152,8 @@ public function testItCanTryAcquireMultipleLocksInOneConnection(): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId1 = PostgresLockId::fromKeyValue('test1'); - $postgresLockId2 = PostgresLockId::fromKeyValue('test2'); + $postgresLockId1 = PostgresLockKey::create('test1'); + $postgresLockId2 = PostgresLockKey::create('test2'); $isLock1Acquired = $locker->acquireSessionLevelLock( $dbConnection, @@ -176,7 +176,7 @@ public function testItCannotAcquireSameLockInTwoConnections(): void $locker = $this->initLocker(); $dbConnection1 = $this->initPostgresPdoConnection(); $dbConnection2 = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $locker->acquireSessionLevelLock( $dbConnection1, $postgresLockId, @@ -198,7 +198,7 @@ public function testItCanReleaseLock( ): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, @@ -234,7 +234,7 @@ public function testItCanNotReleaseLockOfDifferentModes( ): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, @@ -270,7 +270,7 @@ public function testItCanReleaseLockTwiceIfAcquiredTwice(): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId, @@ -293,7 +293,7 @@ public function testItCanTryAcquireLockInSecondConnectionAfterRelease(): void $locker = $this->initLocker(); $dbConnection1 = $this->initPostgresPdoConnection(); $dbConnection2 = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $locker->acquireSessionLevelLock( $dbConnection1, $postgresLockId, @@ -318,7 +318,7 @@ public function testItCannotAcquireLockInSecondConnectionAfterOneReleaseTwiceLoc $locker = $this->initLocker(); $dbConnection1 = $this->initPostgresPdoConnection(); $dbConnection2 = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $locker->acquireSessionLevelLock( $dbConnection1, $postgresLockId, @@ -345,7 +345,7 @@ public function testItCannotReleaseLockIfNotAcquired(): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $isLockReleased = $locker->releaseSessionLevelLock($dbConnection, $postgresLockId); @@ -358,7 +358,7 @@ public function testItCannotReleaseLockIfAcquiredInOtherConnection(): void $locker = $this->initLocker(); $dbConnection1 = $this->initPostgresPdoConnection(); $dbConnection2 = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $locker->acquireSessionLevelLock( $dbConnection1, $postgresLockId, @@ -377,15 +377,15 @@ public function testItCanReleaseAllLocksInConnection(): void $dbConnection = $this->initPostgresPdoConnection(); $locker->acquireSessionLevelLock( $dbConnection, - PostgresLockId::fromKeyValue('test'), + PostgresLockKey::create('test'), ); $locker->acquireSessionLevelLock( $dbConnection, - PostgresLockId::fromKeyValue('test'), + PostgresLockKey::create('test'), ); $locker->acquireSessionLevelLock( $dbConnection, - PostgresLockId::fromKeyValue('test2'), + PostgresLockKey::create('test2'), ); $locker->releaseAllSessionLevelLocks($dbConnection); @@ -408,10 +408,10 @@ public function testItCanReleaseAllLocksInConnectionButKeepsOtherConnectionLocks $locker = $this->initLocker(); $dbConnection1 = $this->initPostgresPdoConnection(); $dbConnection2 = $this->initPostgresPdoConnection(); - $postgresLockId1 = PostgresLockId::fromKeyValue('test'); - $postgresLockId2 = PostgresLockId::fromKeyValue('test2'); - $postgresLockId3 = PostgresLockId::fromKeyValue('test3'); - $postgresLockId4 = PostgresLockId::fromKeyValue('test4'); + $postgresLockId1 = PostgresLockKey::create('test'); + $postgresLockId2 = PostgresLockKey::create('test2'); + $postgresLockId3 = PostgresLockKey::create('test3'); + $postgresLockId4 = PostgresLockKey::create('test4'); $locker->acquireSessionLevelLock( $dbConnection1, $postgresLockId1, @@ -445,7 +445,7 @@ public function testItCannotAcquireLockWithinTransactionNotInTransaction(): void $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $locker->acquireTransactionLevelLock( $dbConnection, @@ -458,7 +458,7 @@ public function testItCannotAcquireLockInSecondConnectionIfTakenWithinTransactio $locker = $this->initLocker(); $dbConnection1 = $this->initPostgresPdoConnection(); $dbConnection2 = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $dbConnection1->beginTransaction(); $locker->acquireSessionLevelLock( $dbConnection1, @@ -479,7 +479,7 @@ public function testItCanAutoReleaseLockAcquiredWithinTransactionOnCommit(): voi { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $dbConnection->beginTransaction(); $locker->acquireTransactionLevelLock( $dbConnection, @@ -496,7 +496,7 @@ public function testItCanAutoReleaseLockAcquiredWithinTransactionOnRollback(): v { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $dbConnection->beginTransaction(); $locker->acquireTransactionLevelLock( $dbConnection, @@ -513,7 +513,7 @@ public function testItCanAutoReleaseLockAcquiredWithinTransactionOnConnectionKil { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $dbConnection->beginTransaction(); $locker->acquireTransactionLevelLock( $dbConnection, @@ -529,7 +529,7 @@ public function testItCannotReleaseLockAcquiredWithinTransaction(): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId = PostgresLockId::fromKeyValue('test'); + $postgresLockId = PostgresLockKey::create('test'); $dbConnection->beginTransaction(); $locker->acquireTransactionLevelLock( $dbConnection, @@ -547,8 +547,8 @@ public function testItCannotReleaseAllLocksAcquiredWithinTransaction(): void { $locker = $this->initLocker(); $dbConnection = $this->initPostgresPdoConnection(); - $postgresLockId1 = PostgresLockId::fromKeyValue('test'); - $postgresLockId2 = PostgresLockId::fromKeyValue('test2'); + $postgresLockId1 = PostgresLockKey::create('test'); + $postgresLockId2 = PostgresLockKey::create('test2'); $locker->acquireSessionLevelLock( $dbConnection, $postgresLockId1, diff --git a/test/Unit/Postgres/PostgresLockIdTest.php b/test/Unit/Postgres/PostgresLockKeyTest.php similarity index 91% rename from test/Unit/Postgres/PostgresLockIdTest.php rename to test/Unit/Postgres/PostgresLockKeyTest.php index c24b7e4..4adb626 100644 --- a/test/Unit/Postgres/PostgresLockIdTest.php +++ b/test/Unit/Postgres/PostgresLockKeyTest.php @@ -13,11 +13,11 @@ namespace Cog\Test\DbLocker\Unit\Postgres; -use Cog\DbLocker\Postgres\PostgresLockId; +use Cog\DbLocker\Postgres\PostgresLockKey; use Cog\Test\DbLocker\Unit\AbstractUnitTestCase; use PHPUnit\Framework\Attributes\DataProvider; -final class PostgresLockIdTest extends AbstractUnitTestCase +final class PostgresLockKeyTest extends AbstractUnitTestCase { private const DB_INT32_VALUE_MIN = -2_147_483_648; private const DB_INT32_VALUE_MAX = 2_147_483_647; @@ -29,7 +29,7 @@ public function testItCanCreatePostgresLockIdFromKeyValue( int $expectedClassId, int $expectedObjectId, ): void { - $postgresLockId = PostgresLockId::fromKeyValue($key, $value); + $postgresLockId = PostgresLockKey::create($key, $value); $this->assertSame($expectedClassId, $postgresLockId->classId); $this->assertSame($expectedObjectId, $postgresLockId->objectId); @@ -58,7 +58,7 @@ public function testItCanCreatePostgresLockIdFromIntKeys( int $classId, int $objectId, ): void { - $lockId = PostgresLockId::fromIntKeys($classId, $objectId); + $lockId = PostgresLockKey::createFromInternalIds($classId, $objectId); $this->assertSame($classId, $lockId->classId); $this->assertSame($objectId, $lockId->objectId); @@ -95,7 +95,7 @@ public function testItCanNotCreatePostgresLockIdFromOutOfRangeIntKeys( $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage($expectedExceptionMessage); - $lockId = PostgresLockId::fromIntKeys($classId, $objectId); + $lockId = PostgresLockKey::createFromInternalIds($classId, $objectId); $this->assertSame($classId, $lockId->classId); $this->assertSame($objectId, $lockId->objectId);