diff --git a/includes/cache.inc b/includes/cache.inc index 9b60a7e..f94ca80 100644 --- a/includes/cache.inc +++ b/includes/cache.inc @@ -373,9 +373,6 @@ class DrupalDatabaseCache implements DrupalCacheInterface { 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 @@ -490,30 +487,28 @@ class DrupalDatabaseCache implements DrupalCacheInterface { } function expire() { - if (variable_get('cache_lifetime', 0)) { + if ($cache_lifetime = 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. $GLOBALS['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); - } + // Clear expired items from the cache. + db_delete($this->bin) + ->condition('expire', CACHE_PERMANENT, '>') + ->condition('expire', REQUEST_TIME, '<') + ->execute(); + variable_set('cache_flush_' . $this->bin, 0); + + // Clear CACHE_TEMPORARY items that are older than the minimum cache lifetime. + db_delete($this->bin) + ->condition('expire', CACHE_TEMPORARY) + ->condition('created', REQUEST_TIME - $cache_lifetime, '<') + ->execute(); } else { - // No minimum cache lifetime, flush all temporary cache entries now. + // No minimum cache lifetime, flush all expired and temporary cache entries now. db_delete($this->bin) ->condition('expire', CACHE_PERMANENT, '<>') ->condition('expire', REQUEST_TIME, '<') @@ -522,20 +517,7 @@ class DrupalDatabaseCache implements DrupalCacheInterface { } 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(); - } + $this->expire(); } function clear($cid = NULL, $wildcard = FALSE) { diff --git a/modules/system/system.install b/modules/system/system.install index 5c4250a..8d4b048 100644 --- a/modules/system/system.install +++ b/modules/system/system.install @@ -675,7 +675,7 @@ function system_schema() { ), ), 'indexes' => array( - 'expire' => array('expire'), + 'expire_created' => array('expire', 'created'), ), 'primary key' => array('cid'), ); diff --git a/modules/system/system.module b/modules/system/system.module index d7dc69c..fabd436 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -3007,7 +3007,22 @@ function system_cron() { $core = array('cache', 'path', 'filter', 'page', 'form', 'menu'); $cache_bins = array_merge(module_invoke_all('flush_caches'), $core); foreach ($cache_bins as $bin) { - cache($bin)->expire(); + // If the cache backend provides a garbageCollection() method, call that. + // If it does not, expire all temporary and expired cache items. Limit + // these calls to once every 24 hours by default to avoid wiping the page + // and block caches every cron run. + $cache = cache($bin); + $name = 'cache_garbage_collect_' . $bin; + $window = max(variable_get('cache_lifetime', 0), variable_get('cache_garbage_collection_frequency', 86400)); + if (flood_is_allowed($name, 1, $window, 'cron')) { + flood_register_event($name, 1, $window, 'cron'); + if (method_exists($cache, 'garbageCollection')) { + $cache->garbageCollection(); + } + else { + $cache->expire(); + } + } } // Cleanup the batch table and the queue for failed batches.