You are here

function cache_get in Memcache API and Integration 6

Same name in this branch
  1. 6 memcache.db.inc \cache_get()
  2. 6 memcache.inc \cache_get()
Same name and namespace in other branches
  1. 5.2 memcache.db.inc \cache_get()
  2. 5.2 memcache.inc \cache_get()
  3. 5 memcache.db.inc \cache_get()
  4. 5 memcache.inc \cache_get()

Return data from the persistent cache.

Data may be stored as either plain text or as serialized data. cache_get() will automatically return unserialized objects and arrays.

Parameters

$cid: The cache ID of the data to retrieve.

$table: The table $table to store the data in. Valid core values are 'cache_filter', 'cache_menu', 'cache_page', or 'cache' for the default cache.

6 calls to cache_get()
MemCacheSavingCase::checkVariable in tests/memcache.test
MemCacheSavingCase::testObject in tests/memcache.test
Test the saving and restoring of an object.
MemcacheTestCase::assertCacheRemoved in tests/memcache.test
Assert or a cache entry has been removed.
MemcacheTestCase::checkCacheExists in tests/memcache.test
Check whether or not a cache entry exists.
memcache_requirements in ./memcache.install
Implements hook_requirements().

... See full list

File

./memcache.inc, line 33

Code

function cache_get($cid, $table = 'cache') {

  // Handle excluded bins first.
  $bins = variable_get('memcache_bins', array());
  if (!is_null($table) && isset($bins[$table]) && $bins[$table] == 'database') {
    return _cache_get($cid, $table);
  }

  // Clean-up the per-user cache expiration session data, so that the session
  // handler can properly clean-up the session data for anonymous users.
  if (isset($_SESSION['cache_flush'])) {
    $expire = $_SERVER['REQUEST_TIME'] - variable_get('cache_lifetime', 0);
    foreach ($_SESSION['cache_flush'] as $bin => $timestamp) {
      if ($timestamp < $expire) {
        unset($_SESSION['cache_flush'][$bin]);
      }
    }
    if (!$_SESSION['cache_flush']) {
      unset($_SESSION['cache_flush']);
    }
  }

  // Retrieve the item from the cache.
  $cache = dmemcache_get($cid, $table);

  // Set up common variables.
  $cache_flush = variable_get("cache_flush_{$table}", 0);
  $cache_content_flush = variable_get("cache_content_flush_{$table}", 0);
  $cache_tables = isset($_SESSION['cache_flush']) ? $_SESSION['cache_flush'] : NULL;
  $cache_lifetime = variable_get('cache_lifetime', 0);
  $wildcard_flushes = variable_get('memcache_wildcard_flushes', array());
  $wildcard_invalidate = variable_get('memcache_wildcard_invalidate', MEMCACHE_WILDCARD_INVALIDATE);
  if (is_object($cache)) {

    // Items that have expired are invalid.
    if (isset($cache->expire) && $cache->expire !== CACHE_PERMANENT && $cache->expire <= $_SERVER['REQUEST_TIME']) {

      // 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) && memcache_stampede_protected($cid, $table)) {

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

      // Cache item expired, return FALSE.
      $cache = FALSE;
    }
    else {
      $flushes = isset($cache->flushes) ? (int) $cache->flushes : 0;
      $recorded_flushes = memcache_wildcard_flushes($cid, $table);
      if ($flushes < $recorded_flushes) {
        $cache = FALSE;
      }

      // If wildcards are cleared by a partial memcache flush or eviction
      // then it is possible for $cache->flushes to be greater than the return
      // of memcache_wildcard_flushes().
      if ($flushes > $recorded_flushes) {

        // Delete the cache item entirely, it will be set again with the correct
        // number of flushes.
        dmemcache_delete($cid, $table);
        $cache = FALSE;
      }
    }
  }
  else {
    $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) && memcache_stampede_protected($cid, $table) && !lock_acquire("memcache_{$cid}:{$table}", 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 sempahore value by 3 (5 seconds).
        lock_wait("memcache_{$cid}:{$table}", variable_get('memcache_stampede_wait_time', 5));
        return cache_get($cid, $table);
      }
    }
  }

  // Clean up $_SESSION['cache_flush'] variable array if it is older than
  // the minimum cache lifetime, since after that the $cache_flush variable
  // will take over.
  if (is_array($cache_tables) && !empty($cache_tables) && $cache_lifetime) {

    // Expire the $_SESSION['cache_flush'] variable array if it is older than
    // the minimum cache lifetime, since after that the $cache_flush variable
    // will take over.
    if (max($cache_tables) < $_SERVER['REQUEST_TIME'] - $cache_lifetime) {
      unset($_SESSION['cache_flush']);
      $cache_tables = NULL;
    }
  }
  return $cache;
}