diff --git a/CHANGELOG.txt b/CHANGELOG.txt index fe3cb56783b1e0176026a59debeb4680b56aa1af..c128e6913bd98b20b88b5a6bb31246ce4255d36a 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,6 @@ Drupal x.x.x, xxxx-xx-xx (development version) ------------------------ +- added support for different cache backends - usability: * added support for auto-complete forms (AJAX) to user profiles. * improved configurability of the contact forms. diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 3db7d9fadc2796ccf1b6eefbe22c2c04c4beb7af..946d926b4b2116ef4453719e6b797820cf12df32 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -16,11 +16,13 @@ define('WATCHDOG_WARNING', 1); define('WATCHDOG_ERROR', 2); -define('DRUPAL_BOOTSTRAP_DATABASE', 0); -define('DRUPAL_BOOTSTRAP_SESSION', 1); -define('DRUPAL_BOOTSTRAP_PAGE_CACHE', 2); -define('DRUPAL_BOOTSTRAP_PATH', 3); -define('DRUPAL_BOOTSTRAP_FULL', 4); +define('DRUPAL_BOOTSTRAP_CONFIGURATION', 0); +define('DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE', 1); +define('DRUPAL_BOOTSTRAP_DATABASE', 2); +define('DRUPAL_BOOTSTRAP_SESSION', 3); +define('DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE', 4); +define('DRUPAL_BOOTSTRAP_PATH', 5); +define('DRUPAL_BOOTSTRAP_FULL', 6); // these values should match the'role' table define('DRUPAL_ANONYMOUS_RID', 1); @@ -306,125 +308,6 @@ function variable_del($name) { unset($conf[$name]); } -/** - * Return data from the persistent cache. - * - * @param $key - * The cache ID of the data to retrieve. - */ -function cache_get($key) { - global $user; - - // Garbage collection necessary when enforcing a minimum cache lifetime - $cache_flush = variable_get('cache_flush', 0); - if ($cache_flush && ($cache_flush + variable_get('cache_lifetime', 0) <= time())) { - // Time to flush old cache data - db_query("DELETE FROM {cache} WHERE expire != %d AND expire <= %d", CACHE_PERMANENT, $cache_flush); - variable_set('cache_flush', 0); - } - - $cache = db_fetch_object(db_query("SELECT data, created, headers, expire FROM {cache} WHERE cid = '%s'", $key)); - if (isset($cache->data)) { - // If the data is permanent or we're not enforcing a minimum cache lifetime - // always return the cached data. - if ($cache->expire == CACHE_PERMANENT || !variable_get('cache_lifetime', 0)) { - $cache->data = db_decode_blob($cache->data); - } - // If enforcing a minimum cache lifetime, validate that the data is - // currently valid for this user before we return it by making sure the - // cache entry was created before the timestamp in the current session's - // cache timer. The cache variable is loaded into the $user object by - // sess_read() in session.inc. - else { - if ($user->cache > $cache->created) { - // This cache data is too old and thus not valid for us, ignore it. - return 0; - } - else { - $cache->data = db_decode_blob($cache->data); - } - } - return $cache; - } - return 0; -} - -/** - * Store data in the persistent cache. - * - * @param $cid - * The cache ID of the data to store. - * @param $data - * The data to store in the cache. Complex data types must be serialized first. - * @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. - * - A Unix timestamp: Indicates that the item should be kept at least until - * the given time, after which it behaves like CACHE_TEMPORARY. - * @param $headers - * A string containing HTTP header information for cached pages. - */ -function cache_set($cid, $data, $expire = CACHE_PERMANENT, $headers = NULL) { - db_lock_table('cache'); - db_query("UPDATE {cache} SET data = %b, created = %d, expire = %d, headers = '%s' WHERE cid = '%s'", $data, time(), $expire, $headers, $cid); - if (!db_affected_rows()) { - @db_query("INSERT INTO {cache} (cid, data, created, expire, headers) VALUES ('%s', %b, %d, %d, '%s')", $cid, $data, time(), $expire, $headers); - } - db_unlock_tables(); -} - -/** - * Expire data from the cache. - * - * @param $cid - * If set, the cache ID to delete. Otherwise, all cache entries that can - * expire are deleted. - * - * @param $wildcard - * If set to true, the $cid is treated as a substring to match rather than a - * complete ID. - */ -function cache_clear_all($cid = NULL, $wildcard = false) { - global $user; - - 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 table by sess_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 = time(); - - $cache_flush = variable_get('cache_flush', 0); - if ($cache_flush == 0) { - // This is the first request to clear the cache, start a timer. - variable_set('cache_flush', time()); - } - else if (time() > ($cache_flush + variable_get('cache_lifetime', 0))) { - // Clear the cache for everyone, cache_flush_delay seconds have - // passed since the first request to clear the cache. - db_query("DELETE FROM {cache} WHERE expire != %d AND expire < %d", CACHE_PERMANENT, time()); - variable_set('cache_flush', 0); - } - } - else { - // No minimum cache lifetime, flush all temporary cache entries now. - db_query("DELETE FROM {cache} WHERE expire != %d AND expire < %d", CACHE_PERMANENT, time()); - } - } - else { - if ($wildcard) { - db_query("DELETE FROM {cache} WHERE cid LIKE '%%%s%%'", $cid); - } - else { - db_query("DELETE FROM {cache} WHERE cid = '%s'", $cid); - } - } -} - /** * Retrieve the current page from the cache. * @@ -713,15 +596,17 @@ function drupal_is_denied($type, $mask) { * * @param $phase * A constant. Allowed values are: + * DRUPAL_BOOTSTRAP_CONFIGURATION: initialize configuration + * DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE: try to call a non-database cache fetch routine * DRUPAL_BOOTSTRAP_DATABASE: initialize database layer. * DRUPAL_BOOTSTRAP_SESSION: initialize session handling. - * DRUPAL_BOOTSTRAP_PAGE_CACHE: load bootstrap.inc and module.inc, start + * DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE: load bootstrap.inc and module.inc, start * the variable system and try to serve a page from the cache. * DRUPAL_BOOTSTRAP_FULL: Drupal is fully loaded, validate and fix input * data. */ function drupal_bootstrap($phase) { - static $phases = array(DRUPAL_BOOTSTRAP_DATABASE, DRUPAL_BOOTSTRAP_SESSION, DRUPAL_BOOTSTRAP_PAGE_CACHE, DRUPAL_BOOTSTRAP_PATH, DRUPAL_BOOTSTRAP_FULL); + static $phases = array(DRUPAL_BOOTSTRAP_CONFIGURATION, DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE, DRUPAL_BOOTSTRAP_DATABASE, DRUPAL_BOOTSTRAP_SESSION, DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE, DRUPAL_BOOTSTRAP_PATH, DRUPAL_BOOTSTRAP_FULL); while (!is_null($current_phase = array_shift($phases))) { _drupal_bootstrap($current_phase); @@ -735,10 +620,19 @@ function _drupal_bootstrap($phase) { global $conf; switch ($phase) { - case DRUPAL_BOOTSTRAP_DATABASE: + case DRUPAL_BOOTSTRAP_CONFIGURATION: drupal_unset_globals(); // Initialize the configuration conf_init(); + break; + case DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE: + if (variable_get('page_cache_fastpath', 0)) { + require_once variable_get('cache_inc', './includes/cache.inc'); + page_cache_fastpath(); + exit; + } + break; + case DRUPAL_BOOTSTRAP_DATABASE: // Initialize the default database. require_once './includes/database.inc'; db_set_active(); @@ -750,7 +644,8 @@ function _drupal_bootstrap($phase) { session_start(); break; - case DRUPAL_BOOTSTRAP_PAGE_CACHE: + case DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE: + require_once variable_get('cache_inc', './includes/cache.inc'); require_once './includes/module.inc'; // Start a page timer: timer_start('page'); diff --git a/includes/cache.inc b/includes/cache.inc new file mode 100644 index 0000000000000000000000000000000000000000..e7982835afd844e36e38c9f539a36db517616636 --- /dev/null +++ b/includes/cache.inc @@ -0,0 +1,121 @@ +<?php + +/** + * Return data from the persistent cache. + * + * @param $key + * The cache ID of the data to retrieve. + */ +function cache_get($key) { + global $user; + + // Garbage collection necessary when enforcing a minimum cache lifetime + $cache_flush = variable_get('cache_flush', 0); + if ($cache_flush && ($cache_flush + variable_get('cache_lifetime', 0) <= time())) { + // Time to flush old cache data + db_query("DELETE FROM {cache} WHERE expire != %d AND expire <= %d", CACHE_PERMANENT, $cache_flush); + variable_set('cache_flush', 0); + } + + $cache = db_fetch_object(db_query("SELECT data, created, headers, expire FROM {cache} WHERE cid = '%s'", $key)); + if (isset($cache->data)) { + // If the data is permanent or we're not enforcing a minimum cache lifetime + // always return the cached data. + if ($cache->expire == CACHE_PERMANENT || !variable_get('cache_lifetime', 0)) { + $cache->data = db_decode_blob($cache->data); + } + // If enforcing a minimum cache lifetime, validate that the data is + // currently valid for this user before we return it by making sure the + // cache entry was created before the timestamp in the current session's + // cache timer. The cache variable is loaded into the $user object by + // sess_read() in session.inc. + else { + if ($user->cache > $cache->created) { + // This cache data is too old and thus not valid for us, ignore it. + return 0; + } + else { + $cache->data = db_decode_blob($cache->data); + } + } + return $cache; + } + return 0; +} + +/** + * Store data in the persistent cache. + * + * @param $cid + * The cache ID of the data to store. + * @param $data + * The data to store in the cache. Complex data types must be serialized first. + * @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. + * - A Unix timestamp: Indicates that the item should be kept at least until + * the given time, after which it behaves like CACHE_TEMPORARY. + * @param $headers + * A string containing HTTP header information for cached pages. + */ +function cache_set($cid, $data, $expire = CACHE_PERMANENT, $headers = NULL) { + db_lock_table('cache'); + db_query("UPDATE {cache} SET data = %b, created = %d, expire = %d, headers = '%s' WHERE cid = '%s'", $data, time(), $expire, $headers, $cid); + if (!db_affected_rows()) { + @db_query("INSERT INTO {cache} (cid, data, created, expire, headers) VALUES ('%s', %b, %d, %d, '%s')", $cid, $data, time(), $expire, $headers); + } + db_unlock_tables(); +} + +/** + * Expire data from the cache. + * + * @param $cid + * If set, the cache ID to delete. Otherwise, all cache entries that can + * expire are deleted. + * + * @param $wildcard + * If set to true, the $cid is treated as a substring to match rather than a + * complete ID. + */ +function cache_clear_all($cid = NULL, $wildcard = false) { + global $user; + + 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 table by sess_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 = time(); + + $cache_flush = variable_get('cache_flush', 0); + if ($cache_flush == 0) { + // This is the first request to clear the cache, start a timer. + variable_set('cache_flush', time()); + } + else if (time() > ($cache_flush + variable_get('cache_lifetime', 0))) { + // Clear the cache for everyone, cache_flush_delay seconds have + // passed since the first request to clear the cache. + db_query("DELETE FROM {cache} WHERE expire != %d AND expire < %d", CACHE_PERMANENT, time()); + variable_set('cache_flush', 0); + } + } + else { + // No minimum cache lifetime, flush all temporary cache entries now. + db_query("DELETE FROM {cache} WHERE expire != %d AND expire < %d", CACHE_PERMANENT, time()); + } + } + else { + if ($wildcard) { + db_query("DELETE FROM {cache} WHERE cid LIKE '%%%s%%'", $cid); + } + else { + db_query("DELETE FROM {cache} WHERE cid = '%s'", $cid); + } + } +} +