Skip to content

Commit 788ef64

Browse files
committed
Rewrite logic to two keyed lock
1 parent e74100d commit 788ef64

File tree

3 files changed

+91
-16
lines changed

3 files changed

+91
-16
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ $postgresLocker = new \Cog\DbLocker\Locker\PostgresAdvisoryLocker();
3636
$postgresLockId = \Cog\DbLocker\LockId\PostgresLockId::fromKeyValue('user', '4');
3737

3838
$dbConnection->beginTransaction();
39-
$isLockAcquired = $postgresLocker->acquireLockWithinTransaction(
39+
$isLockAcquired = $postgresLocker->acquireLock(
4040
$dbConnection,
4141
$postgresLockId,
42+
\Cog\DbLocker\Locker\PostgresAdvisoryLockScopeEnum::Transaction,
4243
);
4344
if ($isLockAcquired) {
4445
// Execute logic if lock was successful
@@ -59,13 +60,14 @@ $postgresLockId = \Cog\DbLocker\LockId\PostgresLockId::fromKeyValue('user', '4')
5960
$isLockAcquired = $postgresLocker->acquireLock(
6061
$dbConnection,
6162
$postgresLockId,
63+
\Cog\DbLocker\Locker\PostgresAdvisoryLockScopeEnum::Session,
6264
);
6365
if ($isLockAcquired) {
6466
// Execute logic if lock was successful
6567
} else {
6668
// Execute logic if lock acquisition has been failed
6769
}
68-
$postgresLocker->releaseLockWithinSession($dbConnection, $postgresLockId);
70+
$postgresLocker->releaseLock($dbConnection, $postgresLockId);
6971
```
7072

7173
## Changelog

src/Locker/PostgresAdvisoryLocker.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,15 @@ public function acquireLock(
5959
/**
6060
* Release session-level lock.
6161
*/
62-
public function releaseLockWithinSession(
62+
public function releaseLock(
6363
PDO $dbConnection,
6464
PostgresLockId $postgresLockId,
65+
PostgresAdvisoryLockScopeEnum $scope = PostgresAdvisoryLockScopeEnum::Session,
6566
): bool {
67+
if ($scope === PostgresAdvisoryLockScopeEnum::Transaction) {
68+
throw new \InvalidArgumentException('Transaction-level advisory lock cannot be released');
69+
}
70+
6671
$statement = $dbConnection->prepare(
6772
<<<SQL
6873
SELECT PG_ADVISORY_UNLOCK(:class_id, :object_id); -- $postgresLockId->humanReadableValue
@@ -81,9 +86,14 @@ public function releaseLockWithinSession(
8186
/**
8287
* Release all session-level locks.
8388
*/
84-
public function releaseAllLocksWithinSession(
89+
public function releaseAllLocks(
8590
PDO $dbConnection,
91+
PostgresAdvisoryLockScopeEnum $scope = PostgresAdvisoryLockScopeEnum::Session,
8692
): void {
93+
if ($scope === PostgresAdvisoryLockScopeEnum::Transaction) {
94+
throw new \InvalidArgumentException('Transaction-level advisory lock cannot be released');
95+
}
96+
8797
$statement = $dbConnection->prepare(
8898
<<<'SQL'
8999
SELECT PG_ADVISORY_UNLOCK_ALL();

test/Integration/Locker/PostgresAdvisoryLockerTest.php

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ public function testItCanReleaseLock(): void
164164
PostgresAdvisoryLockScopeEnum::Session,
165165
);
166166

167-
$isLockReleased = $locker->releaseLockWithinSession($dbConnection, $postgresLockId);
167+
$isLockReleased = $locker->releaseLock($dbConnection, $postgresLockId);
168168

169169
$this->assertTrue($isLockReleased);
170170
$this->assertPgAdvisoryLocksCount(0);
@@ -186,8 +186,8 @@ public function testItCanReleaseLockTwiceIfAcquiredTwice(): void
186186
PostgresAdvisoryLockScopeEnum::Session,
187187
);
188188

189-
$isLockReleased1 = $locker->releaseLockWithinSession($dbConnection, $postgresLockId);
190-
$isLockReleased2 = $locker->releaseLockWithinSession($dbConnection, $postgresLockId);
189+
$isLockReleased1 = $locker->releaseLock($dbConnection, $postgresLockId);
190+
$isLockReleased2 = $locker->releaseLock($dbConnection, $postgresLockId);
191191

192192
$this->assertTrue($isLockReleased1);
193193
$this->assertTrue($isLockReleased2);
@@ -205,7 +205,7 @@ public function testItCanTryAcquireLockInSecondConnectionAfterRelease(): void
205205
$postgresLockId,
206206
PostgresAdvisoryLockScopeEnum::Session,
207207
);
208-
$locker->releaseLockWithinSession(
208+
$locker->releaseLock(
209209
$dbConnection1,
210210
$postgresLockId,
211211
);
@@ -238,7 +238,7 @@ public function testItCannotAcquireLockInSecondConnectionAfterOneReleaseTwiceLoc
238238
PostgresAdvisoryLockScopeEnum::Session,
239239
);
240240

241-
$isLockReleased = $locker->releaseLockWithinSession($dbConnection1, $postgresLockId);
241+
$isLockReleased = $locker->releaseLock($dbConnection1, $postgresLockId);
242242
$isLockAcquired = $locker->acquireLock(
243243
$dbConnection2,
244244
$postgresLockId,
@@ -258,7 +258,7 @@ public function testItCannotReleaseLockIfNotAcquired(): void
258258
$dbConnection = $this->initPostgresPdoConnection();
259259
$postgresLockId = PostgresLockId::fromKeyValue('test');
260260

261-
$isLockReleased = $locker->releaseLockWithinSession($dbConnection, $postgresLockId);
261+
$isLockReleased = $locker->releaseLock($dbConnection, $postgresLockId);
262262

263263
$this->assertFalse($isLockReleased);
264264
$this->assertPgAdvisoryLocksCount(0);
@@ -276,7 +276,7 @@ public function testItCannotReleaseLockIfAcquiredInOtherConnection(): void
276276
PostgresAdvisoryLockScopeEnum::Session,
277277
);
278278

279-
$isLockReleased = $locker->releaseLockWithinSession($dbConnection2, $postgresLockId);
279+
$isLockReleased = $locker->releaseLock($dbConnection2, $postgresLockId);
280280

281281
$this->assertFalse($isLockReleased);
282282
$this->assertPgAdvisoryLocksCount(1);
@@ -298,7 +298,7 @@ public function testItCanReleaseAllLocksInConnection(): void
298298
PostgresAdvisoryLockScopeEnum::Session,
299299
);
300300

301-
$locker->releaseAllLocksWithinSession($dbConnection);
301+
$locker->releaseAllLocks($dbConnection);
302302

303303
$this->assertPgAdvisoryLocksCount(0);
304304
}
@@ -308,7 +308,7 @@ public function testItCanReleaseAllLocksInConnectionIfNoLocksWereAcquired(): voi
308308
$locker = $this->initLocker();
309309
$dbConnection = $this->initPostgresPdoConnection();
310310

311-
$locker->releaseAllLocksWithinSession($dbConnection);
311+
$locker->releaseAllLocks($dbConnection);
312312

313313
$this->assertPgAdvisoryLocksCount(0);
314314
}
@@ -343,7 +343,7 @@ public function testItCanReleaseAllLocksInConnectionButKeepsOtherLocks(): void
343343
PostgresAdvisoryLockScopeEnum::Session,
344344
);
345345

346-
$locker->releaseAllLocksWithinSession($dbConnection1);
346+
$locker->releaseAllLocks($dbConnection1);
347347

348348
$this->assertPgAdvisoryLocksCount(2);
349349
$this->assertPgAdvisoryLockExistsInConnection($dbConnection2, $postgresLockId3);
@@ -475,7 +475,7 @@ public function testItCannotReleaseLockAcquiredWithinTransaction(): void
475475
PostgresAdvisoryLockScopeEnum::Transaction,
476476
);
477477

478-
$isLockReleased = $locker->releaseLockWithinSession($dbConnection, $postgresLockId);
478+
$isLockReleased = $locker->releaseLock($dbConnection, $postgresLockId);
479479

480480
$this->assertFalse($isLockReleased);
481481
$this->assertPgAdvisoryLocksCount(1);
@@ -500,13 +500,76 @@ public function testItCannotReleaseAllLocksAcquiredWithinTransaction(): void
500500
PostgresAdvisoryLockScopeEnum::Transaction,
501501
);
502502

503-
$locker->releaseAllLocksWithinSession($dbConnection);
503+
$locker->releaseAllLocks($dbConnection);
504504

505505
$this->assertPgAdvisoryLocksCount(1);
506506
$this->assertPgAdvisoryLockMissingInConnection($dbConnection, $postgresLockId1);
507507
$this->assertPgAdvisoryLockExistsInConnection($dbConnection, $postgresLockId2);
508508
}
509509

510+
public function testItCannotReleaseAllLocksWithTransactionScope(): void
511+
{
512+
$locker = $this->initLocker();
513+
$dbConnection = $this->initPostgresPdoConnection();
514+
$postgresLockId1 = PostgresLockId::fromKeyValue('test');
515+
$postgresLockId2 = PostgresLockId::fromKeyValue('test2');
516+
$locker->acquireLock(
517+
$dbConnection,
518+
$postgresLockId1,
519+
PostgresAdvisoryLockScopeEnum::Session,
520+
);
521+
$dbConnection->beginTransaction();
522+
$locker->acquireLock(
523+
$dbConnection,
524+
$postgresLockId2,
525+
PostgresAdvisoryLockScopeEnum::Transaction,
526+
);
527+
528+
try {
529+
$locker->releaseAllLocks(
530+
$dbConnection,
531+
PostgresAdvisoryLockScopeEnum::Transaction,
532+
);
533+
} catch (\InvalidArgumentException $exception) {
534+
$this->assertSame(
535+
'Transaction-level advisory lock cannot be released',
536+
$exception->getMessage(),
537+
);
538+
}
539+
}
540+
541+
public function testItCannotReleaseLocksWithTransactionScope(): void
542+
{
543+
$locker = $this->initLocker();
544+
$dbConnection = $this->initPostgresPdoConnection();
545+
$postgresLockId1 = PostgresLockId::fromKeyValue('test');
546+
$postgresLockId2 = PostgresLockId::fromKeyValue('test2');
547+
$locker->acquireLock(
548+
$dbConnection,
549+
$postgresLockId1,
550+
PostgresAdvisoryLockScopeEnum::Session,
551+
);
552+
$dbConnection->beginTransaction();
553+
$locker->acquireLock(
554+
$dbConnection,
555+
$postgresLockId2,
556+
PostgresAdvisoryLockScopeEnum::Transaction,
557+
);
558+
559+
try {
560+
$locker->releaseLock(
561+
$dbConnection,
562+
$postgresLockId2,
563+
PostgresAdvisoryLockScopeEnum::Transaction,
564+
);
565+
} catch (\InvalidArgumentException $exception) {
566+
$this->assertSame(
567+
'Transaction-level advisory lock cannot be released',
568+
$exception->getMessage(),
569+
);
570+
}
571+
}
572+
510573
private function initLocker(): PostgresAdvisoryLocker
511574
{
512575
return new PostgresAdvisoryLocker();

0 commit comments

Comments
 (0)