2020final 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