aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/includes/lock/db.php
blob: 20dbb63e0cf173c93ad3a9eb4a71e524dbdb61a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<?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 phpbb_config
	*/
	private $config;

	/**
	* A database connection
	* @var dbal
	*/
	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	dbal	$db				A database connection
	*/
	public function __construct($config_name, phpbb_config $config, dbal $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;
	}

	/**
	* 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 void
	*/
	public function release()
	{
		if ($this->locked)
		{
			$this->config->set_atomic($this->config_name, $this->unique_id, '0', false);
			$this->locked = false;
		}
	}
}