diff options
author | David King <imkingdavid@gmail.com> | 2013-08-31 13:37:11 -0700 |
---|---|---|
committer | David King <imkingdavid@gmail.com> | 2013-08-31 13:37:11 -0700 |
commit | af1eb7466f11cdb0f851acfcacd957267e20e3ce (patch) | |
tree | 1c72f7436ffcaa0d355ee11a0375323dcf5731f6 /phpBB/phpbb/lock | |
parent | 9485eea0987478da25327a06a4fd36943ca1c01c (diff) | |
parent | 9d6370751f1b998e3da448e16c1446b33ddd17d0 (diff) | |
download | forums-af1eb7466f11cdb0f851acfcacd957267e20e3ce.tar forums-af1eb7466f11cdb0f851acfcacd957267e20e3ce.tar.gz forums-af1eb7466f11cdb0f851acfcacd957267e20e3ce.tar.bz2 forums-af1eb7466f11cdb0f851acfcacd957267e20e3ce.tar.xz forums-af1eb7466f11cdb0f851acfcacd957267e20e3ce.zip |
Merge branch 'develop' into ticket/11215
Diffstat (limited to 'phpBB/phpbb/lock')
-rw-r--r-- | phpBB/phpbb/lock/db.php | 149 | ||||
-rw-r--r-- | phpBB/phpbb/lock/flock.php | 144 |
2 files changed, 293 insertions, 0 deletions
diff --git a/phpBB/phpbb/lock/db.php b/phpBB/phpbb/lock/db.php new file mode 100644 index 0000000000..5cc0821aa0 --- /dev/null +++ b/phpBB/phpbb/lock/db.php @@ -0,0 +1,149 @@ +<?php +/** +* +* @package phpBB3 +* @copyright (c) 2010 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @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 phpbb_config + */ + private $config; + + /** + * A database connection + * @var phpbb_db_driver + */ + private $db; + + /** + * Creates a named released instance of the lock. + * + * You have to call acquire() to actually create the lock. + * + * @param string $config_name A config variable to be used for locking + * @param array $config The phpBB configuration + * @param phpbb_db_driver $db A database connection + */ + public function __construct($config_name, phpbb_config $config, phpbb_db_driver $db) + { + $this->config_name = $config_name; + $this->config = $config; + $this->db = $db; + } + + /** + * Tries to acquire the lock by updating + * the 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 acquire() + { + if ($this->locked) + { + return false; + } + + if (!isset($this->config[$this->config_name])) + { + $this->config->set($this->config_name, '0', false); + } + $lock_value = $this->config[$this->config_name]; + + // make sure lock cannot be acquired by multiple processes + 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(); + + // try to update the config value, if it was already modified by another + // process we failed to acquire the lock. + $this->locked = $this->config->set_atomic($this->config_name, $lock_value, $this->unique_id, false); + + return $this->locked; + } + + /** + * Does this process own the lock? + * + * @return bool true if lock is owned + * false otherwise + */ + public function owns_lock() + { + return (bool) $this->locked; + } + + /** + * Releases the lock. + * + * The lock must have been previously obtained, that is, acquire() call + * was issued and returned true. + * + * Note: Attempting to release a lock that is already released, + * that is, calling release() multiple times, is harmless. + * + * @return null + */ + public function release() + { + if ($this->locked) + { + $this->config->set_atomic($this->config_name, $this->unique_id, '0', false); + $this->locked = false; + } + } +} diff --git a/phpBB/phpbb/lock/flock.php b/phpBB/phpbb/lock/flock.php new file mode 100644 index 0000000000..17de0847c0 --- /dev/null +++ b/phpBB/phpbb/lock/flock.php @@ -0,0 +1,144 @@ +<?php +/** +* +* @package phpBB3 +* @copyright (c) 2012 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* File locking class +* @package phpBB3 +*/ +class phpbb_lock_flock +{ + /** + * Path to the file to which access is controlled + * + * @var string + */ + private $path; + + /** + * File pointer for the lock file + * @var string + */ + private $lock_fp; + + /** + * Constructor. + * + * You have to call acquire() to actually acquire the lock. + * + * @param string $path Path to the file to which access is controlled + */ + public function __construct($path) + { + $this->path = $path; + $this->lock_fp = null; + } + + /** + * Tries to acquire the lock. + * + * If the lock is already held by another process, this call will block + * until the other process releases the lock. If a lock is acquired and + * is not released before script finishes but the process continues to + * live (apache/fastcgi) then subsequent processes trying to acquire + * the same lock will be blocked forever. + * + * If the lock is already held by the same process via another instance + * of this class, this call will block forever. + * + * If flock function is disabled in php or fails to work, lock + * acquisition will fail and false will be returned. + * + * @return bool true if lock was acquired + * false otherwise + */ + public function acquire() + { + if ($this->lock_fp) + { + return false; + } + + // For systems that can't have two processes opening + // one file for writing simultaneously + if (file_exists($this->path . '.lock')) + { + $mode = 'rb'; + } + else + { + $mode = 'wb'; + } + + $this->lock_fp = @fopen($this->path . '.lock', $mode); + + if ($mode == 'wb') + { + if (!$this->lock_fp) + { + // Two processes may attempt to create lock file at the same time. + // Have the losing process try opening the lock file again for reading + // on the assumption that the winning process created it + $mode = 'rb'; + $this->lock_fp = @fopen($this->path . '.lock', $mode); + } + else + { + // Only need to set mode when the lock file is written + @chmod($this->path . '.lock', 0666); + } + } + + if ($this->lock_fp) + { + @flock($this->lock_fp, LOCK_EX); + } + + return (bool) $this->lock_fp; + } + + /** + * Does this process own the lock? + * + * @return bool true if lock is owned + * false otherwise + */ + public function owns_lock() + { + return (bool) $this->lock_fp; + } + + /** + * Releases the lock. + * + * The lock must have been previously obtained, that is, acquire() call + * was issued and returned true. + * + * Note: Attempting to release a lock that is already released, + * that is, calling release() multiple times, is harmless. + * + * @return null + */ + public function release() + { + if ($this->lock_fp) + { + @flock($this->lock_fp, LOCK_UN); + fclose($this->lock_fp); + $this->lock_fp = null; + } + } +} |