You are here

public function Redis_Lock_Backend_PhpRedis::lockAcquire in Redis 7

Same name and namespace in other branches
  1. 7.2 lib/Redis/Lock/Backend/PhpRedis.php \Redis_Lock_Backend_PhpRedis::lockAcquire()

Acquire lock.

Parameters

string $name: Lock name.

float $timeout = 30.0: (optional) Lock lifetime in seconds.

Return value

bool

Overrides Redis_Lock_Backend_Interface::lockAcquire

File

lib/Redis/Lock/Backend/PhpRedis.php, line 8

Class

Redis_Lock_Backend_PhpRedis
Predis lock backend implementation.

Code

public function lockAcquire($name, $timeout = 30.0) {
  $client = Redis_Client::getClient();
  $key = 'lock:' . $name;
  $keyOwn = $key . ':owner';
  $id = $this
    ->getLockId();

  // Insure that the timeout is at least 1 second, we cannot do otherwise with
  // Redis, this is a minor change to the function signature, but in real life
  // nobody will notice with so short duration.
  $timeout = ceil(max($timeout, 1));

  // If we already have the lock, check for his owner and attempt a new EXPIRE
  // command on it.
  if (isset($this->_locks[$name])) {

    // Create a new transaction, for atomicity.
    $client
      ->watch($keyOwn);

    // Global tells us we are the owner, but in real life it could have expired
    // and another process could have taken it, check that.
    if ($client
      ->get($keyOwn) != $id) {

      // Explicit UNWATCH we are not going to run the MULTI/EXEC block.
      $client
        ->unwatch($keyOwn);
      unset($this->_locks[$name]);
      return FALSE;
    }
    $result = $client
      ->multi()
      ->expire($key, $timeout)
      ->setex($keyOwn, $timeout, $id)
      ->exec();

    // Did it broke?
    if (FALSE === $result || 1 != $result[1]) {
      unset($this->_locks[$name]);
      return FALSE;
    }
    return $this->_locks[$name] = TRUE;
  }
  else {
    $client
      ->watch($key);
    $result = $client
      ->multi()
      ->incr($key)
      ->expire($key, $timeout)
      ->setex($key . ':owner', $timeout, $id)
      ->exec();

    // If another client modified the $key value, transaction will be discarded
    // $result will be set to FALSE. This means atomicity have been broken and
    // the other client took the lock instead of us. The another condition is
    // the INCR result test. If we succeeded in incrementing the counter but
    // that counter was more than 0, then someone else already have the lock
    // case in which we cannot proceed.
    if (FALSE === $result || 1 != $result[0]) {
      return FALSE;
    }

    // Register the lock.
    return $this->_locks[$name] = TRUE;
  }
  return FALSE;
}