Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.65% covered (success)
95.65%
22 / 23
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
db
95.65% covered (success)
95.65%
22 / 23
75.00% covered (warning)
75.00%
3 / 4
11
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 acquire
93.75% covered (success)
93.75%
15 / 16
0.00% covered (danger)
0.00%
0 / 1
7.01
 owns_lock
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 release
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
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
14namespace phpbb\lock;
15
16/**
17* Database locking class
18*/
19class 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}