=== modified file 'includes/bootstrap.inc'
--- includes/bootstrap.inc	2009-08-04 04:02:25 +0000
+++ includes/bootstrap.inc	2009-08-15 23:10:56 +0000
@@ -28,13 +28,6 @@ define('CACHE_DISABLED', 0);
 define('CACHE_NORMAL', 1);
 
 /**
- * Indicates that page caching is using "aggressive" mode. This bypasses
- * loading any modules for additional speed, which may break functionality in
- * modules that expect to be run on each page load.
- */
-define('CACHE_AGGRESSIVE', 2);
-
-/**
  * Log message severity -- Emergency: system is unusable.
  *
  * @see watchdog()
@@ -104,10 +97,9 @@ define('WATCHDOG_DEBUG', 7);
 define('DRUPAL_BOOTSTRAP_CONFIGURATION', 0);
 
 /**
- * Second bootstrap phase: try to call a non-database cache
- * fetch routine.
+ * Second bootstrap phase: try to serve a cached page.
  */
-define('DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE', 1);
+define('DRUPAL_BOOTSTRAP_PAGE_CACHE', 1);
 
 /**
  * Third bootstrap phase: initialize database layer.
@@ -120,20 +112,19 @@ define('DRUPAL_BOOTSTRAP_DATABASE', 2);
 define('DRUPAL_BOOTSTRAP_ACCESS', 3);
 
 /**
- * Fifth bootstrap phase: initialize session handling.
+ * Fifth bootstrap phase: initialize the variable system.
  */
-define('DRUPAL_BOOTSTRAP_SESSION', 4);
+define('DRUPAL_BOOTSTRAP_VARIABLES', 4);
 
 /**
- * Sixth bootstrap phase: initialize the variable system.
+ * Sixth bootstrap phase: initialize session handling.
  */
-define('DRUPAL_BOOTSTRAP_VARIABLES', 5);
+define('DRUPAL_BOOTSTRAP_SESSION', 5);
 
 /**
- * Seventh bootstrap phase: load bootstrap.inc and module.inc, start
- * the variable system and try to serve a page from the cache.
+ * Seventh bootstrap phase: set up the page header.
  */
-define('DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE', 6);
+define('DRUPAL_BOOTSTRAP_PAGE_HEADER', 6);
 
 /**
  * Eighth bootstrap phase: find out language of the page.
@@ -141,7 +132,7 @@ define('DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE
 define('DRUPAL_BOOTSTRAP_LANGUAGE', 7);
 
 /**
- * Nineth bootstrap phase: set $_GET['q'] to Drupal path of request.
+ * Ninth bootstrap phase: set $_GET['q'] to Drupal path of request.
  */
 define('DRUPAL_BOOTSTRAP_PATH', 8);
 
