Skip to content

Commit acd390d

Browse files
committed
Rewrite locker API
1 parent dbb6678 commit acd390d

File tree

6 files changed

+165
-204
lines changed

6 files changed

+165
-204
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ $postgresLocker = new \Cog\DbLocker\Locker\PostgresAdvisoryLocker();
3838
$postgresLockId = \Cog\DbLocker\LockId\PostgresLockId::fromKeyValue('user', '4');
3939

4040
$dbConnection->beginTransaction();
41-
$isLockAcquired = $postgresLocker->acquireLock(
41+
$isLockAcquired = $postgresLocker->acquireTransactionLevelLock(
4242
$dbConnection,
4343
$postgresLockId,
44-
\Cog\DbLocker\Locker\PostgresAdvisoryLockScopeEnum::Transaction,
44+
\Cog\DbLocker\Locker\PostgresAdvisoryLockLevelEnum::Transaction,
4545
\Cog\DbLocker\Locker\PostgresAdvisoryLockTypeEnum::NonBlocking,
4646
\Cog\DbLocker\Locker\PostgresLockModeEnum::Exclusive,
4747
);
@@ -61,10 +61,10 @@ $dbConnection = new PDO($dsn, $username, $password);
6161
$postgresLocker = new \Cog\DbLocker\Locker\PostgresAdvisoryLocker();
6262
$postgresLockId = \Cog\DbLocker\LockId\PostgresLockId::fromKeyValue('user', '4');
6363

64-
$isLockAcquired = $postgresLocker->acquireLock(
64+
$isLockAcquired = $postgresLocker->acquireSessionLevelLock(
6565
$dbConnection,
6666
$postgresLockId,
67-
\Cog\DbLocker\Locker\PostgresAdvisoryLockScopeEnum::Session,
67+
\Cog\DbLocker\Locker\PostgresAdvisoryLockLevelEnum::Session,
6868
\Cog\DbLocker\Locker\PostgresAdvisoryLockTypeEnum::NonBlocking,
6969
\Cog\DbLocker\Locker\PostgresLockModeEnum::Exclusive,
7070
);
@@ -73,7 +73,7 @@ if ($isLockAcquired) {
7373
} else {
7474
// Execute logic if lock acquisition has been failed
7575
}
76-
$postgresLocker->releaseLock($dbConnection, $postgresLockId);
76+
$postgresLocker->releaseSessionLevelLock($dbConnection, $postgresLockId);
7777
```
7878

7979
## Changelog

src/LockId/LockId.php

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/Locker/PostgresAdvisoryLockScopeEnum.php renamed to src/Locker/PostgresAdvisoryLockLevelEnum.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace Cog\DbLocker\Locker;
66

77
/**
8-
* PostgresAdvisoryLockScopeEnum defines the scope of advisory lock acquisition.
8+
* PostgresAdvisoryLockLevelEnum defines the level of advisory lock acquisition.
99
*
1010
* - Session. Session-level advisory lock (without _XACT_):
1111
* - PG_ADVISORY_LOCK
@@ -18,7 +18,7 @@
1818
* - PG_TRY_ADVISORY_XACT_LOCK
1919
* - PG_TRY_ADVISORY_XACT_LOCK_SHARED
2020
*/
21-
enum PostgresAdvisoryLockScopeEnum
21+
enum PostgresAdvisoryLockLevelEnum
2222
{
2323
case Session;
2424
case Transaction;

src/Locker/PostgresAdvisoryLocker.php

Lines changed: 97 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -20,59 +20,143 @@
2020
final class PostgresAdvisoryLocker
2121
{
2222
/**
23-
* Acquire an advisory lock with configurable scope, mode and behavior.
23+
* Acquire a transaction-level advisory lock with a configurable acquisition type and mode.
2424
*/
25-
public function acquireLock(
25+
public function acquireTransactionLevelLock(
2626
PDO $dbConnection,
2727
PostgresLockId $postgresLockId,
28-
PostgresAdvisoryLockScopeEnum $scope = PostgresAdvisoryLockScopeEnum::Transaction,
2928
PostgresAdvisoryLockTypeEnum $type = PostgresAdvisoryLockTypeEnum::NonBlocking,
3029
PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive,
3130
): bool {
32-
if ($scope === PostgresAdvisoryLockScopeEnum::Transaction && $dbConnection->inTransaction() === false) {
31+
return $this->acquireLock(
32+
$dbConnection,
33+
$postgresLockId,
34+
PostgresAdvisoryLockLevelEnum::Transaction,
35+
$type,
36+
$mode,
37+
);
38+
}
39+
40+
/**
41+
* Acquire a session-level advisory lock with a configurable acquisition type and mode.
42+
*
43+
* TODO: Write that transaction-level is recommended.
44+
*/
45+
public function acquireSessionLevelLock(
46+
PDO $dbConnection,
47+
PostgresLockId $postgresLockId,
48+
PostgresAdvisoryLockTypeEnum $type = PostgresAdvisoryLockTypeEnum::NonBlocking,
49+
PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive,
50+
): bool {
51+
return $this->acquireLock(
52+
$dbConnection,
53+
$postgresLockId,
54+
PostgresAdvisoryLockLevelEnum::Session,
55+
$type,
56+
$mode,
57+
);
58+
}
59+
60+
/**
61+
* Release session level advisory lock.
62+
*/
63+
public function releaseSessionLevelLock(
64+
PDO $dbConnection,
65+
PostgresLockId $postgresLockId,
66+
PostgresAdvisoryLockLevelEnum $level = PostgresAdvisoryLockLevelEnum::Session,
67+
PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive,
68+
): bool {
69+
if ($level === PostgresAdvisoryLockLevelEnum::Transaction) {
70+
throw new \InvalidArgumentException('Transaction-level advisory lock cannot be released');
71+
}
72+
73+
$sql = match ($mode) {
74+
PostgresLockModeEnum::Exclusive => 'SELECT PG_ADVISORY_UNLOCK(:class_id, :object_id);',
75+
PostgresLockModeEnum::Share => 'SELECT PG_ADVISORY_UNLOCK_SHARED(:class_id, :object_id);',
76+
};
77+
$sql .= " -- $postgresLockId->humanReadableValue";
78+
79+
$statement = $dbConnection->prepare($sql);
80+
$statement->execute(
81+
[
82+
'class_id' => $postgresLockId->classId,
83+
'object_id' => $postgresLockId->objectId,
84+
],
85+
);
86+
87+
return $statement->fetchColumn(0);
88+
}
89+
90+
/**
91+
* Release all session level advisory locks held by the current session.
92+
*/
93+
public function releaseAllSessionLevelLocks(
94+
PDO $dbConnection,
95+
PostgresAdvisoryLockLevelEnum $level = PostgresAdvisoryLockLevelEnum::Session,
96+
): void {
97+
if ($level === PostgresAdvisoryLockLevelEnum::Transaction) {
98+
throw new \InvalidArgumentException('Transaction-level advisory lock cannot be released');
99+
}
100+
101+
$statement = $dbConnection->prepare(
102+
<<<'SQL'
103+
SELECT PG_ADVISORY_UNLOCK_ALL();
104+
SQL,
105+
);
106+
$statement->execute();
107+
}
108+
109+
private function acquireLock(
110+
PDO $dbConnection,
111+
PostgresLockId $postgresLockId,
112+
PostgresAdvisoryLockLevelEnum $level,
113+
PostgresAdvisoryLockTypeEnum $type = PostgresAdvisoryLockTypeEnum::NonBlocking,
114+
PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive,
115+
): bool {
116+
if ($level === PostgresAdvisoryLockLevelEnum::Transaction && $dbConnection->inTransaction() === false) {
33117
throw new LogicException(
34118
"Transaction-level advisory lock `$postgresLockId->humanReadableValue` cannot be acquired outside of transaction",
35119
);
36120
}
37121

38-
$sql = match ([$scope, $type, $mode]) {
122+
$sql = match ([$level, $type, $mode]) {
39123
[
40-
PostgresAdvisoryLockScopeEnum::Transaction,
124+
PostgresAdvisoryLockLevelEnum::Transaction,
41125
PostgresAdvisoryLockTypeEnum::NonBlocking,
42126
PostgresLockModeEnum::Exclusive,
43127
] => 'SELECT PG_TRY_ADVISORY_XACT_LOCK(:class_id, :object_id);',
44128
[
45-
PostgresAdvisoryLockScopeEnum::Transaction,
129+
PostgresAdvisoryLockLevelEnum::Transaction,
46130
PostgresAdvisoryLockTypeEnum::Blocking,
47131
PostgresLockModeEnum::Exclusive,
48132
] => 'SELECT PG_ADVISORY_XACT_LOCK(:class_id, :object_id);',
49133
[
50-
PostgresAdvisoryLockScopeEnum::Transaction,
134+
PostgresAdvisoryLockLevelEnum::Transaction,
51135
PostgresAdvisoryLockTypeEnum::NonBlocking,
52136
PostgresLockModeEnum::Share,
53137
] => 'SELECT PG_TRY_ADVISORY_XACT_LOCK_SHARED(:class_id, :object_id);',
54138
[
55-
PostgresAdvisoryLockScopeEnum::Transaction,
139+
PostgresAdvisoryLockLevelEnum::Transaction,
56140
PostgresAdvisoryLockTypeEnum::Blocking,
57141
PostgresLockModeEnum::Share,
58142
] => 'SELECT PG_ADVISORY_XACT_LOCK_SHARED(:class_id, :object_id);',
59143
[
60-
PostgresAdvisoryLockScopeEnum::Session,
144+
PostgresAdvisoryLockLevelEnum::Session,
61145
PostgresAdvisoryLockTypeEnum::NonBlocking,
62146
PostgresLockModeEnum::Exclusive,
63147
] => 'SELECT PG_TRY_ADVISORY_LOCK(:class_id, :object_id);',
64148
[
65-
PostgresAdvisoryLockScopeEnum::Session,
149+
PostgresAdvisoryLockLevelEnum::Session,
66150
PostgresAdvisoryLockTypeEnum::Blocking,
67151
PostgresLockModeEnum::Exclusive,
68152
] => 'SELECT PG_ADVISORY_LOCK(:class_id, :object_id);',
69153
[
70-
PostgresAdvisoryLockScopeEnum::Session,
154+
PostgresAdvisoryLockLevelEnum::Session,
71155
PostgresAdvisoryLockTypeEnum::NonBlocking,
72156
PostgresLockModeEnum::Share,
73157
] => 'SELECT PG_TRY_ADVISORY_LOCK_SHARED(:class_id, :object_id);',
74158
[
75-
PostgresAdvisoryLockScopeEnum::Session,
159+
PostgresAdvisoryLockLevelEnum::Session,
76160
PostgresAdvisoryLockTypeEnum::Blocking,
77161
PostgresLockModeEnum::Share,
78162
] => 'SELECT PG_ADVISORY_LOCK_SHARED(:class_id, :object_id);',
@@ -89,53 +173,4 @@ public function acquireLock(
89173

90174
return $statement->fetchColumn(0);
91175
}
92-
93-
/**
94-
* Release session level advisory lock.
95-
*/
96-
public function releaseLock(
97-
PDO $dbConnection,
98-
PostgresLockId $postgresLockId,
99-
PostgresAdvisoryLockScopeEnum $scope = PostgresAdvisoryLockScopeEnum::Session,
100-
PostgresLockModeEnum $mode = PostgresLockModeEnum::Exclusive,
101-
): bool {
102-
if ($scope === PostgresAdvisoryLockScopeEnum::Transaction) {
103-
throw new \InvalidArgumentException('Transaction-level advisory lock cannot be released');
104-
}
105-
106-
$sql = match ($mode) {
107-
PostgresLockModeEnum::Exclusive => 'SELECT PG_ADVISORY_UNLOCK(:class_id, :object_id);',
108-
PostgresLockModeEnum::Share => 'SELECT PG_ADVISORY_UNLOCK_SHARED(:class_id, :object_id);',
109-
};
110-
$sql .= " -- $postgresLockId->humanReadableValue";
111-
112-
$statement = $dbConnection->prepare($sql);
113-
$statement->execute(
114-
[
115-
'class_id' => $postgresLockId->classId,
116-
'object_id' => $postgresLockId->objectId,
117-
],
118-
);
119-
120-
return $statement->fetchColumn(0);
121-
}
122-
123-
/**
124-
* Release all session level advisory locks held by the current session.
125-
*/
126-
public function releaseAllLocks(
127-
PDO $dbConnection,
128-
PostgresAdvisoryLockScopeEnum $scope = PostgresAdvisoryLockScopeEnum::Session,
129-
): void {
130-
if ($scope === PostgresAdvisoryLockScopeEnum::Transaction) {
131-
throw new \InvalidArgumentException('Transaction-level advisory lock cannot be released');
132-
}
133-
134-
$statement = $dbConnection->prepare(
135-
<<<'SQL'
136-
SELECT PG_ADVISORY_UNLOCK_ALL();
137-
SQL,
138-
);
139-
$statement->execute();
140-
}
141176
}

0 commit comments

Comments
 (0)