Commit 5b8960df authored by Dries's avatar Dries
Browse files

- Patch #730060 by beejeebus, catch, Damien Tournoud, moshe weitzman,...

- Patch #730060 by beejeebus, catch, Damien Tournoud, moshe weitzman, msonnabaum, oriol_e9g, aspilicious: Fixed Replace CACHE_TEMPORARY, cache_clear_all() (no arguments) and minimum cache lifetime with cache tags support.
parent 75edfb15
......@@ -39,11 +39,6 @@
*/
const CACHE_PERMANENT = 0;
/**
* Indicates that the item should be removed at the next general cache wipe.
*/
const CACHE_TEMPORARY = -1;
/**
* @defgroup logging_severity_levels Logging severity levels
* @{
......
......@@ -67,19 +67,3 @@ function cache_invalidate(array $tags) {
function cache_get_backends() {
return variable_get('cache_classes', array('cache' => 'Drupal\Core\Cache\DatabaseBackend'));
}
/**
* Expires data from the block and page caches.
*/
function cache_clear_all() {
// @todo: remove before release.
if (func_get_args()) {
throw new Exception(t('cache_clear_all() no longer takes arguments, use cache() instead.'));
}
// Clear the block cache first, so stale data will
// not end up in the page cache.
if (module_exists('block')) {
cache('block')->expire();
}
cache('page')->expire();
}
......@@ -110,10 +110,11 @@
* specified. Use DRUPAL_CACHE_CUSTOM to disable standard block cache and
* implement
*
* The block cache is cleared in cache_clear_all(), and uses the same clearing
* policy than page cache (node, comment, user, taxonomy added or updated...).
* Blocks requiring more fine-grained clearing might consider disabling the
* built-in block cache (DRUPAL_NO_CACHE) and roll their own.
* The block cache is cleared when the 'content' cache tag is invalidated,
* following the same pattern as the page cache (node, comment, user, taxonomy
* added or updated...). Blocks requiring more fine-grained clearing might
* consider disabling the built-in block cache (DRUPAL_NO_CACHE)
* and roll their own.
*
* Note that user 1 is excluded from block caching.
*/
......@@ -5129,7 +5130,8 @@ function drupal_page_set_cache() {
'title' => drupal_get_title(),
'headers' => array(),
),
'expire' => CACHE_TEMPORARY,
'tags' => array('content' => TRUE),
'expire' => CACHE_PERMANENT,
'created' => REQUEST_TIME,
);
......@@ -5148,7 +5150,7 @@ function drupal_page_set_cache() {
if (config('system.performance')->get('page_compression') && extension_loaded('zlib')) {
$cache->data['body'] = gzencode($cache->data['body'], 9, FORCE_GZIP);
}
cache('page')->set($cache->cid, $cache->data, $cache->expire);
cache('page')->set($cache->cid, $cache->data, $cache->expire, $cache->tags);
}
return $cache;
}
......@@ -6050,7 +6052,8 @@ function drupal_render_cache_set(&$markup, $elements) {
}
$bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'cache';
$expire = isset($elements['#cache']['expire']) ? $elements['#cache']['expire'] : CACHE_PERMANENT;
cache($bin)->set($cid, $data, $expire);
$tags = isset($elements['#cache']['tags']) ? $elements['#cache']['tags'] : array();
cache($bin)->set($cid, $data, $expire, $tags);
}
/**
......@@ -6123,7 +6126,7 @@ function drupal_render_collect_attached($elements, $return = FALSE) {
* - #pre_render: $function with a _pre_render suffix.
* - #cache: An associative array prepared for drupal_render_cache_set().
*/
function drupal_render_cache_by_query($query, $function, $expire = CACHE_TEMPORARY, $granularity = NULL) {
function drupal_render_cache_by_query($query, $function, $expire = CACHE_PERMANENT, $granularity = NULL) {
$cache_keys = array_merge(array($function), drupal_render_cid_parts($granularity));
$query->preExecute();
$cache_keys[] = hash('sha256', serialize(array((string) $query, $query->getArguments())));
......
......@@ -3257,13 +3257,13 @@ function _menu_clear_page_cache() {
// Clear the page and block caches, but at most twice, including at
// the end of the page load when there are multiple links saved or deleted.
if ($cache_cleared == 0) {
cache_clear_all();
cache_invalidate(array('content' => TRUE));
// Keep track of which menus have expanded items.
_menu_set_expanded_menus();
$cache_cleared = 1;
}
elseif ($cache_cleared == 1) {
drupal_register_shutdown_function('cache_clear_all');
drupal_register_shutdown_function('cache_invalidate', array('content', TRUE));
// Keep track of which menus have expanded items.
drupal_register_shutdown_function('_menu_set_expanded_menus');
$cache_cleared = 2;
......
......@@ -94,11 +94,9 @@ function getMultiple(&$cids);
* @param $expire
* One of the following values:
* - CACHE_PERMANENT: Indicates that the item should never be removed unless
* explicitly told to using cache_clear_all() with a cache ID.
* - CACHE_TEMPORARY: Indicates that the item should be removed at the next
* general cache wipe.
* explicitly told to using cache->delete($cid).
* - A Unix timestamp: Indicates that the item should be kept at least until
* the given time, after which it behaves like CACHE_TEMPORARY.
* the given time.
* @param array $tags
* An array of tags to be stored with the cache item. These should normally
* identify objects used to build the cache item, which should trigger
......
......@@ -100,14 +100,6 @@ protected function prepareItem($cache) {
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.
$config = config('system.performance');
if ($cache->expire != CACHE_PERMANENT && $config->get('cache_lifetime') && 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;
}
// The cache data is invalid if any of its tags have been cleared since.
if ($cache->tags) {
......@@ -199,73 +191,17 @@ function flush() {
* Implements Drupal\Core\Cache\CacheBackendInterface::expire().
*/
function expire() {
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();
}
db_delete($this->bin)
->condition('expire', CACHE_PERMANENT, '<>')
->condition('expire', REQUEST_TIME, '<')
->execute();
}
/**
* Implements Drupal\Core\Cache\CacheBackendInterface::garbageCollection().
*/
function garbageCollection() {
$cache_lifetime = config('system.performance')->get('cache_lifetime');
// 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();
}
$this->expire();
}
/**
......
......@@ -44,8 +44,8 @@ function aggregator_aggregator_parse($feed) {
$feed->etag = $etag;
$feed->modified = $modified;
// Clear the cache.
cache_clear_all();
// Clear the page and block caches.
cache_invalidate(array('content' => TRUE));
return TRUE;
}
......
......@@ -205,7 +205,7 @@ function block_admin_display_form_submit($form, &$form_state) {
throw $e;
}
drupal_set_message(t('The block settings have been updated.'));
cache_clear_all();
cache_invalidate(array('content' => TRUE));
}
/**
......@@ -603,7 +603,7 @@ function block_admin_configure_submit($form, &$form_state) {
throw $e;
}
drupal_set_message(t('The block configuration has been saved.'));
cache_clear_all();
cache_invalidate(array('content' => TRUE));
$form_state['redirect'] = 'admin/structure/block';
}
}
......@@ -712,7 +712,7 @@ function block_add_block_form_submit($form, &$form_state) {
}
drupal_set_message(t('The block has been created.'));
cache_clear_all();
cache_invalidate(array('content' => TRUE));
$form_state['redirect'] = 'admin/structure/block';
}
......@@ -760,7 +760,7 @@ function block_custom_block_delete_submit($form, &$form_state) {
->execute();
drupal_set_message(t('The block %name has been removed.', array('%name' => $form_state['values']['info'])));
cache_clear_all();
cache_invalidate(array('content' => TRUE));
$form_state['redirect'] = 'admin/structure/block';
return;
}
......@@ -812,4 +812,3 @@ function template_preprocess_block_admin_display_form(&$variables) {
$variables['form_submit'] = drupal_render_children($variables['form']);
}
......@@ -374,7 +374,7 @@ function _block_get_renderable_region($list = array()) {
'keys' => array($block->module, $block->delta),
'granularity' => $block->cache,
'bin' => 'block',
'expire' => CACHE_TEMPORARY,
'tags' => array('content' => TRUE),
),
);
}
......
......@@ -66,7 +66,7 @@ function testCachePerRole() {
$this->assertText($old_content, t('Block is served from the cache.'));
// Clear the cache and verify that the stale data is no longer there.
cache_clear_all();
cache_invalidate(array('content' => TRUE));
$this->drupalGet('');
$this->assertNoText($old_content, t('Block cache clear removes stale cache data.'));
$this->assertText($current_content, t('Fresh block content is displayed after clearing the cache.'));
......
......@@ -194,7 +194,7 @@ function comment_admin_overview_submit($form, &$form_state) {
}
drupal_set_message(t('The update has been performed.'));
$form_state['redirect'] = 'admin/content/comment';
cache_clear_all();
cache_invalidate(array('content' => TRUE));
}
/**
......@@ -242,7 +242,7 @@ function comment_multiple_delete_confirm($form, &$form_state) {
function comment_multiple_delete_confirm_submit($form, &$form_state) {
if ($form_state['values']['confirm']) {
comment_delete_multiple(array_keys($form_state['values']['comments']));
cache_clear_all();
cache_invalidate(array('content' => TRUE));
$count = count($form_state['values']['comments']);
watchdog('content', 'Deleted @count comments.', array('@count' => $count));
drupal_set_message(format_plural($count, 'Deleted 1 comment.', 'Deleted @count comments.'));
......@@ -301,7 +301,7 @@ function comment_confirm_delete_submit($form, &$form_state) {
drupal_set_message(t('The comment and all its replies have been deleted.'));
watchdog('content', 'Deleted comment @cid and its replies.', array('@cid' => $comment->cid));
// Clear the cache so an anonymous user sees that his comment was deleted.
cache_clear_all();
cache_invalidate(array('content' => TRUE));
$form_state['redirect'] = "node/$comment->nid";
}
......@@ -2096,7 +2096,7 @@ function comment_form_submit($form, &$form_state) {
$form_state['redirect'] = $redirect;
// Clear the block and page caches so that anonymous users see the comment
// they have posted.
cache_clear_all();
cache_invalidate(array('content' => TRUE));
}
/**
......@@ -2439,7 +2439,7 @@ function comment_unpublish_by_keyword_action_submit($form, $form_state) {
*/
function comment_save_action(Comment $comment) {
comment_save($comment);
cache_clear_all();
cache_invalidate(array('content' => TRUE));
watchdog('action', 'Saved comment %title', array('%title' => $comment->subject));
}
......
......@@ -51,7 +51,7 @@ function testRecentCommentBlock() {
user_role_revoke_permissions(DRUPAL_ANONYMOUS_RID, array('access comments'));
// drupalCreateNode() does not automatically flush content caches unlike
// posting a node from a node form.
cache_clear_all();
cache_invalidate(array('content' => TRUE));
$this->drupalGet('');
$this->assertNoText($block['title'], t('Block was not found.'));
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access comments'));
......
......@@ -96,7 +96,7 @@ function forum_form_submit($form, &$form_state) {
case SAVED_UPDATED:
drupal_set_message(t('The @type %term has been updated.', array('%term' => $form_state['values']['name'], '@type' => $type)));
// Clear the page and block caches to avoid stale data.
cache_clear_all();
cache_invalidate(array('content' => TRUE));
break;
}
$form_state['redirect'] = 'admin/structure/forum';
......
......@@ -213,7 +213,7 @@ function testJavaScriptTranslation() {
// Test JavaScript translation rebuilding.
file_unmanaged_delete($js_file);
$this->assertTrue($result = !file_exists($js_file), t('JavaScript file deleted: %file', array('%file' => $result ? $js_file : t('found'))));
cache_clear_all();
cache_invalidate(array('content' => TRUE));
_locale_rebuild_js($langcode);
$this->assertTrue($result = file_exists($js_file), t('JavaScript file rebuilt: %file', array('%file' => $result ? $js_file : t('not found'))));
}
......
......@@ -105,7 +105,7 @@ function testRecentNodeBlock() {
$node4 = $this->drupalCreateNode($default_settings);
// drupalCreateNode() does not automatically flush content caches unlike
// posting a node from a node form.
cache_clear_all();
cache_invalidate(array('content' => TRUE));
// Test that all four nodes are shown.
$this->drupalGet('');
......
......@@ -611,7 +611,7 @@ function node_admin_nodes_submit($form, &$form_state) {
}
call_user_func_array($function, $args);
cache_clear_all();
cache_invalidate(array('content' => TRUE));
}
else {
// We need to rebuild the form to go to a second step. For example, to
......
......@@ -3447,7 +3447,7 @@ function node_access_rebuild($batch_mode = FALSE) {
if (!isset($batch)) {
drupal_set_message(t('Content permissions have been rebuilt.'));
node_access_needs_rebuild(FALSE);
cache_clear_all();
cache_invalidate(array('content' => TRUE));
}
}
......@@ -3497,7 +3497,7 @@ function _node_access_rebuild_batch_finished($success, $results, $operations) {
else {
drupal_set_message(t('The content access permissions have not been properly rebuilt.'), 'error');
}
cache_clear_all();
cache_invalidate(array('content' => TRUE));
}
/**
......
......@@ -520,7 +520,7 @@ function node_form_submit($form, &$form_state) {
$form_state['rebuild'] = TRUE;
}
// Clear the page and block caches.
cache_clear_all();
cache_invalidate(array('content' => TRUE));
}
/**
......
......@@ -756,7 +756,7 @@ function poll_vote($form, &$form_state) {
->condition('chid', $choice)
->execute();
cache_clear_all();
cache_invalidate(array('content' => TRUE));
if (!$user->uid) {
// The vote is recorded so the user gets the result view instead of the
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment