Error message

You are browsing documentation for drupal 7.x, which is not supported anymore. Read the updated version of this page for drupal 11.x (the latest version).

class DrupalDatabaseCache

Defines a default cache implementation.

This is Drupal's default cache implementation. It uses the database to store cached data. Each cache bin corresponds to a database table by the same name.

Hierarchy

Expanded class hierarchy of DrupalDatabaseCache

1 string reference to 'DrupalDatabaseCache'
_cache_get_object in includes/cache.inc
Gets the cache object for a cache bin.

File

includes/cache.inc, line 322

View source
class DrupalDatabaseCache  implements DrupalCacheInterface {
 protected $bin;
 
 /**
 * Constructs a DrupalDatabaseCache object.
 *
 * @param $bin
 * The cache bin for which the object is created.
 */
 function __construct($bin) {
 $this->bin  = $bin;
 }
 
 /**
 * Implements DrupalCacheInterface::get().
 */
 function get($cid) {
 $cids = array(
 $cid,
 );
 $cache = $this->getMultiple ($cids);
 return reset ($cache);
 }
 
 /**
 * Implements DrupalCacheInterface::getMultiple().
 */
 function getMultiple(&$cids) {
 try {
 // Garbage collection necessary when enforcing a minimum cache lifetime.
 $this->garbageCollection ($this->bin );
 // When serving cached pages, the overhead of using db_select() was found
 // to add around 30% overhead to the request. Since $this->bin is a
 // variable, this means the call to db_query() here uses a concatenated
 // string. This is highly discouraged under any other circumstances, and
 // is used here only due to the performance overhead we would incur
 // otherwise. When serving an uncached page, the overhead of using
 // db_select() is a much smaller proportion of the request.
 $result = db_query ('SELECT cid, data, created, expire, serialized FROM {' . db_escape_table ($this->bin ) . '} WHERE cid IN (:cids)', array(
 ':cids' => $cids,
 ));
 $cache = array();
 foreach ($result as $item) {
 $item = $this->prepareItem ($item);
 if ($item) {
 $cache[$item->cid ] = $item;
 }
 }
 $cids = array_diff ($cids, array_keys ($cache));
 return $cache;
 } catch (Exception $e) {
 // If the database is never going to be available, cache requests should
 // return FALSE in order to allow exception handling to occur.
 return array();
 }
 }
 
