You are here

MemcacheLockBackend.php in Memcache API and Integration 8.2

File

src/Lock/MemcacheLockBackend.php
View source
<?php

namespace Drupal\memcache\Lock;

use Drupal\Core\Lock\LockBackendAbstract;
use Drupal\memcache\DrupalMemcacheInterface;

/**
 * Defines a Memcache lock backend.
 */
class MemcacheLockBackend extends LockBackendAbstract {

  /**
   * An array of currently acquired locks.
   *
   * @var array
   */
  protected $locks = [];

  /**
   * The bin name for this lock.
   *
   * @var string
   */
  protected $bin;

  /**
   * The memcache wrapper object.
   *
   * @var \Drupal\memcache\DrupalMemcacheInterface
   */
  protected $memcache;

  /**
   * Constructs a new MemcacheLockBackend.
   *
   * @param string $bin
   *   The bin name for this lock.
   * @param \Drupal\memcache\DrupalMemcacheInterface $memcache
   *   The memcache wrapper object.
   */
  public function __construct($bin, DrupalMemcacheInterface $memcache) {
    $this->bin = $bin;
    $this->memcache = $memcache;

    // __destruct() is causing problems with garbage collections, register a
    // shutdown function instead.
    drupal_register_shutdown_function([
      $this,
      'releaseAll',
    ]);
  }

  /**
   * {@inheritdoc}
   */
  public function acquire($name, $timeout = 30.0) {

    // Ensure that the timeout is at least 1 sec. This is a limitation imposed
    // by memcached.
    $timeout = (int) max($timeout, 1);
    $lock_id = $this
      ->getLockId();
    if (isset($this->locks[$name])) {

      // Try to extend the expiration of a lock we already acquired.
      $success = !$this
        ->lockMayBeAvailable($name) && $this->memcache
        ->set($name, $lock_id, $timeout);
      if (!$success) {

        // The lock was broken.
        unset($this->locks[$name]);
      }
      return $success;
    }
    else {
      if ($this
        ->lockMayBeAvailable($name)) {
        $success = $this->memcache
          ->add($name, $lock_id, $timeout);
        if (!$success) {
          return FALSE;
        }

        // We track all acquired locks in the global variable, if successful.
        $this->locks[$name] = TRUE;
      }
      else {
        return FALSE;
      }
    }
    return isset($this->locks[$name]);
  }

  /**
   * {@inheritdoc}
   */
  public function lockMayBeAvailable($name) {
    return !$this->memcache
      ->get($name);
  }

  /**
   * {@inheritdoc}
   */
  public function release($name) {
    $this->memcache
      ->delete($name);

    // We unset unconditionally since caller assumes lock is released anyway.
    unset($this->locks[$name]);
  }

  /**
   * {@inheritdoc}
   */
  public function releaseAll($lock_id = NULL) {
    if (empty($lock_id)) {
      $lock_id = $this
        ->getLockId();
    }
    foreach ($this->locks as $name => $id) {
      $value = $this->memcache
        ->get($name);
      if ($value == $lock_id) {
        $this->memcache
          ->delete($name);
      }
    }
    $this->locks = [];
  }

}

Classes

Namesort descending Description
MemcacheLockBackend Defines a Memcache lock backend.