Example #1
0
 public function lock($lockName, $method, $timeout = 5)
 {
     // http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
     $key = $this->addQuotes($this->bigintFromLockName($lockName));
     $loop = new WaitConditionLoop(function () use($lockName, $key, $timeout, $method) {
         $res = $this->query("SELECT pg_try_advisory_lock({$key}) AS lockstatus", $method);
         $row = $this->fetchObject($res);
         if ($row->lockstatus === 't') {
             parent::lock($lockName, $method, $timeout);
             // record
             return true;
         }
         return WaitConditionLoop::CONDITION_CONTINUE;
     }, $timeout);
     return $loop->invoke() === $loop::CONDITION_REACHED;
 }
Example #2
0
 /**
  * Acquire an advisory lock on a key string
  *
  * Note that if reentry is enabled, duplicate calls ignore $expiry
  *
  * @param string $key
  * @param int $timeout Lock wait timeout; 0 for non-blocking [optional]
  * @param int $expiry Lock expiry [optional]; 1 day maximum
  * @param string $rclass Allow reentry if set and the current lock used this value
  * @return bool Success
  */
 public function lock($key, $timeout = 6, $expiry = 6, $rclass = '')
 {
     // Avoid deadlocks and allow lock reentry if specified
     if (isset($this->locks[$key])) {
         if ($rclass != '' && $this->locks[$key]['class'] === $rclass) {
             ++$this->locks[$key]['depth'];
             return true;
         } else {
             return false;
         }
     }
     $expiry = min($expiry ?: INF, self::TTL_DAY);
     $loop = new WaitConditionLoop(function () use($key, $timeout, $expiry) {
         $this->clearLastError();
         if ($this->add("{$key}:lock", 1, $expiry)) {
             return true;
             // locked!
         } elseif ($this->getLastError()) {
             return WaitConditionLoop::CONDITION_ABORTED;
             // network partition?
         }
         return WaitConditionLoop::CONDITION_CONTINUE;
     }, $timeout);
     $locked = $loop->invoke() === $loop::CONDITION_REACHED;
     if ($locked) {
         $this->locks[$key] = ['class' => $rclass, 'depth' => 1];
     }
     return $locked;
 }
Example #3
0
 /**
  * @param MemcachedBagOStuff $memc
  * @param array $keys List of keys to acquire
  * @return bool
  */
 protected function acquireMutexes(MemcachedBagOStuff $memc, array $keys)
 {
     $lockedKeys = [];
     // Acquire the keys in lexicographical order, to avoid deadlock problems.
     // If P1 is waiting to acquire a key P2 has, P2 can't also be waiting for a key P1 has.
     sort($keys);
     // Try to quickly loop to acquire the keys, but back off after a few rounds.
     // This reduces memcached spam, especially in the rare case where a server acquires
     // some lock keys and dies without releasing them. Lock keys expire after a few minutes.
     $loop = new WaitConditionLoop(function () use($memc, $keys, &$lockedKeys) {
         foreach (array_diff($keys, $lockedKeys) as $key) {
             if ($memc->add("{$key}:mutex", 1, 180)) {
                 // lock record
                 $lockedKeys[] = $key;
             }
         }
         return array_diff($keys, $lockedKeys) ? WaitConditionLoop::CONDITION_CONTINUE : true;
     }, 3.0);
     $loop->invoke();
     if (count($lockedKeys) != count($keys)) {
         $this->releaseMutexes($memc, $lockedKeys);
         // failed; release what was locked
         return false;
     }
     return true;
 }
 /**
  * Load in previous master positions for the client
  */
 protected function initPositions()
 {
     if ($this->initialized) {
         return;
     }
     $this->initialized = true;
     if ($this->wait) {
         // If there is an expectation to see master positions with a certain min
         // timestamp, then block until they appear, or until a timeout is reached.
         if ($this->waitForPosTime > 0.0) {
             $data = null;
             $loop = new WaitConditionLoop(function () use(&$data) {
                 $data = $this->store->get($this->key);
                 return self::minPosTime($data) >= $this->waitForPosTime ? WaitConditionLoop::CONDITION_REACHED : WaitConditionLoop::CONDITION_CONTINUE;
             }, $this->waitForPosTimeout);
             $result = $loop->invoke();
             $waitedMs = $loop->getLastWaitTime() * 1000.0;
             if ($result == $loop::CONDITION_REACHED) {
                 $msg = "expected and found pos time {$this->waitForPosTime} ({$waitedMs}ms)";
                 $this->logger->debug($msg);
             } else {
                 $msg = "expected but missed pos time {$this->waitForPosTime} ({$waitedMs}ms)";
                 $this->logger->info($msg);
             }
         } else {
             $data = $this->store->get($this->key);
         }
         $this->startupPositions = $data ? $data['positions'] : [];
         $this->logger->info(__METHOD__ . ": key is {$this->key} (read)\n");
     } else {
         $this->startupPositions = [];
         $this->logger->info(__METHOD__ . ": key is {$this->key} (unread)\n");
     }
 }
Example #5
0
 /**
  * Lock the resources at the given abstract paths
  *
  * @param array $pathsByType Map of LockManager::LOCK_* constants to lists of paths
  * @param int $timeout Timeout in seconds (0 means non-blocking) (since 1.21)
  * @return StatusValue
  * @since 1.22
  */
 public final function lockByType(array $pathsByType, $timeout = 0)
 {
     $pathsByType = $this->normalizePathsByType($pathsByType);
     $status = null;
     $loop = new WaitConditionLoop(function () use(&$status, $pathsByType) {
         $status = $this->doLockByType($pathsByType);
         return $status->isOK() ?: WaitConditionLoop::CONDITION_CONTINUE;
     }, $timeout);
     $loop->invoke();
     return $status;
 }