@@ -1021,7 +1012,7 @@ function drupal_serve_page_from_cache(st
   // not bother caching the page in a public proxy, because the cached copy
   // will only be served to that particular user due to Vary: Cookie, unless
   // the Vary header has been replaced or unset in hook_boot() (see below).
-  $max_age = variable_get('cache') == CACHE_AGGRESSIVE && (!isset($_COOKIE[session_name()]) || isset($hook_boot_headers['vary'])) ? variable_get('cache_lifetime', 0) : 0;
+  $max_age = !variable_get('page_cache_invoke_hooks', TRUE) && (!isset($_COOKIE[session_name()]) || isset($hook_boot_headers['vary'])) ? variable_get('cache_lifetime', 0) : 0;
   $default_headers['Cache-Control'] = 'public, max-age=' . $max_age;
 
   // Entity tag should change if the output changes.
@@ -1304,7 +1295,7 @@ function drupal_get_messages($type = NUL
  * to avoid querying the database at this critical stage of the bootstrap if
  * an administrative interface for IP address blocking is not required.
  *
- * @param $ip string
+ * @param $ip
  *   IP address to check.
  * @return bool
  *   TRUE if access is denied, FALSE if access is allowed.
@@ -1314,11 +1305,29 @@ function drupal_is_denied($ip) {
   // for an array of IP addresses in settings.php before querying the
   // database.
   $blocked_ips = variable_get('blocked_ips');
+  $denied = FALSE;
   if (isset($blocked_ips) && is_array($blocked_ips)) {
-    return in_array($ip, $blocked_ips);
+    $denied = in_array($ip, $blocked_ips);
   }
-  else {
-    return (bool)db_query("SELECT 1 FROM {blocked_ips} WHERE ip = :ip", array(':ip' => $ip))->fetchField();
+  // Only check if database.inc is loaded already.
+  elseif (function_exists('db_is_active')) {
+    $denied = (bool)db_query("SELECT 1 FROM {blocked_ips} WHERE ip = :ip", array(':ip' => $ip))->fetchField();
+  }
+  return $denied;
+}
+
+/**
+ * Handle denied users.
+ *
+ * @param $ip
+ *   IP address to check. Prints a message and exits if access is denied.
+ */
+function drupal_handle_denied($ip) {
+  // Deny access to blocked IP addresses - t() is not yet available.
+  if (drupal_is_denied($ip)) {
+    header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
+    print 'Sorry, ' . check_plain(ip_address()) . ' has been banned.';
+    exit();
   }
 }
 
@@ -1358,16 +1367,22 @@ function drupal_anonymous_user($session 
  *     DRUPAL_BOOTSTRAP_LANGUAGE: identify the language used on the page.
  *     DRUPAL_BOOTSTRAP_PATH: set $_GET['q'] to Drupal path of request.
  *     DRUPAL_BOOTSTRAP_FULL: Drupal is fully loaded, validate and fix input data.
- */
-function drupal_bootstrap($phase = NULL) {
+ * @param $new_phase
+ *   A boolean, set to FALSE if calling drupal_bootstrap from inside a
+ *   function called from drupal_bootstrap (recursion).
+ */
+function drupal_bootstrap($phase = NULL, $new_phase = TRUE) {
+  $final_phase = &drupal_static(__FUNCTION__ . '_final_phase');
+  if ($new_phase) {
+    $final_phase = $new_phase;
+  }
   $phases = &drupal_static(__FUNCTION__ . '_phases', array(
     DRUPAL_BOOTSTRAP_CONFIGURATION,
-    DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE,
+    DRUPAL_BOOTSTRAP_PAGE_CACHE,
     DRUPAL_BOOTSTRAP_DATABASE,
-    DRUPAL_BOOTSTRAP_ACCESS,
-    DRUPAL_BOOTSTRAP_SESSION,
     DRUPAL_BOOTSTRAP_VARIABLES,
-    DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE,
+    DRUPAL_BOOTSTRAP_SESSION,
+    DRUPAL_BOOTSTRAP_PAGE_HEADER,
     DRUPAL_BOOTSTRAP_LANGUAGE,
     DRUPAL_BOOTSTRAP_PATH,
     DRUPAL_BOOTSTRAP_FULL,
@@ -1375,10 +1390,14 @@ function drupal_bootstrap($phase = NULL)
   $completed_phase = &drupal_static(__FUNCTION__ . '_completed_phase', -1);
 
   if (isset($phase)) {
-    while ($phases && $phase > $completed_phase) {
+    while ($phases && $phase > $completed_phase && $final_phase > $completed_phase) {
       $current_phase = array_shift($phases);
       _drupal_bootstrap($current_phase);
-      $completed_phase = $current_phase;
+      // This function is reentrant. Only update the completed phase when the
+      // current call actually resulted in a progress in the bootstrap process.
+      if ($current_phase > $completed_phase) {
+        $completed_phase = $current_phase;
+      }
     }
   }
   return $completed_phase;
@@ -1395,8 +1414,9 @@ function drupal_get_bootstrap_phase() {
   return drupal_bootstrap();
 }
 
-function _drupal_bootstrap($phase) {
+function _drupal_bootstrap($phase, $final_phase) {
   global $conf, $user;
+  static $cache;
 
   switch ($phase) {
 
@@ -1408,16 +1428,34 @@ function _drupal_bootstrap($phase) {
       drupal_settings_initialize();
       break;
 
-    case DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE:
+    case DRUPAL_BOOTSTRAP_PAGE_CACHE:
       // Allow specifying special cache handlers in settings.php, like
       // using memcached or files for storing cache information.
       require_once DRUPAL_ROOT . '/' . variable_get('cache_inc', 'includes/cache.inc');
-      // If the page_cache_fastpath is set to TRUE in settings.php and
-      // page_cache_fastpath (implemented in the special implementation of
-      // cache.inc) printed the page and indicated this with a returned TRUE
-      // then we are done.
-      if (variable_get('page_cache_fastpath', FALSE) && page_cache_fastpath()) {
-        exit;
+      // Check for a cache mode force from settings.php.
+      if (variable_get('page_cache_without_database')) {
+        $cache_mode = CACHE_NORMAL;
+      }
+      else {
+        drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES, FALSE);
+        $cache_mode = variable_get('cache');
+      }
+      drupal_handle_denied(ip_address());
+      if (!isset($_COOKIE[session_name()]) && $cache_mode == CACHE_NORMAL) {
+        $user = drupal_anonymous_user();
+        $cache = drupal_page_get_cache();
+        if (is_object($cache)) {
+          if (variable_get('page_cache_invoke_hooks', TRUE)) {
+            require_once DRUPAL_ROOT . '/includes/module.inc';
+            module_invoke_all('boot');
+          }
+          header('X-Drupal-Cache: HIT');
+          drupal_serve_page_from_cache($cache);
+          if (variable_get('page_cache_invoke_hooks', TRUE)) {
+            module_invoke_all('exit');
+          }
+          exit;
+        }
       }
       break;
 
@@ -1437,13 +1475,9 @@ function _drupal_bootstrap($phase) {
       spl_autoload_register('drupal_autoload_interface');
       break;
 
-    case DRUPAL_BOOTSTRAP_ACCESS:
-      // Deny access to blocked IP addresses - t() is not yet available.
-      if (drupal_is_denied(ip_address())) {
-        header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
-        print 'Sorry, ' . check_plain(ip_address()) . ' has been banned.';
-        exit();
-      }
+    case DRUPAL_BOOTSTRAP_VARIABLES:
+      // Load variables from the database, but do not overwrite variables set in settings.php.
+      $conf = variable_initialize(isset($conf) ? $conf : array());
       break;
 
     case DRUPAL_BOOTSTRAP_SESSION:
@@ -1451,41 +1485,9 @@ function _drupal_bootstrap($phase) {
       drupal_session_initialize();
       break;
 
-    case DRUPAL_BOOTSTRAP_VARIABLES:
-      // Load variables from the database, but do not overwrite variables set in settings.php.
-      $conf = variable_initialize(isset($conf) ? $conf : array());
-      break;
-
-    case DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE:
-      $cache_mode = variable_get('cache', CACHE_DISABLED);
-
-      // Get the page from the cache.
-      if ($cache_mode != CACHE_DISABLED) {
-        $cache = drupal_page_get_cache();
-      }
-      else {
-        $cache = FALSE;
-      }
-
-      // If the skipping of the bootstrap hooks is not enforced, call hook_boot.
-      if (!$cache || $cache_mode != CACHE_AGGRESSIVE) {
-        // Load module handling.
-        require_once DRUPAL_ROOT . '/includes/module.inc';
-        module_invoke_all('boot');
-      }
-
-      // If there is a cached page, display it.
-      if ($cache) {
-        header('X-Drupal-Cache: HIT');
-        drupal_serve_page_from_cache($cache);
-        // If the skipping of the bootstrap hooks is not enforced, call hook_exit.
-        if ($cache_mode != CACHE_AGGRESSIVE) {
-          module_invoke_all('exit');
-        }
-        // We are done.
-        exit;
-      }
-
+    case DRUPAL_BOOTSTRAP_PAGE_HEADER:
+      require_once DRUPAL_ROOT . '/includes/module.inc';
+      module_invoke_all('boot');
       if (!$cache && drupal_page_is_cacheable()) {
         header('X-Drupal-Cache: MISS');
       }

=== modified file 'modules/simpletest/tests/bootstrap.test'
--- modules/simpletest/tests/bootstrap.test	2009-08-04 04:02:25 +0000
+++ modules/simpletest/tests/bootstrap.test	2009-08-15 21:55:22 +0000
@@ -260,22 +260,6 @@ class HookBootExitTestCase extends Drupa
     $calls++;
     $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot called with normal cache.'));
     $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit called with normal cache.'));
-
-    // Test with aggressive cache. Boot and exit should not fire since the
-    // page is cached.
-    variable_set('cache', CACHE_AGGRESSIVE);
-    $this->assertTrue(cache_get(url('', array('absolute' => TRUE)), 'cache_page'), t('Page has been cached.'));
-    $this->drupalGet('');
-    $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot not called with agressive cache and a cached page.'));
-    $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit not called with agressive cache and a cached page.'));
-
-    // Test with aggressive cache and page cache cleared. Boot and exit should
-    // be called.
-    $this->assertTrue(db_delete('cache_page')->execute(), t('Page cache cleared.'));
-    $this->drupalGet('');
-    $calls++;
-    $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot called with agressive cache and no cached page.'));
-    $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit called with agressive cache and no cached page.'));
   }
 }
 

=== modified file 'modules/system/system.admin.inc'
--- modules/system/system.admin.inc	2009-08-15 06:27:49 +0000
+++ modules/system/system.admin.inc	2009-08-15 21:55:22 +0000
@@ -1363,21 +1363,6 @@ function system_performance_settings() {
   );
 
   $cache = variable_get('cache', CACHE_DISABLED);
-  $js_hide = $cache != CACHE_AGGRESSIVE ? 'js-hide' : '';
-  $problem_modules = array_unique(array_merge(module_implements('boot'), module_implements('exit')));
-  if (count($problem_modules) > 0) {
-    $module_names = array();
-    foreach ($problem_modules as $module) {
-      $info = drupal_parse_info_file(drupal_get_path('module', $module) . "/$module.info");
-      $module_names[] = $info['name'];
-    }
-    sort($module_names);
-    $message = format_plural(count($module_names), '%module may cause issues when using aggressive caching.', '%modules may cause issues when using aggressive caching.', array('%module' => $module_names[0], '%modules' => implode(', ', $module_names)));
-    $description = ' <strong id="cache-error" class="error ' . $js_hide . '">' . $message . '</strong>';
-  }
-  else {
-    $description = ' <strong class="' . $js_hide . '">' . t('Note: if you use aggressive page caching and enable new modules, you will need to check this setting again to ensure compatibility.') . '</strong>';
-  }
   $form['caching']['cache'] = array(
     '#type' => 'radios',
     '#title' => t('Page cache for anonymous users'),

=== modified file 'modules/system/system.install'
--- modules/system/system.install	2009-08-12 23:51:19 +0000
+++ modules/system/system.install	2009-08-15 21:55:22 +0000
@@ -2243,6 +2243,17 @@ function system_update_7032() {
 }
 
 /**
+ * Move CACHE_AGGRESSIVE to CACHE_NORMAL.
+ */
+function system_update_7033() {
+  if (variable_get('cache') == 2) {
+    variable_set('cache', CACHE_NORMAL);
+    $ret[] = array('success' => TRUE, 'query' => "Aggressive caching was disabled and replaced with normal caching, please read the page caching section in default.settings.php for more information on how to enable similar functionality.");
+  }
+  return array();
+}
+
+/**
  * @} End of "defgroup updates-6.x-to-7.x"
  * The next series of updates should start at 8000.
  */

=== modified file 'sites/default/default.settings.php'
--- sites/default/default.settings.php	2009-07-04 06:22:03 +0000
+++ sites/default/default.settings.php	2009-08-15 23:01:40 +0000
@@ -341,3 +341,16 @@ $conf = array(
 # $conf['blocked_ips'] = array(
 #   'a.b.c.d',
 # );
+
+/**
+ * Page Caching:
+ *
+ * To use a caching backend that does not use the database for page cache,
+ * set cache_inc to the file which provides this backend and set
+ * page_cache_without_database to TRUE. For additional speedup,
+ * page_cache_invoke_hooks can be set to FALSE to skip calling hook_boot and
+ * hook_exit.
+ */
+# $conf['cache_inc'] = DRUPAL_ROOT . '/sites/all/modules/memcache/memcache.inc';
+# $conf['page_cache_without_database'] = TRUE;
+# $conf['page_cache_invoke_hooks'] = FALSE;

