Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\Core\Lock;
|
Chris@0
|
4
|
Chris@0
|
5 /**
|
Chris@0
|
6 * @defgroup lock Locking mechanisms
|
Chris@0
|
7 * @{
|
Chris@0
|
8 * Functions to coordinate long operations across requests.
|
Chris@0
|
9 *
|
Chris@0
|
10 * In most environments, multiple Drupal page requests (a.k.a. threads or
|
Chris@0
|
11 * processes) will execute in parallel. This leads to potential conflicts or
|
Chris@0
|
12 * race conditions when two requests execute the same code at the same time. For
|
Chris@0
|
13 * instance, some implementations of hook_cron() implicitly assume they are
|
Chris@0
|
14 * running only once, rather than having multiple calls in parallel. To prevent
|
Chris@0
|
15 * problems with such code, the cron system uses a locking process to ensure
|
Chris@0
|
16 * that cron is not started again if it is already running.
|
Chris@0
|
17 *
|
Chris@0
|
18 * To avoid these types of conflicts, Drupal has a cooperative, advisory lock
|
Chris@0
|
19 * system. Any long-running operation that could potentially be attempted in
|
Chris@0
|
20 * parallel by multiple requests should try to acquire a lock before
|
Chris@0
|
21 * proceeding. By obtaining a lock, one request notifies any other requests that
|
Chris@0
|
22 * a specific operation is in progress which must not be executed in parallel.
|
Chris@0
|
23 *
|
Chris@0
|
24 * To use this API, pick a unique name for the lock. A sensible choice is the
|
Chris@0
|
25 * name of the function performing the operation. Here is a simple example:
|
Chris@0
|
26 * @code
|
Chris@0
|
27 * function mymodule_long_operation() {
|
Chris@0
|
28 * $lock = \Drupal::lock();
|
Chris@0
|
29 * if ($lock->acquire('mymodule_long_operation')) {
|
Chris@0
|
30 * // Do the long operation here.
|
Chris@0
|
31 * // ...
|
Chris@0
|
32 * $lock->release('mymodule_long_operation');
|
Chris@0
|
33 * }
|
Chris@0
|
34 * }
|
Chris@0
|
35 * @endcode
|
Chris@0
|
36 *
|
Chris@0
|
37 * If a function acquires a lock it should always release it when the operation
|
Chris@0
|
38 * is complete by calling $lock->release(), as in the example.
|
Chris@0
|
39 *
|
Chris@0
|
40 * A function that has acquired a lock may attempt to renew a lock (extend the
|
Chris@0
|
41 * duration of the lock) by calling $lock->acquire() again during the operation.
|
Chris@0
|
42 * Failure to renew a lock is indicative that another request has acquired the
|
Chris@0
|
43 * lock, and that the current operation may need to be aborted.
|
Chris@0
|
44 *
|
Chris@0
|
45 * If a function fails to acquire a lock it may either immediately return, or
|
Chris@0
|
46 * it may call $lock->wait() if the rest of the current page request requires
|
Chris@0
|
47 * that the operation in question be complete. After $lock->wait() returns, the
|
Chris@0
|
48 * function may again attempt to acquire the lock, or may simply allow the page
|
Chris@0
|
49 * request to proceed on the assumption that a parallel request completed the
|
Chris@0
|
50 * operation.
|
Chris@0
|
51 *
|
Chris@0
|
52 * $lock->acquire() and $lock->wait() will automatically break (delete) a lock
|
Chris@0
|
53 * whose duration has exceeded the timeout specified when it was acquired.
|
Chris@0
|
54 *
|
Chris@0
|
55 * The following limitations in this implementation should be carefully noted:
|
Chris@0
|
56 * - Time: Timestamps are derived from the local system clock of the environment
|
Chris@0
|
57 * the code is executing in. The orderly progression of time from this
|
Chris@0
|
58 * viewpoint can be disrupted by external events such as NTP synchronization
|
Chris@0
|
59 * and operator intervention. Where multiple web servers are involved in
|
Chris@0
|
60 * serving the site, they will have their own independent clocks, introducing
|
Chris@0
|
61 * another source of error in the time keeping process. Timeout values applied
|
Chris@0
|
62 * to locks must therefore be considered approximate, and should not be relied
|
Chris@0
|
63 * upon.
|
Chris@0
|
64 * - Uniqueness: Uniqueness of lock names is not enforced. The impact of the
|
Chris@0
|
65 * use of a common lock name will depend on what processes and resources the
|
Chris@0
|
66 * lock is being used to manage.
|
Chris@0
|
67 * - Sharing: There is limited support for resources shared across sites.
|
Chris@0
|
68 * The locks are stored as rows in the semaphore table and, as such, they
|
Chris@0
|
69 * have the same visibility as the table. If resources managed by a lock are
|
Chris@0
|
70 * shared across sites then the semaphore table must be shared across sites
|
Chris@0
|
71 * as well. This is a binary situation: either all resources are shared and
|
Chris@0
|
72 * the semaphore table is shared or no resources are shared and the semaphore
|
Chris@0
|
73 * table is not shared. Mixed mode operation is not supported.
|
Chris@0
|
74 *
|
Chris@0
|
75 * @} End of "defgroup lock".
|
Chris@0
|
76 */
|
Chris@0
|
77
|
Chris@0
|
78 /**
|
Chris@0
|
79 * Lock backend interface.
|
Chris@0
|
80 *
|
Chris@0
|
81 * @ingroup lock
|
Chris@0
|
82 */
|
Chris@0
|
83 interface LockBackendInterface {
|
Chris@0
|
84
|
Chris@0
|
85 /**
|
Chris@0
|
86 * Acquires a lock.
|
Chris@0
|
87 *
|
Chris@0
|
88 * @param string $name
|
Chris@0
|
89 * Lock name. Limit of name's length is 255 characters.
|
Chris@0
|
90 * @param float $timeout
|
Chris@0
|
91 * (optional) Lock lifetime in seconds. Defaults to 30.0.
|
Chris@0
|
92 *
|
Chris@0
|
93 * @return bool
|
Chris@0
|
94 */
|
Chris@0
|
95 public function acquire($name, $timeout = 30.0);
|
Chris@0
|
96
|
Chris@0
|
97 /**
|
Chris@0
|
98 * Checks if a lock is available for acquiring.
|
Chris@0
|
99 *
|
Chris@0
|
100 * @param string $name
|
Chris@0
|
101 * Lock to acquire.
|
Chris@0
|
102 *
|
Chris@0
|
103 * @return bool
|
Chris@0
|
104 */
|
Chris@0
|
105 public function lockMayBeAvailable($name);
|
Chris@0
|
106
|
Chris@0
|
107 /**
|
Chris@0
|
108 * Waits a short amount of time before a second lock acquire attempt.
|
Chris@0
|
109 *
|
Chris@0
|
110 * While this method is subject to have a generic implementation in abstract
|
Chris@0
|
111 * backend implementation, some backends may provide non blocking or less I/O
|
Chris@0
|
112 * intensive wait mechanism: this is why this method remains on the backend
|
Chris@0
|
113 * interface.
|
Chris@0
|
114 *
|
Chris@0
|
115 * @param string $name
|
Chris@0
|
116 * Lock name currently being locked.
|
Chris@0
|
117 * @param int $delay
|
Chris@0
|
118 * Seconds to wait for. Defaults to 30.
|
Chris@0
|
119 *
|
Chris@0
|
120 * @return bool
|
Chris@0
|
121 * TRUE if the lock holds, FALSE if it may be available. You still need to
|
Chris@0
|
122 * acquire the lock manually and it may fail again.
|
Chris@0
|
123 */
|
Chris@0
|
124 public function wait($name, $delay = 30);
|
Chris@0
|
125
|
Chris@0
|
126 /**
|
Chris@0
|
127 * Releases the given lock.
|
Chris@0
|
128 *
|
Chris@0
|
129 * @param string $name
|
Chris@0
|
130 */
|
Chris@0
|
131 public function release($name);
|
Chris@0
|
132
|
Chris@0
|
133 /**
|
Chris@0
|
134 * Releases all locks for the given lock token identifier.
|
Chris@0
|
135 *
|
Chris@0
|
136 * @param string $lockId
|
Chris@0
|
137 * (optional) If none given, remove all locks from the current page.
|
Chris@0
|
138 * Defaults to NULL.
|
Chris@0
|
139 */
|
Chris@0
|
140 public function releaseAll($lockId = NULL);
|
Chris@0
|
141
|
Chris@0
|
142 /**
|
Chris@0
|
143 * Gets the unique page token for locks.
|
Chris@0
|
144 *
|
Chris@0
|
145 * Locks will be wiped out at the end of each page request on a token basis.
|
Chris@0
|
146 *
|
Chris@0
|
147 * @return string
|
Chris@0
|
148 */
|
Chris@0
|
149 public function getLockId();
|
Chris@0
|
150
|
Chris@0
|
151 }
|