]> git.mxchange.org Git - friendica.git/blob - src/Core/Lock/DatabaseLock.php
CleanUp Lock namespace
[friendica.git] / src / Core / Lock / DatabaseLock.php
1 <?php
2
3 namespace Friendica\Core\Lock;
4
5 use Friendica\Core\BaseLock;
6 use Friendica\Core\Cache\Duration;
7 use Friendica\Database\Database;
8 use Friendica\Util\DateTimeFormat;
9
10 /**
11  * Locking driver that stores the locks in the database
12  */
13 class DatabaseLock extends BaseLock
14 {
15         /**
16          * The current ID of the process
17          *
18          * @var int
19          */
20         private $pid;
21
22         /**
23          * @var Database The database connection of Friendica
24          */
25         private $dba;
26
27         /**
28          * @param null|int $pid The Id of the current process (null means determine automatically)
29          */
30         public function __construct(Database $dba, $pid = null)
31         {
32                 $this->dba = $dba;
33                 $this->pid = isset($pid) ? $pid : getmypid();
34         }
35
36         /**
37          * (@inheritdoc)
38          */
39         public function acquire($key, $timeout = 120, $ttl = Duration::FIVE_MINUTES)
40         {
41                 $got_lock = false;
42                 $start    = time();
43
44                 do {
45                         $this->dba->lock('locks');
46                         $lock = $this->dba->selectFirst('locks', ['locked', 'pid'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]);
47
48                         if ($this->dba->isResult($lock)) {
49                                 if ($lock['locked']) {
50                                         // We want to lock something that was already locked by us? So we got the lock.
51                                         if ($lock['pid'] == $this->pid) {
52                                                 $got_lock = true;
53                                         }
54                                 }
55                                 if (!$lock['locked']) {
56                                         $this->dba->update('locks', ['locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')], ['name' => $key]);
57                                         $got_lock = true;
58                                 }
59                         } else {
60                                 $this->dba->insert('locks', ['name' => $key, 'locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')]);
61                                 $got_lock = true;
62                                 $this->markAcquire($key);
63                         }
64
65                         $this->dba->unlock();
66
67                         if (!$got_lock && ($timeout > 0)) {
68                                 usleep(rand(100000, 2000000));
69                         }
70                 } while (!$got_lock && ((time() - $start) < $timeout));
71
72                 return $got_lock;
73         }
74
75         /**
76          * (@inheritdoc)
77          */
78         public function release($key, $override = false)
79         {
80                 if ($override) {
81                         $where = ['name' => $key];
82                 } else {
83                         $where = ['name' => $key, 'pid' => $this->pid];
84                 }
85
86                 if ($this->dba->exists('locks', $where)) {
87                         $return = $this->dba->delete('locks', $where);
88                 } else {
89                         $return = false;
90                 }
91
92                 $this->markRelease($key);
93
94                 return $return;
95         }
96
97         /**
98          * (@inheritdoc)
99          */
100         public function releaseAll($override = false)
101         {
102                 $success = parent::releaseAll($override);
103
104                 if ($override) {
105                         $where = ['1 = 1'];
106                 } else {
107                         $where = ['pid' => $this->pid];
108                 }
109                 $return = $this->dba->delete('locks', $where);
110
111                 $this->acquiredLocks = [];
112
113                 return $return && $success;
114         }
115
116         /**
117          * (@inheritdoc)
118          */
119         public function isLocked($key)
120         {
121                 $lock = $this->dba->selectFirst('locks', ['locked'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]);
122
123                 if ($this->dba->isResult($lock)) {
124                         return $lock['locked'] !== false;
125                 } else {
126                         return false;
127                 }
128         }
129
130         /**
131          * {@inheritDoc}
132          */
133         public function getName()
134         {
135                 return Type::DATABASE;
136         }
137
138         /**
139          * {@inheritDoc}
140          */
141         public function getLocks(string $prefix = '')
142         {
143                 if (empty($prefix)) {
144                         $where = ['`expires` >= ?', DateTimeFormat::utcNow()];
145                 } else {
146                         $where = ['`expires` >= ? AND `name` LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix];
147                 }
148
149                 $stmt = $this->dba->select('locks', ['name'], $where);
150
151                 $keys = [];
152                 while ($key = $this->dba->fetch($stmt)) {
153                         array_push($keys, $key['name']);
154                 }
155                 $this->dba->close($stmt);
156
157                 return $keys;
158         }
159 }