Skip to content

Commit f9a67a8

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

File tree

5 files changed

+81
-35
lines changed

5 files changed

+81
-35
lines changed

src/Locker/PostgresAdvisoryLockModeEnum.php

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cog\DbLocker\Locker;
6+
7+
/**
8+
* PostgresAdvisoryLockTypeEnum defines the type of advisory lock acquisition.
9+
*
10+
* - NonBlocking: Attempt to acquire the lock without blocking (PG_TRY_ADVISORY_LOCK, PG_TRY_ADVISORY_XACT_LOCK).
11+
* - Blocking: Acquire the lock, blocking until it becomes available (PG_ADVISORY_LOCK, PG_ADVISORY_XACT_LOCK).
12+
*/
13+
enum PostgresAdvisoryLockTypeEnum
14+
{
15+
case NonBlocking;
16+
case Blocking;
17+
}

src/Locker/PostgresAdvisoryLocker.php

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,64 @@
2020
final class PostgresAdvisoryLocker
2121
{
2222
/**
23-
* Acquire an advisory lock with configurable scope and mode.
23+
* Acquire an advisory lock with configurable scope, mode and behavior.
2424
*/
2525
public function acquireLock(
2626
PDO $dbConnection,
2727
PostgresLockId $postgresLockId,
2828
PostgresAdvisoryLockScopeEnum $scope = PostgresAdvisoryLockScopeEnum::Transaction,
29-
PostgresAdvisoryLockModeEnum $mode = PostgresAdvisoryLockModeEnum::Try,
29+
PostgresAdvisoryLockTypeEnum $type = PostgresAdvisoryLockTypeEnum::NonBlocking,
30+
PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive,
3031
): bool {
3132
if ($scope === PostgresAdvisoryLockScopeEnum::Transaction && $dbConnection->inTransaction() === false) {
3233
throw new LogicException(
3334
"Transaction-level advisory lock `$postgresLockId->humanReadableValue` cannot be acquired outside of transaction",
3435
);
3536
}
3637

37-
$sql = match ([$scope, $mode]) {
38-
[PostgresAdvisoryLockScopeEnum::Transaction, PostgresAdvisoryLockModeEnum::Try] =>
39-
'SELECT PG_TRY_ADVISORY_XACT_LOCK(:class_id, :object_id); -- ' . $postgresLockId->humanReadableValue,
40-
[PostgresAdvisoryLockScopeEnum::Transaction, PostgresAdvisoryLockModeEnum::Block] =>
41-
'SELECT PG_ADVISORY_XACT_LOCK(:class_id, :object_id); -- ' . $postgresLockId->humanReadableValue,
42-
[PostgresAdvisoryLockScopeEnum::Session, PostgresAdvisoryLockModeEnum::Try] =>
43-
'SELECT PG_TRY_ADVISORY_LOCK(:class_id, :object_id); -- ' . $postgresLockId->humanReadableValue,
44-
[PostgresAdvisoryLockScopeEnum::Session, PostgresAdvisoryLockModeEnum::Block] =>
45-
'SELECT PG_ADVISORY_LOCK(:class_id, :object_id); -- ' . $postgresLockId->humanReadableValue,
38+
$sql = match ([$scope, $type, $mode]) {
39+
[
40+
PostgresAdvisoryLockScopeEnum::Transaction,
41+
PostgresAdvisoryLockTypeEnum::NonBlocking,
42+
PostgresLockModeEnum::Exclusive,
43+
] => 'SELECT PG_TRY_ADVISORY_XACT_LOCK(:class_id, :object_id);',
44+
[
45+
PostgresAdvisoryLockScopeEnum::Transaction,
46+
PostgresAdvisoryLockTypeEnum::Blocking,
47+
PostgresLockModeEnum::Exclusive,
48+
] => 'SELECT PG_ADVISORY_XACT_LOCK(:class_id, :object_id);',
49+
[
50+
PostgresAdvisoryLockScopeEnum::Transaction,
51+
PostgresAdvisoryLockTypeEnum::NonBlocking,
52+
PostgresLockModeEnum::Share,
53+
] => 'SELECT PG_TRY_ADVISORY_XACT_LOCK_SHARE(:class_id, :object_id);',
54+
[
55+
PostgresAdvisoryLockScopeEnum::Transaction,
56+
PostgresAdvisoryLockTypeEnum::Blocking,
57+
PostgresLockModeEnum::Share,
58+
] => 'SELECT PG_ADVISORY_XACT_LOCK_SHARE(:class_id, :object_id);',
59+
[
60+
PostgresAdvisoryLockScopeEnum::Session,
61+
PostgresAdvisoryLockTypeEnum::NonBlocking,
62+
PostgresLockModeEnum::Exclusive,
63+
] => 'SELECT PG_TRY_ADVISORY_LOCK(:class_id, :object_id);',
64+
[
65+
PostgresAdvisoryLockScopeEnum::Session,
66+
PostgresAdvisoryLockTypeEnum::Blocking,
67+
PostgresLockModeEnum::Exclusive,
68+
] => 'SELECT PG_ADVISORY_LOCK(:class_id, :object_id);',
69+
[
70+
PostgresAdvisoryLockScopeEnum::Session,
71+
PostgresAdvisoryLockTypeEnum::NonBlocking,
72+
PostgresLockModeEnum::Share,
73+
] => 'SELECT PG_TRY_ADVISORY_LOCK_SHARE(:class_id, :object_id);',
74+
[
75+
PostgresAdvisoryLockScopeEnum::Session,
76+
PostgresAdvisoryLockTypeEnum::Blocking,
77+
PostgresLockModeEnum::Share,
78+
] => 'SELECT PG_ADVISORY_LOCK_SHARE(:class_id, :object_id);',
4679
};
80+
$sql .= " -- $postgresLockId->humanReadableValue";
4781

4882
$statement = $dbConnection->prepare($sql);
4983
$statement->execute(
@@ -57,7 +91,7 @@ public function acquireLock(
5791
}
5892

5993
/**
60-
* Release session-level lock.
94+
* Release session level advisory lock.
6195
*/
6296
public function releaseLock(
6397
PDO $dbConnection,
@@ -84,7 +118,7 @@ public function releaseLock(
84118
}
85119

86120
/**
87-
* Release all session-level locks.
121+
* Release all session level advisory locks held by the current session.
88122
*/
89123
public function releaseAllLocks(
90124
PDO $dbConnection,

src/Locker/PostgresLockModeEnum.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cog\DbLocker\Locker;
6+
7+
/**
8+
* PostgresLockModeEnum defines the access mode of advisory lock acquisition.
9+
*/
10+
enum PostgresLockModeEnum: string
11+
{
12+
case Exclusive = 'ExclusiveLock';
13+
case Share = 'ShareLock';
14+
}

test/Integration/AbstractIntegrationTestCase.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,13 @@
1313

1414
namespace Cog\Test\DbLocker\Integration;
1515

16+
use Cog\DbLocker\Locker\PostgresLockModeEnum;
1617
use Cog\DbLocker\LockId\PostgresLockId;
1718
use PDO;
1819
use PHPUnit\Framework\TestCase;
1920

2021
abstract class AbstractIntegrationTestCase extends TestCase
2122
{
22-
private const MODE_EXCLUSIVE = 'ExclusiveLock';
23-
private const MODE_SHARE = 'ShareLock';
24-
2523
protected function tearDown(): void
2624
{
2725
$this->closeAllPostgresPdoConnections();
@@ -110,7 +108,7 @@ private function findPostgresAdvisoryLockInConnection(
110108
'lock_object_id' => $postgresLockId->objectId,
111109
'lock_object_subid' => 2, // Using two keyed locks
112110
'connection_pid' => $dbConnection->pgsqlGetPid(),
113-
'mode' => self::MODE_EXCLUSIVE,
111+
'mode' => PostgresLockModeEnum::Exclusive->value,
114112
],
115113
);
116114

@@ -137,7 +135,7 @@ private function findAllPostgresAdvisoryLocks(): array
137135
);
138136
$statement->execute(
139137
[
140-
'mode' => self::MODE_EXCLUSIVE,
138+
'mode' => PostgresLockModeEnum::Exclusive->value,
141139
],
142140
);
143141

0 commit comments

Comments
 (0)