diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 25dd3e6..6ef4e01 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -106,6 +106,12 @@ define('DRUPAL_ANONYMOUS_RID', 1); define('DRUPAL_AUTHENTICATED_RID', 2); /** + * The maximum time to allow for a lock to be held when rebuilding a page for + * the page cache -- this is to prevent stale locks from aborted sessions. + */ +define('CACHE_REBUILD_MAX', 5); + +/** * Start the timer with the specified name. If you start and stop * the same timer multiple times, the measured intervals will be * accumulated. @@ -475,6 +481,17 @@ function page_get_cache() { if (!$user->uid && $_SERVER['REQUEST_METHOD'] == 'GET' && count(drupal_set_message()) == 0) { $cache = cache_get($base_root . request_uri(), 'cache_page'); + // Check if the currently cached page was created before the cache was + // last flushed. If so, try to rebuild it. + if (is_object($cache) && $cache->created < variable_get('cache_page_clear', 0)) { + $lock = cache_get($base_root . request_uri(), 'cache_lock'); + if (!$lock) { + // Grab the lock and rebuild the web page. + cache_set($base_root . request_uri(), 'cache_lock', time(), time() + CACHE_REBUILD_MAX); + $cache = NULL; + } + } + if (empty($cache)) { ob_start(); } @@ -718,6 +735,9 @@ function request_uri() { function watchdog($type, $message, $severity = WATCHDOG_NOTICE, $link = NULL) { global $user, $base_root; + if (!function_exists('db_set_active')) { + include_once './includes/database.inc'; + } $current_db = db_set_active(); // Note: log the exact, entire absolute URL. diff --git a/includes/common.inc b/includes/common.inc index c0b08fa..bc95f38 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -1906,6 +1906,8 @@ function page_set_cache() { ob_end_flush(); if ($cache && $data) { cache_set($base_root . request_uri(), 'cache_page', $data, CACHE_TEMPORARY, drupal_get_headers()); + // Clear lock that prevented multiple requests rebuilding this page. + cache_clear_all($base_root . request_uri(), 'cache_lock'); } } } diff --git a/sites/all/modules/memcache/memcache.inc b/sites/all/modules/memcache/memcache.inc index 2fe6df4..7d778c9 100644 --- a/sites/all/modules/memcache/memcache.inc +++ b/sites/all/modules/memcache/memcache.inc @@ -85,11 +85,13 @@ function cache_set($cid, $table = 'cache', $data, $expire = CACHE_PERMANENT, $he */ function cache_clear_all($cid = NULL, $table = NULL, $wildcard = FALSE) { // If cid and table are not set, we should flush the cache_page table. - if (!isset($cid) && !isset($table)) { - $cid = '*'; - $wildcard = TRUE; - $table = 'cache_page'; - } + if ((!isset($cid) && !isset($table)) || $table == 'cache_page') { + // Special handling for the page cache. Rather than flushing this table, we + // update a variable. When pages are in high demand, this allows us to + // serve the old cached version while an updated version is being created. + variable_set('cache_page_clear', time()); + return; + } if (empty($cid) || ($cid == '*' && $wildcard !== TRUE)) { // don't do anything if cid is unset. this matches the default drupal behavior... if ($wildcard && $cid != '*') {