You are here

public function Redis_Lock_Backend_PhpRedis::lockAcquire in Redis 7.2

Same name and namespace in other branches
  1. 7 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 11

Class

Redis_Lock_Backend_PhpRedis
Predis lock backend implementation.

Code

public function lockAcquire($name, $timeout = 30.0) {
  $client = Redis_Client::getClient();
  $key = $this
    ->getKey($name);
  $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($key);

    // 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($key) != $id) {

      // Explicit UNWATCH we are not going to run the MULTI/EXEC block.
      $client
        ->unwatch();
      unset($this->_locks[$name]);
      return FALSE;
    }

    // See https://github.com/nicolasff/phpredis#watch-unwatch
    // MULTI and other commands can fail, so we can't chain calls.
    if (FALSE !== ($result = $client
      ->multi())) {
      $client
        ->setex($key, $timeout, $id);
      $result = $client
        ->exec();
    }

    // Did it broke?
    if (FALSE === $result) {
      unset($this->_locks[$name]);

      // Explicit transaction release which also frees the WATCH'ed key.
      $client
        ->discard();
      return FALSE;
    }
    return $this->_locks[$name] = TRUE;
  }
  else {
    $client
      ->watch($key);
    $owner = $client
      ->get($key);

    // If the $key is set they lock is not available
    if (!empty($owner) && $id != $owner) {
      $client
        ->unwatch();
      return FALSE;
    }

    // See https://github.com/nicolasff/phpredis#watch-unwatch
    // MULTI and other commands can fail, so we can't chain calls.
    if (FALSE !== ($result = $client
      ->multi())) {
      $client
        ->setex($key, $timeout, $id);
      $result
        ->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.
    if (FALSE === $result) {

      // Explicit transaction release which also frees the WATCH'ed key.
      $client
        ->discard();
      return FALSE;
    }

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