1
1
** [ Requirements] ( #requirements ) ** |
2
2
** [ Installation] ( #installation ) ** |
3
3
** [ Usage] ( #usage ) ** |
4
+ ** [ Implementations] ( #implementations ) ** |
4
5
** [ Authors] ( #authors ) ** |
5
6
** [ License] ( #license ) **
6
7
@@ -51,7 +52,7 @@ This library uses the namespace `Malkusch\Lock`.
51
52
52
53
The [ ` Malkusch\Lock\Mutex\Mutex ` ] [ 5 ] interface provides the base API for this library.
53
54
54
- #### Mutex::synchronized()
55
+ ### Mutex::synchronized()
55
56
56
57
[ ` Malkusch\Lock\Mutex\Mutex::synchronized() ` ] [ 6 ] executes code exclusively. This
57
58
method guarantees that the code is only executed by one process at once. Other
@@ -65,10 +66,7 @@ return value `false` or `null` should be seen as a failed action.
65
66
Example:
66
67
67
68
``` php
68
- $newBalance = $mutex->synchronized(function () use (
69
- $bankAccount,
70
- $amount
71
- ): int {
69
+ $newBalance = $mutex->synchronized(static function () use ($bankAccount, $amount) {
72
70
$balance = $bankAccount->getBalance();
73
71
$balance -= $amount;
74
72
if ($balance < 0) {
@@ -80,7 +78,7 @@ $newBalance = $mutex->synchronized(function () use (
80
78
});
81
79
```
82
80
83
- #### Mutex::check()
81
+ ### Mutex::check()
84
82
85
83
[ ` Malkusch\Lock\Mutex\Mutex::check() ` ] [ 7 ] sets a callable, which will be
86
84
executed when [ ` Malkusch\Lock\Util\DoubleCheckedLocking::then() ` ] [ 8 ] is called,
@@ -108,24 +106,24 @@ this return value will not be checked by the library.
108
106
Example:
109
107
110
108
``` php
111
- $newBalance = $mutex->check(function () use ($bankAccount, $amount): bool {
109
+ $newBalance = $mutex->check(static function () use ($bankAccount, $amount): bool {
112
110
return $bankAccount->getBalance() >= $amount;
113
- })->then(function () use ($bankAccount, $amount): int {
111
+ })->then(static function () use ($bankAccount, $amount) {
114
112
$balance = $bankAccount->getBalance();
115
113
$balance -= $amount;
116
114
$bankAccount->setBalance($balance);
117
115
118
116
return $balance;
119
117
});
120
118
121
- if ($newBalance === false ) {
119
+ if (! $newBalance) {
122
120
if ($balance < 0) {
123
121
throw new \DomainException('You have no credit');
124
122
}
125
123
}
126
124
```
127
125
128
- #### Extracting code result after lock release exception
126
+ ### Extracting code result after lock release exception
129
127
130
128
Mutex implementations based on [ ` Malkush\Lock\Mutex\AbstractLockMutex ` ] [ 10 ] will throw
131
129
[ ` Malkusch\Lock\Exception\LockReleaseException ` ] [ 11 ] in case of lock release
@@ -136,8 +134,8 @@ In order to read the code result (or an exception thrown there),
136
134
Example:
137
135
``` php
138
136
try {
139
- // or $mutex->check(...)
140
- $result = $mutex->synchronized(function () {
137
+ // OR $mutex->check(...)
138
+ $result = $mutex->synchronized(static function () {
141
139
if (someCondition()) {
142
140
throw new \DomainException();
143
141
}
@@ -149,7 +147,7 @@ try {
149
147
$codeException = $unlockException->getCodeException();
150
148
// do something with the code exception
151
149
} else {
152
- $code_result = $unlockException->getCodeResult();
150
+ $codeResult = $unlockException->getCodeResult();
153
151
// do something with the code result
154
152
}
155
153
@@ -158,7 +156,7 @@ try {
158
156
}
159
157
```
160
158
161
- ### Implementations
159
+ ## Implementations
162
160
163
161
You can choose from one of the provided [ ` Malkusch\Lock\Mutex\Mutex ` ] ( #mutex ) interface
164
162
implementations or create/extend your own implementation.
@@ -168,30 +166,23 @@ implementations or create/extend your own implementation.
168
166
- [ ` RedisMutex ` ] ( #redismutex )
169
167
- [ ` SemaphoreMutex ` ] ( #semaphoremutex )
170
168
- [ ` MySQLMutex ` ] ( #mysqlmutex )
171
- - [ ` PostgreSQLMutex ` ] ( #PostgreSQLMutex )
169
+ - [ ` PostgreSQLMutex ` ] ( #postgresqlmutex )
170
+ - [ ` DistributedMutex ` ] ( #distributedmutex )
172
171
173
- #### FlockMutex
172
+ ### FlockMutex
174
173
175
174
The ** FlockMutex** is a lock implementation based on
176
175
[ ` flock() ` ] ( https://php.net/manual/en/function.flock.php ) .
177
176
178
177
Example:
179
178
``` php
180
179
$mutex = new FlockMutex(fopen(__FILE__, 'r'));
181
- $mutex->synchronized(function () use ($bankAccount, $amount) {
182
- $balance = $bankAccount->getBalance();
183
- $balance -= $amount;
184
- if ($balance < 0) {
185
- throw new \DomainException('You have no credit');
186
- }
187
- $bankAccount->setBalance($balance);
188
- });
189
180
```
190
181
191
182
Timeouts are supported as an optional second argument. This uses the ` ext-pcntl `
192
183
extension if possible or busy waiting if not.
193
184
194
- #### MemcachedMutex
185
+ ### MemcachedMutex
195
186
196
187
The ** MemcachedMutex** is a spinlock implementation which uses the
197
188
[ ` Memcached ` extension] ( https://php.net/manual/en/book.memcached.php ) .
@@ -202,22 +193,13 @@ $memcached = new \Memcached();
202
193
$memcached->addServer('localhost', 11211);
203
194
204
195
$mutex = new MemcachedMutex('balance', $memcached);
205
- $mutex->synchronized(function () use ($bankAccount, $amount) {
206
- $balance = $bankAccount->getBalance();
207
- $balance -= $amount;
208
- if ($balance < 0) {
209
- throw new \DomainException('You have no credit');
210
- }
211
- $bankAccount->setBalance($balance);
212
- });
213
196
```
214
197
215
- #### RedisMutex
198
+ ### RedisMutex
216
199
217
- The ** RedisMutex** is the distributed lock implementation of
218
- [ RedLock] ( https://redis.io/topics/distlock#the-redlock-algorithm ) which supports the
200
+ The ** RedisMutex** is a lock implementation which supports the
219
201
[ ` phpredis ` extension] ( https://github.com/phpredis/phpredis )
220
- or [ ` Predis ` API] ( https://github.com/nrk/predis ) .
202
+ or [ ` Predis ` API] ( https://github.com/nrk/predis ) clients .
221
203
222
204
Both Redis and Valkey servers are supported.
223
205
@@ -230,18 +212,10 @@ $redis = new \Redis();
230
212
$redis->connect('localhost');
231
213
// OR $redis = new \Predis\Client('redis://localhost');
232
214
233
- $mutex = new RedisMutex([$redis], 'balance');
234
- $mutex->synchronized(function () use ($bankAccount, $amount) {
235
- $balance = $bankAccount->getBalance();
236
- $balance -= $amount;
237
- if ($balance < 0) {
238
- throw new \DomainException('You have no credit');
239
- }
240
- $bankAccount->setBalance($balance);
241
- });
215
+ $mutex = new RedisMutex($redis, 'balance');
242
216
```
243
217
244
- #### SemaphoreMutex
218
+ ### SemaphoreMutex
245
219
246
220
The ** SemaphoreMutex** is a lock implementation based on
247
221
[ Semaphore] ( https://php.net/manual/en/ref.sem.php ) .
@@ -250,17 +224,9 @@ Example:
250
224
``` php
251
225
$semaphore = sem_get(ftok(__FILE__, 'a'));
252
226
$mutex = new SemaphoreMutex($semaphore);
253
- $mutex->synchronized(function () use ($bankAccount, $amount) {
254
- $balance = $bankAccount->getBalance();
255
- $balance -= $amount;
256
- if ($balance < 0) {
257
- throw new \DomainException('You have no credit');
258
- }
259
- $bankAccount->setBalance($balance);
260
- });
261
227
```
262
228
263
- #### MySQLMutex
229
+ ### MySQLMutex
264
230
265
231
The ** MySQLMutex** uses MySQL's
266
232
[ ` GET_LOCK ` ] ( https://dev.mysql.com/doc/refman/9.0/en/locking-functions.html#function_get-lock )
@@ -280,19 +246,10 @@ you to namespace your locks like `dbname.lockname`.
280
246
281
247
``` php
282
248
$pdo = new \PDO('mysql:host=localhost;dbname=test', 'username');
283
-
284
249
$mutex = new MySQLMutex($pdo, 'balance', 15);
285
- $mutex->synchronized(function () use ($bankAccount, $amount) {
286
- $balance = $bankAccount->getBalance();
287
- $balance -= $amount;
288
- if ($balance < 0) {
289
- throw new \DomainException('You have no credit');
290
- }
291
- $bankAccount->setBalance($balance);
292
- });
293
250
```
294
251
295
- #### PostgreSQLMutex
252
+ ### PostgreSQLMutex
296
253
297
254
The ** PostgreSQLMutex** uses PostgreSQL's
298
255
[ advisory locking] ( https://www.postgresql.org/docs/9.4/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS )
@@ -306,16 +263,21 @@ interrupted, the lock is automatically released.
306
263
307
264
``` php
308
265
$pdo = new \PDO('pgsql:host=localhost;dbname=test', 'username');
309
-
310
266
$mutex = new PostgreSQLMutex($pdo, 'balance');
311
- $mutex->synchronized(function () use ($bankAccount, $amount) {
312
- $balance = $bankAccount->getBalance();
313
- $balance -= $amount;
314
- if ($balance < 0) {
315
- throw new \DomainException('You have no credit');
316
- }
317
- $bankAccount->setBalance($balance);
318
- });
267
+ ```
268
+
269
+ ### DistributedMutex
270
+
271
+ The ** DistributedMutex** is the distributed lock implementation of
272
+ [ RedLock] ( https://redis.io/topics/distlock#the-redlock-algorithm ) which supports
273
+ one or more [ ` Malkush\Lock\Mutex\AbstractSpinlockMutex ` ] [ 10 ] instances.
274
+
275
+ Example:
276
+ ``` php
277
+ $mutex = new DistributedMutex([
278
+ new \Predis\Client('redis://10.0.0.1'),
279
+ new \Predis\Client('redis://10.0.0.2'),
280
+ ], 'balance');
319
281
```
320
282
321
283
## Authors
@@ -341,3 +303,4 @@ This project is free and is licensed under the MIT.
341
303
[ 9 ] : https://en.wikipedia.org/wiki/Double-checked_locking
342
304
[ 10 ] : https://github.com/php-lock/lock/blob/3ca295ccda/src/Mutex/AbstractLockMutex.php
343
305
[ 11 ] : https://github.com/php-lock/lock/blob/3ca295ccda/src/Exception/LockReleaseException.php
306
+ [ 12 ] : https://github.com/php-lock/lock/blob/41509dda0a/src/Mutex/AbstractSpinlockMutex.php#L15
0 commit comments