Index: memcache-lock.inc =================================================================== RCS file: memcache-lock.inc diff -N memcache-lock.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ memcache-lock.inc 23 Jun 2010 07:57:03 -0000 @@ -0,0 +1,122 @@ +lock_expire = $expire; + + // need direct access to memcache object, since we need to 'add' later. See http://drupal.org/node239798 + $mc = dmemcache_object('semaphore'); + $key = dmemcache_key($name, 'semaphore'); + $result = $mc->get($key); + if ($result && $locks[$name] > $now) { + if ($mc->set($key, $lock, FALSE, $timeout)) { + $locks[$name] = $expire; + } + } + else if ($mc->add($key, $lock, FALSE, $timeout)) { + $locks[$name] = $expire; + } + else { + // could not acquire lock + unset($locks[$name]); + } + + return isset($locks[$name]); +} + +/** + * Check if lock acquired by a different process may be available. + * + * If an existing lock has expired, it is removed. + * + * @param $name + * The name of the lock. + * @return + * TRUE if there is no lock or it was removed, FALSE otherwise. + */ +function lock_may_be_available($name) { + return !dmemcache_get($name, 'semaphore'); +} + +/** + * Wait for a lock to be available. + * + * This function may be called in a request that fails to acquire a desired + * 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(). + * + * @param $name + * The name of the lock. + * @param $delay + * The maximum number of seconds to wait, as an integer. + * @return + * TRUE if the lock holds, FALSE if it is available. + */ +function lock_wait($name, $delay = 30) { + $delay = (int) $delay; + while ($delay--) { + // 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); + 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]); +} +