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. 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 (!dmemcache_get($name, 'semaphore')) { // No longer need to wait. return FALSE; } } // The caller must still wait longer to get the lock. return TRUE; } /** * Release a lock previously acquired by lock_acquire(). * * This will release the named lock if it is still held by the current request. * * @param $name * The name of the lock. */ function lock_release($name) { global $locks; dmemcache_delete($name, 'semaphore'); // We unset unconditionally since caller assumes lock is released anyway. unset($locks[$name]); } /** * Generate a unique identifier for locks generated during this request. */ function _lock_id() { static $lock_id; if (!isset($lock_id)) { $lock_id = uniqid(mt_rand(), TRUE); // We only register a shutdown function if a lock is used. register_shutdown_function('lock_release_all', $lock_id); } return $lock_id; } /** * Release all locks acquired by this request. */ function lock_release_all($lock_id) { global $locks; foreach ($locks as $name => $id) { $value = dmemcache_get($name, 'semaphore'); if ($value == $id) { dmemcache_delete($name, 'semaphore'); } } }