PluginProbe
UpdraftCentral Dashboard / trunk
UpdraftCentral Dashboard vtrunk
0.8.33 0.7.2 0.7.3 0.7.4 0.8.0 0.8.1 0.8.10 0.8.11 0.8.12 0.8.13 0.8.14 0.8.15 0.8.16 0.8.17 0.8.18 0.8.19 0.8.2 0.8.20 0.8.21 0.8.22 0.8.23 0.8.24 0.8.25 0.8.26 0.8.27 All 51 releases
updraftcentral / classes / class-updraft-semaphore.php

class-updraft-semaphore.php in UpdraftCentral Dashboard trunk, at classes/class-updraft-semaphore.php

276 lines 6.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Semaphore Lock Management
4 */
5 class Updraft_Semaphore_1_0 {
6
7 /**
8 * Initializes the semaphore object.
9 *
10 * @static
11 * @return Updraft_Semaphore
12 */
13 public static function factory() {
14 return new self;
15 }
16
17 /**
18 * Lock Broke
19 *
20 * @var boolean
21 */
22 protected $lock_broke = false;
23
24 /**
25 * Array of loggers
26 *
27 * @var array
28 */
29 protected $loggers;
30
31 public $lock_name = 'lock';
32
33 /**
34 * Ensures that the semaphore options exists before actually using them
35 */
36 public function ensure_semaphore_exists() {
37 // Make sure the options for semaphores exist
38 global $wpdb;
39
40 $results = $wpdb->get_results("
41 SELECT option_id
42 FROM $wpdb->options
43 WHERE option_name IN ('updraft_locked_".$this->lock_name."', 'updraft_unlocked_".$this->lock_name."', 'updraft_last_lock_time_".$this->lock_name."', 'updraft_semaphore_".$this->lock_name."')
44 ");
45
46 if (!is_array($results) || count($results) < 3) {
47
48 if (is_array($results) && count($results) > 0) {
49 $this->log(sprintf('Semaphore (%s, $s) in an impossible/broken state - fixing (%d)', $this->lock_name, $wpdb->options, count($results)));
50 } else {
51 $this->log(sprintf('Semaphore (%s, %s) being initialised', $this->lock_name, $wpdb->options));
52 }
53
54 $wpdb->query("
55 DELETE FROM $wpdb->options
56 WHERE option_name IN ('updraft_locked_".$this->lock_name."', 'updraft_unlocked_".$this->lock_name."', 'updraft_last_lock_time_".$this->lock_name."', 'updraft_semaphore_".$this->lock_name."')
57 ");
58
59 $wpdb->query($wpdb->prepare("
60 INSERT INTO $wpdb->options (option_name, option_value, autoload)
61 VALUES
62 ('updraft_unlocked_".$this->lock_name."', '1', 'no'),
63 ('updraft_last_lock_time_".$this->lock_name."', '%s', 'no'),
64 ('updraft_semaphore_".$this->lock_name."', '0', 'no')
65 ", current_time('mysql', 1)));
66 }
67 }
68
69 /**
70 * Attempts to start the lock. If the rename works, the lock is started.
71 *
72 * @return bool
73 */
74 public function lock() {
75 global $wpdb;
76
77 // Attempt to set the lock
78 $affected = $wpdb->query("
79 UPDATE $wpdb->options
80 SET option_name = 'updraft_locked_".$this->lock_name."'
81 WHERE option_name = 'updraft_unlocked_".$this->lock_name."'
82 ");
83
84 if ('0' == $affected && !$this->stuck_check()) {
85 $this->log('Semaphore lock ('.$this->lock_name.', '.$wpdb->options.') failed (line '.__LINE__.')');
86 return false;
87 }
88
89 // Check to see if all processes are complete
90 $affected = $wpdb->query("
91 UPDATE $wpdb->options
92 SET option_value = CAST(option_value AS UNSIGNED) + 1
93 WHERE option_name = 'updraft_semaphore_".$this->lock_name."'
94 AND option_value = '0'
95 ");
96 if ('1' != $affected) {
97 if (!$this->stuck_check()) {
98 $this->log('Semaphore lock ('.$this->lock_name.', '.$wpdb->options.') failed (line '.__LINE__.')');
99 return false;
100 }
101
102 // Reset the semaphore to 1
103 $wpdb->query("
104 UPDATE $wpdb->options
105 SET option_value = '1'
106 WHERE option_name = 'updraft_semaphore_".$this->lock_name."'
107 ");
108
109 $this->log('Semaphore ('.$this->lock_name.', '.$wpdb->options.') reset to 1');
110 }
111
112 // Set the lock time
113 $wpdb->query($wpdb->prepare("
114 UPDATE $wpdb->options
115 SET option_value = %s
116 WHERE option_name = 'updraft_last_lock_time_".$this->lock_name."'
117 ", current_time('mysql', 1)));
118 $this->log('Set semaphore last lock ('.$this->lock_name.') time to '.current_time('mysql', 1));
119
120 $this->log('Semaphore lock ('.$this->lock_name.') complete');
121 return true;
122 }
123
124 /**
125 * Increment the semaphore.
126 *
127 * @param array $filters
128 * @return Updraft_Semaphore
129 */
130 public function increment(array $filters = array()) {
131 global $wpdb;
132
133 if (count($filters)) {
134 // Loop through all of the filters and increment the semaphore
135 foreach ($filters as $priority) {
136 for ($i = 0, $j = count($priority); $i < $j; ++$i) {
137 $this->increment();
138 }
139 }
140 } else {
141 $wpdb->query("
142 UPDATE $wpdb->options
143 SET option_value = CAST(option_value AS UNSIGNED) + 1
144 WHERE option_name = 'updraft_semaphore_".$this->lock_name."'
145 ");
146 $this->log('Incremented the semaphore ('.$this->lock_name.') by 1');
147 }
148
149 return $this;
150 }
151
152 /**
153 * Decrements the semaphore.
154 *
155 * @return void
156 */
157 public function decrement() {
158 global $wpdb;
159
160 $wpdb->query("
161 UPDATE $wpdb->options
162 SET option_value = CAST(option_value AS UNSIGNED) - 1
163 WHERE option_name = 'updraft_semaphore_".$this->lock_name."'
164 AND CAST(option_value AS UNSIGNED) > 0
165 ");
166 $this->log('Decremented the semaphore ('.$this->lock_name.') by 1');
167 }
168
169 /**
170 * Unlocks the process.
171 *
172 * @return bool
173 */
174 public function unlock() {
175 global $wpdb;
176
177 // Decrement for the master process.
178 $this->decrement();
179
180 $result = $wpdb->query("
181 UPDATE $wpdb->options
182 SET option_name = 'updraft_unlocked_".$this->lock_name."'
183 WHERE option_name = 'updraft_locked_".$this->lock_name."'
184 ");
185
186 if ('1' == $result) {
187 $this->log('Semaphore ('.$this->lock_name.') unlocked');
188 return true;
189 }
190
191 $this->log('Semaphore ('.$this->lock_name.', '.$wpdb->options.') still locked ('.$result.')');
192 return false;
193 }
194
195 /**
196 * Attempts to jiggle the stuck lock loose.
197 *
198 * @return bool
199 */
200 private function stuck_check() {
201 global $wpdb;
202
203 // Check to see if we already broke the lock.
204 if ($this->lock_broke) {
205 return true;
206 }
207
208 $current_time = current_time('mysql', 1);
209 $three_minutes_before = gmdate('Y-m-d H:i:s', time()-(defined('UPDRAFT_SEMAPHORE_LOCK_WAIT') ? UPDRAFT_SEMAPHORE_LOCK_WAIT : 180));
210
211 $affected = $wpdb->query($wpdb->prepare("
212 UPDATE $wpdb->options
213 SET option_value = %s
214 WHERE option_name = 'updraft_last_lock_time_".$this->lock_name."'
215 AND option_value <= %s
216 ", $current_time, $three_minutes_before));
217
218 if ('1' == $affected) {
219 $this->log('Semaphore ('.$this->lock_name.', '.$wpdb->options.') was stuck, set lock time to '.$current_time);
220 $this->lock_broke = true;
221 return true;
222 }
223
224 return false;
225 }
226
227 /**
228 * Sets the logger for this instance.
229 *
230 * @param array $loggers - the loggers for this task
231 */
232 public function set_loggers($loggers) {
233 foreach ($loggers as $logger) {
234 $this->add_logger($logger);
235 }
236 }
237
238 /**
239 * Add a logger to loggers list
240 *
241 * @param Object $logger - a logger for the instance
242 */
243 public function add_logger($logger) {
244 $this->_loggers[] = $logger;
245 }
246
247 /**
248 * Return list of loggers
249 *
250 * @return array
251 */
252 public function get_loggers() {
253 return $this->_loggers;
254 }
255
256 /**
257 * Captures and logs any interesting messages
258 *
259 * @param String $message - the error message
260 * @param String $error_type - the error type
261 *
262 * @return void
263 */
264 public function log($message, $error_type = 'info') {
265 if (defined('UPDRAFTCENTRAL_DISABLE_SEMAPHORE_LOG') && UPDRAFTCENTRAL_DISABLE_SEMAPHORE_LOG) return;
266
267 if (isset($this->_loggers)) {
268 foreach ($this->_loggers as $logger) {
269 $logger->log($error_type, $message);
270 }
271 } else {
272 error_log($message);
273 }
274 }
275 } // End Updraft_Semaphore
276