diff --git a/includes/cache-install.inc b/includes/cache-install.inc index d9bb0f9..8bcf8b7 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 8666874..1d1acf9 100644 --- a/includes/cache.inc +++ b/includes/cache.inc @@ -138,6 +138,73 @@ function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT) { } /** + * Delete an item from the cache. + * + * @param $cid + * A cache ID to delete. + * @param $bin + * A cache bin. + */ +function cache_delete($cid, $bin) { + return _cache_get_object($bin)->delete($cid, $wildcard); +} + +/** + * Delete multiple items from the cache. + * + * @param $cids + * An array of $cids to delete. + * @param $bin + * A cache bin. + */ +function cache_delete_multiple(Array $cids, $bin) { + return _cache_get_object($bin)->deleteMultiple($cid); +} + +/** + * Delete items from the cache using a wildcard prefix. + * + * @param $prefix + * A wildcard prefix. + * @param $bin + * A cache bin. + */ +function cache_delete_prefix($prefix, $bin) { + return _cache_get_object($bin)->deletePrefix($prefix); +} + +/** + * Flush all cache items in a bin. + */ +function cache_flush($bin) { + _cache_get_object($bin)->flush(); +} + +/** + * 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_get_object('cache_block')->flushTemporary(); + } + _cache_get_object('cache_page')->flushTemporary(); +} + +/** + * Perform garbage collection on a cache bin. + * + * @param $bin + * A cache bin. + */ +function cache_garbage_collection($bin) { + _cache_get_object($bin)->garbageCollection(); +} + +/** * Expire data from the cache. * * If called without arguments, expirable entries will be cleared from the @@ -158,12 +225,7 @@ 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); @@ -274,6 +336,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 +453,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 +514,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; - - $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 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)); + } + + 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); } } }