summaryrefslogtreecommitdiff
path: root/includes/lock.inc
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2011-05-13 22:34:19 -0400
committerDries Buytaert <dries@buytaert.net>2011-05-13 22:34:19 -0400
commit7d1ae1167ddf733278841824aa0df7dab2f34661 (patch)
treed7cd5db47e8d61eb07e4fe5f18dbf55b2f3c3484 /includes/lock.inc
parent33e746fc34ff2af303aca27b11c65a638bbc11a9 (diff)
downloadbrdo-7d1ae1167ddf733278841824aa0df7dab2f34661.tar.gz
brdo-7d1ae1167ddf733278841824aa0df7dab2f34661.tar.bz2
- Patch #802856 by catch, pillarsdotnet: make lock_wait() wait less.
Diffstat (limited to 'includes/lock.inc')
-rw-r--r--includes/lock.inc28
1 files changed, 24 insertions, 4 deletions
diff --git a/includes/lock.inc b/includes/lock.inc
index 2eb7b9a90..42f1906f2 100644
--- a/includes/lock.inc
+++ b/includes/lock.inc
@@ -187,7 +187,7 @@ function lock_may_be_available($name) {
* lock. This will block further execution until the lock is available or the
* specified delay in seconds is reached. This should not be used with locks
* that are acquired very frequently, since the lock is likely to be acquired
- * again by a different request during the sleep().
+ * again by a different request while waiting.
*
* @param $name
* The name of the lock.
@@ -198,12 +198,32 @@ function lock_may_be_available($name) {
* TRUE if the lock holds, FALSE if it is available.
*/
function lock_wait($name, $delay = 30) {
- $delay = (int) $delay;
- while ($delay--) {
+ // Pause the process for short periods between calling
+ // lock_may_be_available(). This prevents hitting the database with constant
+ // database queries while waiting, which could lead to performance issues.
+ // However, if the wait period is too long, there is the potential for a
+ // large number of processes to be blocked waiting for a lock, especially
+ // if the item being rebuilt is commonly requested. To address both of these
+ // concerns, begin waiting for 25ms, then add 25ms to the wait period each
+ // time until it reaches 500ms. After this point polling will continue every
+ // 500ms until $delay is reached.
+
+ // $delay is passed in seconds, but we will be using usleep(), which takes
+ // microseconds as a parameter. Multiply it by 1 million so that all
+ // further numbers are equivalent.
+ $delay = (int) $delay * 1000000;
+
+ // Begin sleeping at 25ms.
+ $sleep = 25000;
+ while ($delay > 0) {
// This function should only be called by a request that failed to get a
// lock, so we sleep first to give the parallel request a chance to finish
// and release the lock.
- sleep(1);
+ usleep($sleep);
+ // After each sleep, increase the value of $sleep until it reaches
+ // 500ms, to reduce the potential for a lock stampede.
+ $delay = $delay - $sleep;
+ $sleep = min(500000, $sleep + 25000, $delay);
if (lock_may_be_available($name)) {
// No longer need to wait.
return FALSE;