lock_id = _lock_id(); $lock->lock_expire = $expire; // need direct access to memcache object, since we need to 'add' later $mc = dmemcache_object('semaphore'); $key = dmemcache_key($name, 'semaphore'); $result = $mc->get($key); if (isset($locks[$name])) { if ($result && $result->lock_id == _lock_id()) { // renew if we have at least 1 second more. This is required to ensure atomic renew. $success = ($now > $result->lock_expire + 1) && (bool)$mc->set($name, $lock, FALSE, $timeout); // NOTE: if we do not have enough time, then $locks[$name] is not updated, and might become stale } else { // The lock was broken unset($locks[$name]); $success = FALSE; } return $success; } else if ($mc->add($key, $lock, FALSE, $timeout)) { $locks[$name] = TRUE; } 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 (bool)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; if (dmemcache_delete($name, 'semaphore')) { unset($locks[$name]); } }