Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
95.65% |
22 / 23 |
|
75.00% |
3 / 4 |
CRAP | |
0.00% |
0 / 1 |
db | |
95.65% |
22 / 23 |
|
75.00% |
3 / 4 |
11 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
acquire | |
93.75% |
15 / 16 |
|
0.00% |
0 / 1 |
7.01 | |||
owns_lock | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
release | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * |
4 | * This file is part of the phpBB Forum Software package. |
5 | * |
6 | * @copyright (c) phpBB Limited <https://www.phpbb.com> |
7 | * @license GNU General Public License, version 2 (GPL-2.0) |
8 | * |
9 | * For full copyright and license information, please see |
10 | * the docs/CREDITS.txt file. |
11 | * |
12 | */ |
13 | |
14 | namespace phpbb\lock; |
15 | |
16 | /** |
17 | * Database locking class |
18 | */ |
19 | class db |
20 | { |
21 | /** |
22 | * Name of the config variable this lock uses |
23 | * @var string |
24 | */ |
25 | private $config_name; |
26 | |
27 | /** |
28 | * Unique identifier for this lock. |
29 | * |
30 | * @var string |
31 | */ |
32 | private $unique_id; |
33 | |
34 | /** |
35 | * Stores the state of this lock |
36 | * @var bool |
37 | */ |
38 | private $locked; |
39 | |
40 | /** |
41 | * The phpBB configuration |
42 | * @var \phpbb\config\config |
43 | */ |
44 | private $config; |
45 | |
46 | /** |
47 | * A database connection |
48 | * @var \phpbb\db\driver\driver_interface |
49 | */ |
50 | private $db; |
51 | |
52 | /** |
53 | * Creates a named released instance of the lock. |
54 | * |
55 | * You have to call acquire() to actually create the lock. |
56 | * |
57 | * @param string $config_name A config variable to be used for locking |
58 | * @param \phpbb\config\config $config The phpBB configuration |
59 | * @param \phpbb\db\driver\driver_interface $db A database connection |
60 | */ |
61 | public function __construct($config_name, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db) |
62 | { |
63 | $this->config_name = $config_name; |
64 | $this->config = $config; |
65 | $this->db = $db; |
66 | } |
67 | |
68 | /** |
69 | * Tries to acquire the lock by updating |
70 | * the configuration variable in the database. |
71 | * |
72 | * As a lock may only be held by one process at a time, lock |
73 | * acquisition may fail if another process is holding the lock |
74 | * or if another process obtained the lock but never released it. |
75 | * Locks are forcibly released after a timeout of 1 hour. |
76 | * |
77 | * @return bool true if lock was acquired |
78 | * false otherwise |
79 | */ |
80 | public function acquire() |
81 | { |
82 | if ($this->locked) |
83 | { |
84 | return false; |
85 | } |
86 | |
87 | if (!isset($this->config[$this->config_name])) |
88 | { |
89 | $this->config->set($this->config_name, '0', false); |
90 | } |
91 | $lock_value = $this->config[$this->config_name]; |
92 | |
93 | // make sure lock cannot be acquired by multiple processes |
94 | if ($lock_value) |
95 | { |
96 | // if the other process is running more than an hour already we have to assume it |
97 | // aborted without cleaning the lock |
98 | $time = explode(' ', $lock_value); |
99 | $time = $time[0]; |
100 | |
101 | if ($time + 3600 >= time()) |
102 | { |
103 | return false; |
104 | } |
105 | } |
106 | |
107 | $this->unique_id = time() . ' ' . unique_id(); |
108 | |
109 | // try to update the config value, if it was already modified by another |
110 | // process we failed to acquire the lock. |
111 | $this->locked = $this->config->set_atomic($this->config_name, $lock_value, $this->unique_id, false); |
112 | |
113 | if ($this->locked == true) |
114 | { |
115 | if ($this->config->ensure_lock($this->config_name, $this->unique_id)) |
116 | { |
117 | return true; |
118 | } |
119 | } |
120 | return $this->locked; |
121 | } |
122 | |
123 | /** |
124 | * Does this process own the lock? |
125 | * |
126 | * @return bool true if lock is owned |
127 | * false otherwise |
128 | */ |
129 | public function owns_lock() |
130 | { |
131 | return (bool) $this->locked; |
132 | } |
133 | |
134 | /** |
135 | * Releases the lock. |
136 | * |
137 | * The lock must have been previously obtained, that is, acquire() call |
138 | * was issued and returned true. |
139 | * |
140 | * Note: Attempting to release a lock that is already released, |
141 | * that is, calling release() multiple times, is harmless. |
142 | * |
143 | * @return null |
144 | */ |
145 | public function release() |
146 | { |
147 | if ($this->locked) |
148 | { |
149 | $this->config->set_atomic($this->config_name, $this->unique_id, '0', false); |
150 | $this->locked = false; |
151 | } |
152 | } |
153 | } |