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