diff options
author | Nils Adermann <naderman@naderman.de> | 2011-01-07 20:58:28 +0100 |
---|---|---|
committer | Oleg Pudeyev <oleg@bsdpower.com> | 2011-02-12 22:05:53 -0500 |
commit | 3a3a8bb96d0cb7be2529ab095f305fd3b042783c (patch) | |
tree | e8bc13cacb8ab2f9803c2d13d55025e4903e4d7f /phpBB/includes | |
parent | 6e5e4721d83c8bde9780b02bd011bdbf5d188dea (diff) | |
download | forums-3a3a8bb96d0cb7be2529ab095f305fd3b042783c.tar forums-3a3a8bb96d0cb7be2529ab095f305fd3b042783c.tar.gz forums-3a3a8bb96d0cb7be2529ab095f305fd3b042783c.tar.bz2 forums-3a3a8bb96d0cb7be2529ab095f305fd3b042783c.tar.xz forums-3a3a8bb96d0cb7be2529ab095f305fd3b042783c.zip |
[feature/system-cron] Abstract the database locking mechanism out of cron.
Added a number of tests for the locking mechanism which can now lock
arbitrary config variables.
PHPBB3-9596
Diffstat (limited to 'phpBB/includes')
-rw-r--r-- | phpBB/includes/cron/lock.php | 104 | ||||
-rw-r--r-- | phpBB/includes/lock/db.php | 158 |
2 files changed, 158 insertions, 104 deletions
diff --git a/phpBB/includes/cron/lock.php b/phpBB/includes/cron/lock.php deleted file mode 100644 index 27b8b425c1..0000000000 --- a/phpBB/includes/cron/lock.php +++ /dev/null @@ -1,104 +0,0 @@ -<?php -/** -* -* @package phpBB3 -* @copyright (c) 2010 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Cron lock class -* @package phpBB3 -*/ -class phpbb_cron_lock -{ - /** - * Unique identifier for this lock. - * - * @var string - */ - private $cron_id; - - /** - * Tries to acquire the cron lock by updating - * the 'cron_lock' configuration variable in the database. - * - * As a lock may only be held by one process at a time, lock - * acquisition may fail if another process is holding the lock - * or if another process obtained the lock but never released it. - * Locks are forcibly released after a timeout of 1 hour. - * - * @return bool true if lock was acquired - * false otherwise - */ - public function lock() - { - global $config, $db; - - if (!isset($config['cron_lock'])) - { - set_config('cron_lock', '0', true); - } - - // make sure cron doesn't run multiple times in parallel - if ($config['cron_lock']) - { - // if the other process is running more than an hour already we have to assume it - // aborted without cleaning the lock - $time = explode(' ', $config['cron_lock']); - $time = $time[0]; - - if ($time + 3600 >= time()) - { - return false; - } - } - - $this->cron_id = time() . ' ' . unique_id(); - - $sql = 'UPDATE ' . CONFIG_TABLE . " - SET config_value = '" . $db->sql_escape($this->cron_id) . "' - WHERE config_name = 'cron_lock' - AND config_value = '" . $db->sql_escape($config['cron_lock']) . "'"; - $db->sql_query($sql); - - // another cron process altered the table between script start and UPDATE query so exit - if ($db->sql_affectedrows() != 1) - { - return false; - } - - return true; - } - - /** - * Releases the cron lock. - * - * The lock must have been previously obtained, that is, lock() call - * was issued and returned true. - * - * Note: Attempting to release a cron lock that is already released, - * that is, calling unlock() multiple times, is harmless. - * - * @return void - */ - public function unlock() - { - global $db; - - $sql = 'UPDATE ' . CONFIG_TABLE . " - SET config_value = '0' - WHERE config_name = 'cron_lock' - AND config_value = '" . $db->sql_escape($this->cron_id) . "'"; - $db->sql_query($sql); - } -} diff --git a/phpBB/includes/lock/db.php b/phpBB/includes/lock/db.php new file mode 100644 index 0000000000..e9885285d9 --- /dev/null +++ b/phpBB/includes/lock/db.php @@ -0,0 +1,158 @@ +<?php +/** +* +* @package phpBB3 +* @copyright (c) 2010 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* Database locking class +* @package phpBB3 +*/ +class phpbb_lock_db +{ + /** + * Name of the config variable this lock uses + * @var string + */ + private $config_name; + + /** + * Unique identifier for this lock. + * + * @var string + */ + private $unique_id; + + /** + * Stores the state of this lock + * @var bool + */ + private $locked; + + /** + * The phpBB configuration + * @var array + */ + private $config; + + /** + * A database connection + * @var dbal + */ + private $db; + + /** + * Creates a named released instance of the lock. + * + * You have to call lock to actually create the lock. + * + * @param string $config_name A config variable to be used for locking + * @param array $config The phpBB configuration + * @param dbal $db A database connection + */ + public function __construct($config_name, $config, dbal $db) + { + $this->config_name = $config_name; + $this->config = $config; + $this->db = $db; + } + + /** + * Tries to acquire the cron lock by updating + * the 'cron_lock' configuration variable in the database. + * + * As a lock may only be held by one process at a time, lock + * acquisition may fail if another process is holding the lock + * or if another process obtained the lock but never released it. + * Locks are forcibly released after a timeout of 1 hour. + * + * @return bool true if lock was acquired + * false otherwise + */ + public function lock() + { + if ($this->locked) + { + return true; + } + + if (!isset($this->config[$this->config_name])) + { + set_config($this->config_name, '0', true); + global $config; + $this->config = $config; + } + $lock_value = $this->config[$this->config_name]; + + // make sure cron doesn't run multiple times in parallel + if ($lock_value) + { + // if the other process is running more than an hour already we have to assume it + // aborted without cleaning the lock + $time = explode(' ', $lock_value); + $time = $time[0]; + + if ($time + 3600 >= time()) + { + return false; + } + } + + $this->unique_id = time() . ' ' . unique_id(); + + $sql = 'UPDATE ' . CONFIG_TABLE . " + SET config_value = '" . $this->db->sql_escape($this->unique_id) . "' + WHERE config_name = '" . $this->db->sql_escape($this->config_name) . "' + AND config_value = '" . $this->db->sql_escape($lock_value) . "'"; + $this->db->sql_query($sql); + + if ($this->db->sql_affectedrows()) + { + $this->locked = true; + } + else + { + // another cron process altered the table between script start and + // UPDATE query so return false + $this->locked = false; + } + + return $this->locked; + } + + /** + * Releases the cron lock. + * + * The lock must have been previously obtained, that is, lock() call + * was issued and returned true. + * + * Note: Attempting to release a cron lock that is already released, + * that is, calling unlock() multiple times, is harmless. + * + * @return void + */ + public function unlock() + { + if ($this->locked) + { + $sql = 'UPDATE ' . CONFIG_TABLE . " + SET config_value = '0' + WHERE config_name = '" . $this->db->sql_escape($this->config_name) . "' + AND config_value = '" . $this->db->sql_escape($this->unique_id) . "'"; + $this->db->sql_query($sql); + + $this->locked = false; + } + } +} |