1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* This file is part of ninja-mutex. |
4
|
|
|
* |
5
|
|
|
* (C) Kamil Dziedzic <[email protected]> |
6
|
|
|
* |
7
|
|
|
* For the full copyright and license information, please view the LICENSE |
8
|
|
|
* file that was distributed with this source code. |
9
|
|
|
*/ |
10
|
|
|
namespace NinjaMutex\Lock; |
11
|
|
|
|
12
|
|
|
use Memcache; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* Lock implementor using Memcache |
16
|
|
|
* |
17
|
|
|
* @author Kamil Dziedzic <[email protected]> |
18
|
|
|
*/ |
19
|
|
View Code Duplication |
class MemcacheLock extends LockAbstract implements LockExpirationInterface |
|
|
|
|
20
|
|
|
{ |
21
|
|
|
/** |
22
|
|
|
* Maximum expiration time in seconds (30 days) |
23
|
|
|
* http://php.net/manual/en/memcache.add.php |
24
|
|
|
*/ |
25
|
|
|
const MAX_EXPIRATION = 2592000; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Memcache connection |
29
|
|
|
* |
30
|
|
|
* @var Memcache |
31
|
|
|
*/ |
32
|
|
|
protected $memcache; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @var int Expiration time of the lock in seconds |
36
|
|
|
*/ |
37
|
|
|
protected $expiration = 0; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @param Memcache $memcache |
41
|
|
|
*/ |
42
|
|
|
public function __construct(Memcache $memcache) |
43
|
|
|
{ |
44
|
|
|
parent::__construct(); |
45
|
|
|
|
46
|
|
|
$this->memcache = $memcache; |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* @param int $expiration Expiration time of the lock in seconds. If it's equal to zero (default), the lock will never expire. |
51
|
|
|
* Max 2592000s (30 days), if greater it will be capped to 2592000 without throwing an error. |
52
|
|
|
* WARNING: Using value higher than 0 may lead to race conditions. If you set too low expiration time |
53
|
|
|
* e.g. 30s and critical section will run for 31s another process will gain lock at the same time, |
54
|
|
|
* leading to unpredicted behaviour. Use with caution. |
55
|
|
|
*/ |
56
|
|
|
public function setExpiration($expiration) |
57
|
|
|
{ |
58
|
|
|
if ($expiration > static::MAX_EXPIRATION) { |
59
|
|
|
$expiration = static::MAX_EXPIRATION; |
60
|
|
|
} |
61
|
|
|
$this->expiration = $expiration; |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Clear lock without releasing it |
66
|
|
|
* Do not use this method unless you know what you do |
67
|
|
|
* |
68
|
|
|
* @param string $name name of lock |
69
|
|
|
* @return bool |
70
|
|
|
*/ |
71
|
|
|
public function clearLock($name) |
72
|
|
|
{ |
73
|
|
|
if (!isset($this->locks[$name])) { |
74
|
|
|
return false; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
unset($this->locks[$name]); |
78
|
|
|
return true; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* @param string $name name of lock |
83
|
|
|
* @param bool $blocking |
84
|
|
|
* @return bool |
85
|
|
|
*/ |
86
|
|
|
protected function getLock($name, $blocking) |
87
|
|
|
{ |
88
|
|
|
if (!$this->memcache->add($name, serialize($this->getLockInformation()), 0, $this->expiration)) { |
89
|
|
|
return false; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
return true; |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* Release lock |
97
|
|
|
* |
98
|
|
|
* @param string $name name of lock |
99
|
|
|
* @return bool |
100
|
|
|
*/ |
101
|
|
|
public function releaseLock($name) |
102
|
|
|
{ |
103
|
|
|
if (isset($this->locks[$name]) && $this->memcache->delete($name)) { |
104
|
|
|
unset($this->locks[$name]); |
105
|
|
|
|
106
|
|
|
return true; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
return false; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Check if lock is locked |
114
|
|
|
* |
115
|
|
|
* @param string $name name of lock |
116
|
|
|
* @return bool |
117
|
|
|
*/ |
118
|
|
|
public function isLocked($name) |
119
|
|
|
{ |
120
|
|
|
return false !== $this->memcache->get($name); |
121
|
|
|
} |
122
|
|
|
} |
123
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.