You are here

public function Redis_Lock_Backend_Predis::lockAcquire in Redis 7.2

Same name and namespace in other branches
  1. 7 lib/Redis/Lock/Backend/Predis.php \Redis_Lock_Backend_Predis::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/Predis.php, line 11

Class

Redis_Lock_Backend_Predis
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) {
      $client
        ->unwatch();
      unset($this->_locks[$name]);
      return FALSE;
    }
    switch (Redis_Client_Predis::getPredisVersionMajor()) {
      case 0:
        $replies = $client
          ->pipeline(function ($pipe) use ($key, $timeout, $id) {
          $pipe
            ->multi();
          $pipe
            ->setex($key, $timeout, $id);
          $pipe
            ->exec();
        });
        break;
      default:
        $replies = $client
          ->transaction(function ($pipe) use ($key, $timeout, $id) {
          $pipe
            ->setex($key, $timeout, $id);
        });
        break;
    }
    $execReply = array_pop($replies);
    if (FALSE === $execReply[0]) {
      unset($this->_locks[$name]);
      return FALSE;
    }
    return TRUE;
  }
  else {
    $client
      ->watch($key);
    $owner = $client
      ->get($key);
    if (!empty($owner) && $owner != $id) {
      $client
        ->unwatch();
      unset($this->_locks[$name]);
      return FALSE;
    }
    $replies = $client
      ->pipeline(function ($pipe) use ($key, $timeout, $id) {
      $pipe
        ->multi();
      $pipe
        ->setex($key, $timeout, $id);
      $pipe
        ->exec();
    });
    $execReply = array_pop($replies);

    // 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.
    // EXPIRE and SETEX won't return something here, EXEC return is index 0
    // This was determined debugging, seems to be Predis specific.
    if (FALSE === $execReply[0]) {
      return FALSE;
    }

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