From e5c66be406f22fb73a837c1d5e58dc57c5aa6ad0 Mon Sep 17 00:00:00 2001 From: Bob Vincent Date: Mon, 15 Aug 2011 08:59:35 -0400 Subject: [PATCH] Issue #81461: Clean up the cache API. --- includes/cache-install.inc | 10 ++ includes/cache.inc | 214 ++++++++++++++++++++++++++++--------------- 2 files changed, 149 insertions(+), 75 deletions(-) diff --git a/includes/cache-install.inc b/includes/cache-install.inc index d9bb0f92ea5be05e4ddb53931dd4e6413af7da7c..8bcf8b7b1c1738cf891e37c4ff9e50f899b2aef5 100644 --- a/includes/cache-install.inc +++ b/includes/cache-install.inc @@ -26,6 +26,16 @@ class DrupalFakeCache extends DrupalDatabaseCache implements DrupalCacheInterfac function set($cid, $data, $expire = CACHE_PERMANENT) { } + function deletePrefix($cid) { + try { + if (class_exists('Database')) { + parent::deletePrefix($cid); + } + } + catch (Exception $e) { + } + } + function clear($cid = NULL, $wildcard = FALSE) { // If there is a database cache, attempt to clear it whenever possible. The // reason for doing this is that the database cache can accumulate data diff --git a/includes/cache.inc b/includes/cache.inc index 8666874ac6250efd71ec4ab873e6f0b39ada09b0..dcec3bc610dded36b77dfa90c9f8f112fd9e2a34 100644 --- a/includes/cache.inc +++ b/includes/cache.inc @@ -1,7 +1,7 @@ get($cid); + return cache($bin)->get($cid); } /** @@ -61,7 +61,7 @@ function cache_get($cid, $bin = 'cache') { * An array of the items successfully returned from cache indexed by cid. */ function cache_get_multiple(array &$cids, $bin = 'cache') { - return _cache_get_object($bin)->getMultiple($cids); + return cache($bin)->getMultiple($cids); } /** @@ -134,7 +134,21 @@ function cache_get_multiple(array &$cids, $bin = 'cache') { * the given time, after which it behaves like CACHE_TEMPORARY. */ function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT) { - return _cache_get_object($bin)->set($cid, $data, $expire); + return cache($bin)->set($cid, $data, $expire); +} + +/** + * Flush temporary items from cache. + * + * @todo: this should not be hard-coded to the block and page caches. + */ +function cache_flush_temporary() { + // Clear the block cache first, so stale data will + // not end up in the page cache. + if (module_exists('block')) { + cache('cache_block')->flushTemporary(); + } + cache('cache_page')->flushTemporary(); } /** @@ -158,15 +172,10 @@ function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT) { */ function cache_clear_all($cid = NULL, $bin = NULL, $wildcard = FALSE) { if (!isset($cid) && !isset($bin)) { - // Clear the block cache first, so stale data will - // not end up in the page cache. - if (module_exists('block')) { - cache_clear_all(NULL, 'cache_block'); - } - cache_clear_all(NULL, 'cache_page'); + cache_flush_temporary(); return; } - return _cache_get_object($bin)->clear($cid, $wildcard); + return cache($bin)->clear($cid, $wildcard); } /** @@ -181,7 +190,7 @@ function cache_clear_all($cid = NULL, $bin = NULL, $wildcard = FALSE) { * TRUE if the cache bin specified is empty. */ function cache_is_empty($bin) { - return _cache_get_object($bin)->isEmpty(); + return cache($bin)->isEmpty(); } /** @@ -218,7 +227,7 @@ function cache_is_empty($bin) { * cache_get($cid, 'custom_bin'); * @endcode * - * @see _cache_get_object() + * @see cache() * @see DrupalDatabaseCache */ interface DrupalCacheInterface { @@ -274,6 +283,46 @@ interface DrupalCacheInterface { */ function set($cid, $data, $expire = CACHE_PERMANENT); + /** + * Delete an item from the cache. + * + * @param $cid + * The cache ID to delete. + */ + function delete($cid); + + /** + * Delete multiple items from the cache. + * + * @param $cids + * An array of $cids to delete. + */ + function deleteMultiple(Array $cids); + + /** + * Delete items from the cache using a wildcard prefix. + * + * @param $prefix + * A wildcard prefix. + */ + function deletePrefix($prefix); + + /** + * Flush all cache items in a bin. + */ + function flush(); + + /** + * Clear temporary items from cache. + * + * @todo: this should not be hard-coded to the block and page caches. + */ + function flushTemporary(); + + /** + * Perform garbage collection on a cache bin. + */ + function garbageCollection(); /** * Expire data from the cache. If called without arguments, expirable @@ -351,28 +400,6 @@ class DrupalDatabaseCache implements DrupalCacheInterface { } /** - * Garbage collection for get() and getMultiple(). - * - * @param $bin - * The bin being requested. - */ - protected function garbageCollection() { - global $user; - - // Garbage collection necessary when enforcing a minimum cache lifetime. - $cache_flush = variable_get('cache_flush_' . $this->bin, 0); - if ($cache_flush && ($cache_flush + variable_get('cache_lifetime', 0) <= 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(); - } - } - - /** * Prepare a cached item. * * Checks that items are either permanent or did not expire, and unserializes @@ -434,64 +461,101 @@ class DrupalDatabaseCache implements DrupalCacheInterface { } } - function clear($cid = NULL, $wildcard = FALSE) { - global $user; + function delete($cid) { + db_delete($this->bin) + ->condition('cid', $cid) + ->execute(); + } - if (empty($cid)) { - if (variable_get('cache_lifetime', 0)) { - // We store the time in the current user's $user->cache variable which - // will be saved into the sessions bin by _drupal_session_write(). We then - // simulate that the cache was flushed for this user by not returning - // cached data that was cached before the timestamp. - $user->cache = REQUEST_TIME; + function deleteMultiple(Array $cids) { + // Delete in chunks when a large array is passed. + do { + db_delete($this->bin) + ->condition('cid', array_splice($cids, 0, 1000), 'IN') + ->execute(); + } + while (count($cids)); + } - $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); - } + function deletePrefix($prefix) { + db_delete($this->bin) + ->condition('cid', db_like($prefix) . '%', 'LIKE') + ->execute(); + } + + function flush() { + db_truncate($this->bin)->execute(); + } + + function flushTemporary() { + if (variable_get('cache_lifetime', 0)) { + // We store the time in the current user's $user->cache variable which + // will be saved into the sessions bin by _drupal_session_write(). We then + // simulate that the cache was flushed for this user by not returning + // cached data that was cached before the timestamp. + $user->cache = 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); } - else { - // No minimum cache lifetime, flush all temporary cache entries now. + 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(); + } + } + + function garbageCollection() { + global $user; + + // 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 + variable_get('cache_lifetime', 0) <= 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(); + } + } + + function clear($cid = NULL, $wildcard = FALSE) { + global $user; + + if (empty($cid)) { + $this->flushTemporary(); + } + else { if ($wildcard) { if ($cid == '*') { - db_truncate($this->bin)->execute(); + $this->flush(); } else { - db_delete($this->bin) - ->condition('cid', db_like($cid) . '%', 'LIKE') - ->execute(); + $this->deletePrefix($cid); } } 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)); + $this->deleteMultiple($cid); } else { - db_delete($this->bin) - ->condition('cid', $cid) - ->execute(); + $this->delete($cid); } } } -- 1.7.4.1