 /**
 * Garbage collection for get() and getMultiple().
 *
 * @param $bin
 * The bin being requested.
 */
 protected function garbageCollection() {
 $cache_lifetime = variable_get ('cache_lifetime', 0);
 // 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_expiration'])) {
 $expire = REQUEST_TIME  - $cache_lifetime;
 foreach ($_SESSION['cache_expiration'] as $bin => $timestamp) {
 if ($timestamp < $expire) {
 unset($_SESSION['cache_expiration'][$bin]);
 }
 }
 if (!$_SESSION['cache_expiration']) {
 unset($_SESSION['cache_expiration']);
 }
 }
 // Garbage collection of temporary items is only necessary when enforcing
 // a minimum cache lifetime.
 if (!$cache_lifetime) {
 return;
 }
 // When cache lifetime is in force, avoid running garbage collection too
 // often since this will remove temporary cache items indiscriminately.
 $cache_flush = variable_get ('cache_flush_' . $this->bin , 0);
 if ($cache_flush && $cache_flush + $cache_lifetime <= REQUEST_TIME ) {
 // Reset the variable immediately to prevent a meltdown in heavy load situations.
 variable_set ('cache_flush_' . $this->bin , 0);
 // Time to flush old cache data
 db_delete ($this->bin )
 ->condition ('expire', CACHE_PERMANENT , '<>')
 ->condition ('expire', $cache_flush, '<=')
 ->execute ();
 }
 }
 
 /**
 * Prepares a cached item.
 *
 * Checks that items are either permanent or did not expire, and unserializes
 * data as appropriate.
 *
 * @param $cache
 * An item loaded from cache_get() or cache_get_multiple().
 *
 * @return
 * The item with data unserialized as appropriate or FALSE if there is no
 * valid item to load.
 */
 protected function prepareItem($cache) {
 global $user;
 if (!isset($cache->data )) {
 return FALSE;
 }
 // If the cached data is temporary and subject to a per-user minimum
 // lifetime, compare the cache entry timestamp with the user session
 // cache_expiration timestamp. If the cache entry is too old, ignore it.
 if ($cache->expire != CACHE_PERMANENT  && variable_get ('cache_lifetime', 0) && isset($_SESSION['cache_expiration'][$this->bin ]) && $_SESSION['cache_expiration'][$this->bin ] > $cache->created) {
 // Ignore cache data that is too old and thus not valid for this user.
 return FALSE;
 }
 // If the data is permanent or not subject to a minimum cache lifetime,
 // unserialize and return the cached data.
 if ($cache->serialized) {
 $cache->data  = unserialize ($cache->data );
 }
 return $cache;
 }
 
 /**
 * Implements DrupalCacheInterface::set().
 */
 function set($cid, $data, $expire = CACHE_PERMANENT ) {
 $fields = array(
 'serialized' => 0,
 'created' => REQUEST_TIME ,
 'expire' => $expire,
 );
 if (!is_string ($data)) {
 $fields['data'] = serialize ($data);
 $fields['serialized'] = 1;
 }
 else {
 $fields['data'] = $data;
 $fields['serialized'] = 0;
 }
 try {
 db_merge ($this->bin )
 ->key (array(
 'cid' => $cid,
 ))
 ->fields ($fields)
 ->execute ();
 } catch (Exception $e) {
 // The database may not be available, so we'll ignore cache_set requests.
 }
 }
 
 /**
 * Implements DrupalCacheInterface::clear().
 */
 function clear($cid = NULL, $wildcard = FALSE) {
 global $user;
 if (empty($cid)) {
 if (variable_get ('cache_lifetime', 0)) {
 // We store the time in the current user's session. We then simulate
 // that the cache was flushed for this user by not returning cached
 // data that was cached before the timestamp.
 $_SESSION['cache_expiration'][$this->bin ] = REQUEST_TIME ;
 $cache_flush = variable_get ('cache_flush_' . $this->bin , 0);
 if ($cache_flush == 0) {
 // This is the first request to clear the cache, start a timer.
 variable_set ('cache_flush_' . $this->bin , REQUEST_TIME );
 }
 elseif (REQUEST_TIME  > $cache_flush + variable_get ('cache_lifetime', 0)) {
 // Clear the cache for everyone, cache_lifetime seconds have
 // passed since the first request to clear the cache.
 db_delete ($this->bin )
 ->condition ('expire', CACHE_PERMANENT , '<>')
 ->condition ('expire', REQUEST_TIME , '<')
 ->execute ();
 variable_set ('cache_flush_' . $this->bin , 0);
 }
 }
 else {
 // No minimum cache lifetime, flush all temporary cache entries now.
 db_delete ($this->bin )
 ->condition ('expire', CACHE_PERMANENT , '<>')
 ->condition ('expire', REQUEST_TIME , '<')
 ->execute ();
 }
 }
 else {
 if ($wildcard) {
 if ($cid == '*') {
 // Check if $this->bin is a cache table before truncating. Other
 // cache_clear_all() operations throw a PDO error in this situation,
 // so we don't need to verify them first. This ensures that non-cache
 // tables cannot be truncated accidentally.
 if ($this->isValidBin ()) {
 db_truncate ($this->bin )
 ->execute ();
 }
 else {
 throw new Exception(t ('Invalid or missing cache bin specified: %bin', array(
 '%bin' => $this->bin ,
 )));
 }
 }
 else {
 db_delete ($this->bin )
 ->condition ('cid', db_like ($cid) . '%', 'LIKE')
 ->execute ();
 }
 }
 elseif (is_array ($cid)) {
 // Delete in chunks when a large array is passed.
 do {
 db_delete ($this->bin )
 ->condition ('cid', array_splice ($cid, 0, 1000), 'IN')
 ->execute ();
 } while (count ($cid));
 }
 else {
 db_delete ($this->bin )
 ->condition ('cid', $cid)
 ->execute ();
 }
 }
 }
 
 /**
 * Implements DrupalCacheInterface::isEmpty().
 */
 function isEmpty() {
 $this->garbageCollection ();
 $query = db_select ($this->bin );
 $query->addExpression ('1');
 $result = $query->range (0, 1)
 ->execute ()
 ->fetchField ();
 return empty($result);
 }
 
 /**
 * Checks if $this->bin represents a valid cache table.
 *
 * This check is required to ensure that non-cache tables are not truncated
 * accidentally when calling cache_clear_all().
 *
 * @return boolean
 */
 function isValidBin() {
 if ($this->bin  == 'cache' || substr ($this->bin , 0, 6) == 'cache_') {
 // Skip schema check for bins with standard table names.
 return TRUE;
 }
 // These fields are required for any cache table.
 $fields = array(
 'cid',
 'data',
 'expire',
 'created',
 'serialized',
 );
 // Load the table schema.
 $schema = drupal_get_schema ($this->bin );
 // Confirm that all fields are present.
 return isset($schema['fields']) && !array_diff ($fields, array_keys ($schema['fields']));
 }
}

Members

Title Sort descending Modifiers Object type Summary Overriden Title Overrides
DrupalDatabaseCache::$bin protected property
DrupalDatabaseCache::clear function Implements DrupalCacheInterface::clear(). Overrides DrupalCacheInterface::clear 1
DrupalDatabaseCache::garbageCollection protected function Garbage collection for get() and getMultiple().
DrupalDatabaseCache::get function Implements DrupalCacheInterface::get(). Overrides DrupalCacheInterface::get 1
DrupalDatabaseCache::getMultiple function Implements DrupalCacheInterface::getMultiple(). Overrides DrupalCacheInterface::getMultiple 1
DrupalDatabaseCache::isEmpty function Implements DrupalCacheInterface::isEmpty(). Overrides DrupalCacheInterface::isEmpty 1
DrupalDatabaseCache::isValidBin function Checks if $this-&gt;bin represents a valid cache table.
DrupalDatabaseCache::prepareItem protected function Prepares a cached item.
DrupalDatabaseCache::set function Implements DrupalCacheInterface::set(). Overrides DrupalCacheInterface::set 1
DrupalDatabaseCache::__construct function Constructs a DrupalDatabaseCache object.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.