]> git.mxchange.org Git - friendica.git/blob - src/Core/Lock/CacheLock.php
Merge pull request #7541 from vinzv/patch-2
[friendica.git] / src / Core / Lock / CacheLock.php
1 <?php
2
3 namespace Friendica\Core\Lock;
4
5 use Friendica\Core\Cache;
6 use Friendica\Core\Cache\IMemoryCache;
7
8 class CacheLock extends Lock
9 {
10         /**
11          * @var string The static prefix of all locks inside the cache
12          */
13         const CACHE_PREFIX = 'lock:';
14
15         /**
16          * @var \Friendica\Core\Cache\ICache;
17          */
18         private $cache;
19
20         /**
21          * CacheLock constructor.
22          *
23          * @param IMemoryCache $cache The CacheDriver for this type of lock
24          */
25         public function __construct(IMemoryCache $cache)
26         {
27                 $this->cache = $cache;
28         }
29
30         /**
31          * (@inheritdoc)
32          */
33         public function acquireLock($key, $timeout = 120, $ttl = Cache\Cache::FIVE_MINUTES)
34         {
35                 $got_lock = false;
36                 $start    = time();
37
38                 $cachekey = self::getLockKey($key);
39
40                 do {
41                         $lock = $this->cache->get($cachekey);
42                         // When we do want to lock something that was already locked by us.
43                         if ((int)$lock == getmypid()) {
44                                 $got_lock = true;
45                         }
46
47                         // When we do want to lock something new
48                         if (is_null($lock)) {
49                                 // At first initialize it with "0"
50                                 $this->cache->add($cachekey, 0);
51                                 // Now the value has to be "0" because otherwise the key was used by another process meanwhile
52                                 if ($this->cache->compareSet($cachekey, 0, getmypid(), $ttl)) {
53                                         $got_lock = true;
54                                         $this->markAcquire($key);
55                                 }
56                         }
57
58                         if (!$got_lock && ($timeout > 0)) {
59                                 usleep(rand(10000, 200000));
60                         }
61                 } while (!$got_lock && ((time() - $start) < $timeout));
62
63                 return $got_lock;
64         }
65
66         /**
67          * (@inheritdoc)
68          */
69         public function releaseLock($key, $override = false)
70         {
71                 $cachekey = self::getLockKey($key);
72
73                 if ($override) {
74                         $return = $this->cache->delete($cachekey);
75                 } else {
76                         $return = $this->cache->compareDelete($cachekey, getmypid());
77                 }
78                 $this->markRelease($key);
79
80                 return $return;
81         }
82
83         /**
84          * (@inheritdoc)
85          */
86         public function isLocked($key)
87         {
88                 $cachekey = self::getLockKey($key);
89                 $lock     = $this->cache->get($cachekey);
90                 return isset($lock) && ($lock !== false);
91         }
92
93         /**
94          * {@inheritDoc}
95          */
96         public function getName()
97         {
98                 return $this->cache->getName();
99         }
100
101         /**
102          * {@inheritDoc}
103          */
104         public function getLocks(string $prefix = '')
105         {
106                 $locks = $this->cache->getAllKeys(self::CACHE_PREFIX . $prefix);
107
108                 array_walk($locks, function (&$lock, $key) {
109                         $lock = substr($lock, strlen(self::CACHE_PREFIX));
110                 });
111
112                 return $locks;
113         }
114
115         /**
116          * {@inheritDoc}
117          */
118         public function releaseAll($override = false)
119         {
120                 $success = parent::releaseAll($override);
121
122                 $locks = $this->getLocks();
123
124                 foreach ($locks as $lock) {
125                         if (!$this->releaseLock($lock, $override)) {
126                                 $success = false;
127                         }
128                 }
129
130                 return $success;
131         }
132
133         /**
134          * @param string $key The original key
135          *
136          * @return string        The cache key used for the cache
137          */
138         private static function getLockKey($key)
139         {
140                 return self::CACHE_PREFIX . $key;
141         }
142 }