You are here

protected function MemCacheDrupal::valid in Memcache API and Integration 7

Checks if a retrieved cache item is valid.

Parameters

string $cid: The cache id of the item

mixed $cache: The cache item, which will be updated if needed.

Return value

bool Whether the item is valid.

2 calls to MemCacheDrupal::valid()
MemCacheDrupal::get in ./memcache.inc
Implements DrupalCacheInterface::get().
MemCacheDrupal::getMultiple in ./memcache.inc
Implements DrupalCacheInterface::getMultiple().

File

./memcache.inc, line 123

Class

MemCacheDrupal
Implementation of cache.inc with memcache logic included

Code

protected function valid($cid, &$cache) {
  if ($cache) {

    // Legacy support
    if (!isset($cache->expire)) {
      $cache->expire = CACHE_TEMPORARY;
    }
    if (!isset($cache->created)) {
      $cache->created = 0;
    }

    // Session storage is used to simulate a cache clear for the current user
    // when cache_lifetime is greater than 0.
    $cache_tables = isset($_SESSION['cache_flush']) ? $_SESSION['cache_flush'] : NULL;

    // Items that have expired are invalid. This includes CACHE_TEMPORARY
    // items that were set prior to the last garbage collection, and
    // timestamp set items.
    //
    // Test whether this cache has been garbage collected (general cache
    // flush) longer ago than the cache_lifetime setting.
    $cache_garbage_collected = $cache->created + $this->cache_lifetime <= $this->cache_temporary_flush;

    // Depending on value of memcache_expire_wait_gc, test if a timestamp
    // cached item has expired:
    // If memcache_expired_wait_gc is true, this includes any timestamp items
    // that expired more than cache_lifetime seconds before the last garbage
    // collection. If memcache_expire_wait_gc is false, this includes any
    // items that expired before present time.
    $cache_timestamp_expired = variable_get('memcache_expire_wait_gc', FALSE) ? $cache->expire + $this->cache_lifetime <= $this->cache_temporary_flush : $cache->expire <= REQUEST_TIME;

    // Test for expired items.
    if ($cache->expire == CACHE_TEMPORARY && $cache_garbage_collected || $cache->expire > 0 && $cache_timestamp_expired) {

      // If the memcache_stampede_protection variable is set, allow one
      // process to rebuild the cache entry while serving expired content to
      // the rest. Note that core happily returns expired cache items as valid
      // and relies on cron to expire them, but this is mostly reliant on its
      // use of CACHE_TEMPORARY which does not map well to memcache.
      // @see http://drupal.org/node/534092
      if (variable_get('memcache_stampede_protection', FALSE)) {

        // The process that acquires the lock will get a cache miss, all
        // others will get a cache hit.
        if ($this
          ->lockInit() && $this
          ->stampedeProtected($cid) && lock_acquire("memcache_{$cid}:{$this->bin}", variable_get('memcache_stampede_semaphore', 15))) {
          $cache = FALSE;
        }
      }
      else {
        $cache = FALSE;
      }
    }
    elseif ($cache->created <= $this->cache_flush) {
      $cache = FALSE;
    }
    elseif ($cache->expire != CACHE_PERMANENT && $cache->created + $this->cache_lifetime <= $this->cache_content_flush) {
      $cache = FALSE;
    }
    elseif ($cache->expire != CACHE_PERMANENT && is_array($cache_tables) && isset($cache_tables[$this->bin]) && $cache_tables[$this->bin] >= $cache->created) {

      // Cache item expired, return FALSE.
      $cache = FALSE;
    }
    else {
      if (!$this
        ->wildcardValid($cid, $cache)) {
        $cache = FALSE;
      }
    }
  }

  // On cache misses, attempt to avoid stampedes when the
  // memcache_stampede_protection variable is enabled.
  if (!$cache) {
    if (variable_get('memcache_stampede_protection', FALSE) && $this
      ->lockInit() && $this
      ->stampedeProtected($cid) && !lock_acquire("memcache_{$cid}:{$this->bin}", variable_get('memcache_stampede_semaphore', 15))) {

      // Prevent any single request from waiting more than three times due to
      // stampede protection. By default this is a maximum total wait of 15
      // seconds. This accounts for two possibilities - a cache and lock miss
      // more than once for the same item. Or a cache and lock miss for
      // different items during the same request.
      // @todo: it would be better to base this on time waited rather than
      // number of waits, but the lock API does not currently provide this
      // information. Currently the limit will kick in for three waits of 25ms
      // or three waits of 5000ms.
      static $lock_count = 0;
      $lock_count++;
      if ($lock_count <= variable_get('memcache_stampede_wait_limit', 3)) {

        // The memcache_stampede_semaphore variable was used in previous
        // releases of memcache, but the max_wait variable was not, so by
        // default divide the semaphore value by 3 (5 seconds).
        lock_wait("memcache_{$cid}:{$this->bin}", variable_get('memcache_stampede_wait_time', 5));
        $cache = $this
          ->get($cid);
      }
    }
  }
  $valid = (bool) $cache;
  if (variable_get('memcache_pagecache_header', FALSE) && $this->bin == 'cache_page') {

    // Per RFC-6648, don't start with X-
    $header = t('Drupal-Pagecache-Memcache: !status', array(
      '!status' => $valid ? t('HIT') : t('MISS'),
    ));
    if ($valid) {
      $header .= t(', age=!age', array(
        '!age' => REQUEST_TIME - $cache->created,
      ));
    }
    header($header);
  }
  return $valid;
}