Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.117
diff -u -F^f -r1.117 bootstrap.inc
--- includes/bootstrap.inc	28 Aug 2006 11:08:04 -0000	1.117
+++ includes/bootstrap.inc	29 Aug 2006 04:20:54 -0000
@@ -10,19 +10,19 @@
 define('CACHE_TEMPORARY', -1);
 
 define('CACHE_DISABLED', 0);
-define('CACHE_ENABLED', 1);
+define('CACHE_RECOMMENDED', 1);
+define('CACHE_EXPERT', 2);
 
 define('WATCHDOG_NOTICE', 0);
 define('WATCHDOG_WARNING', 1);
 define('WATCHDOG_ERROR', 2);
 
 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);
+define('DRUPAL_BOOTSTRAP_DATABASE', 1);
+define('DRUPAL_BOOTSTRAP_SESSION', 2);
+define('DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE', 3);
+define('DRUPAL_BOOTSTRAP_PATH', 4);
+define('DRUPAL_BOOTSTRAP_FULL', 5);
 
 // These values should match the 'role' table
 define('DRUPAL_ANONYMOUS_RID', 1);
@@ -382,11 +382,6 @@ function drupal_load($type, $name) {
 /**
  * Set HTTP headers in preparation for a page response.
  *
- * The general approach here is that anonymous users can keep a local
- * cache of the page, but must revalidate it on every request.  Then,
- * they are given a '304 Not Modified' response as long as they stay
- * logged out and the page has not been modified.
- *
  * Authenticated users are always given a 'no-cache' header, and will
  * fetch a fresh page on every request.  This prevents authenticated
  * users seeing locally cached pages that show them as logged out.
@@ -394,62 +389,66 @@ function drupal_load($type, $name) {
  * @see page_set_cache
  */
 function drupal_page_header() {
-  if (variable_get('cache', 0) && $cache = page_get_cache()) {
-    bootstrap_invoke_all('init');
-
-    // Set default values:
-    $last_modified = gmdate('D, d M Y H:i:s', $cache->created) .' GMT';
-    $etag = '"'.md5($last_modified).'"';
-
-    // See if the client has provided the required HTTP headers:
-    $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) : FALSE;
-    $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : FALSE;
-
-    if ($if_modified_since && $if_none_match
-        && $if_none_match == $etag // etag must match
-        && $if_modified_since == $last_modified) {  // if-modified-since must match
-      header('HTTP/1.1 304 Not Modified');
-      // All 304 responses must send an etag if the 200 response for the same object contained an etag
-      header("Etag: $etag");
-      exit();
-    }
-
-    // Send appropriate response:
-    header("Last-Modified: $last_modified");
-    header("ETag: $etag");
+  header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
+  header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
+  header("Cache-Control: no-store, no-cache, must-revalidate");
+  header("Cache-Control: post-check=0, pre-check=0", FALSE);
+  header("Pragma: no-cache");
+}
 
-    // The following headers force validation of cache:
-    header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
-    header("Cache-Control: must-revalidate");
+/**
+ * Set HTTP headers in preparation for a cached page response.
+ *
+ * The general approach here is that anonymous users can keep a local
+ * cache of the page, but must revalidate it on every request.  Then,
+ * they are given a '304 Not Modified' response as long as they stay
+ * logged out and the page has not been modified.
+ *
+ */
+function drupal_page_cache_header($cache) {
+  // Set default values:
+  $last_modified = gmdate('D, d M Y H:i:s', $cache->created) .' GMT';
+  $etag = '"'.md5($last_modified).'"';
+
+  // See if the client has provided the required HTTP headers:
+  $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) : FALSE;
+  $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : FALSE;
+
+  if ($if_modified_since && $if_none_match
+      && $if_none_match == $etag // etag must match
+      && $if_modified_since == $last_modified) {  // if-modified-since must match
+    header('HTTP/1.1 304 Not Modified');
+    // All 304 responses must send an etag if the 200 response for the same object contained an etag
+    header("Etag: $etag");
+    exit();
+  }
 
-    // Determine if the browser accepts gzipped data.
-    if (@strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === FALSE && function_exists('gzencode')) {
-      // Strip the gzip header and run uncompress.
-      $cache->data = gzinflate(substr(substr($cache->data, 10), 0, -8));
-    }
-    elseif (function_exists('gzencode')) {
-      header('Content-Encoding: gzip');
-    }
+  // Send appropriate response:
+  header("Last-Modified: $last_modified");
+  header("ETag: $etag");
 
-    // Send the original request's headers. We send them one after
-    // another so PHP's header() function can deal with duplicate
-    // headers.
-    $headers = explode("\n", $cache->headers);
-    foreach ($headers as $header) {
-      header($header);
-    }
+  // The following headers force validation of cache:
+  header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
+  header("Cache-Control: must-revalidate");
 
-    print $cache->data;
-    bootstrap_invoke_all('exit');
-    exit();
+  // Determine if the browser accepts gzipped data.
+  if (@strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === FALSE && function_exists('gzencode')) {
+    // Strip the gzip header and run uncompress.
+    $cache->data = gzinflate(substr(substr($cache->data, 10), 0, -8));
   }
-  else {
-    header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
-    header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
-    header("Cache-Control: no-store, no-cache, must-revalidate");
-    header("Cache-Control: post-check=0, pre-check=0", FALSE);
-    header("Pragma: no-cache");
+  elseif (function_exists('gzencode')) {
+    header('Content-Encoding: gzip');
+  }
+
+  // Send the original request's headers. We send them one after
+  // another so PHP's header() function can deal with duplicate
+  // headers.
+  $headers = explode("\n", $cache->headers);
+  foreach ($headers as $header) {
+    header($header);
   }
+
+  print $cache->data;
 }
 
 /**
@@ -631,7 +630,6 @@ function drupal_anonymous_user($session 
  * @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_LATE_PAGE_CACHE: load bootstrap.inc and module.inc, start
@@ -639,7 +637,7 @@ function drupal_anonymous_user($session 
  *     DRUPAL_BOOTSTRAP_FULL: Drupal is fully loaded, validate and fix input data.
  */
 function drupal_bootstrap($phase) {
-  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);
+  static $phases = array(DRUPAL_BOOTSTRAP_CONFIGURATION, 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);
@@ -653,32 +651,31 @@ function _drupal_bootstrap($phase) {
   global $conf;
 
   switch ($phase) {
+    
     case DRUPAL_BOOTSTRAP_CONFIGURATION:
       drupal_unset_globals();
+      _drupal_cache_init($phase);
       // 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';
+      require_once variable_get('cache_inc', './includes/cache.inc');
       db_set_active();
+      // Initialize configuration variables, using values from settings.php if available.
+      $conf = variable_init(isset($conf) ? $conf : array());
       break;
 
     case DRUPAL_BOOTSTRAP_SESSION:
       require_once './includes/session.inc';
       session_set_save_handler("sess_open", "sess_close", "sess_read", "sess_write", "sess_destroy", "sess_gc");
       session_start();
+      _drupal_cache_init($phase);
       break;
 
     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');
@@ -690,8 +687,7 @@ function _drupal_bootstrap($phase) {
         exit();
       }
 
-      // Initialize configuration variables, using values from conf.php if available.
-      $conf = variable_init(isset($conf) ? $conf : array());
+      _drupal_cache_init($phase);
       drupal_page_header();
       break;
 
@@ -709,6 +705,36 @@ function _drupal_bootstrap($phase) {
 }
 
 /**
+ * Initialize the caching strategy, which loads at different stages within 
+ * Drupal's bootstrap process.
+ */
+function _drupal_cache_init($phase) {
+  if ($phase == DRUPAL_BOOTSTRAP_CONFIGURATION && variable_get('page_cache_fastpath', 0)) {
+    require_once variable_get('cache_inc', './includes/cache.inc');
+    if (page_cache_fastpath()) {
+      exit();
+    }
+  }
+  elseif ($phase == DRUPAL_BOOTSTRAP_SESSION && variable_get('cache', CACHE_DISABLED) == CACHE_EXPERT) {
+    require_once variable_get('cache_inc', './includes/cache.inc');
+    if ($cache = page_get_cache()) {
+      drupal_page_cache_header($cache);
+      exit();
+    }
+  }
+  elseif ($phase == DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE && variable_get('cache', 0)) {
+    // cache.inc should already be loaded with this late of phase since other
+    // module rely on the caching API.
+    if ($cache = page_get_cache()) {
+      bootstrap_invoke_all('init');
+      drupal_page_cache_header($cache);
+      bootstrap_invoke_all('exit');
+      exit();
+    }
+  }
+}
+
+/**
  * Enables use of the theme system without requiring database access. Since
  * there is not database access no theme will be enabled and the default
  * themeable functions will be called. Some themeable functions can not be used
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.352
diff -u -F^f -r1.352 system.module
--- modules/system/system.module	27 Aug 2006 12:54:01 -0000	1.352
+++ modules/system/system.module	29 Aug 2006 04:20:56 -0000
@@ -34,6 +34,8 @@ function system_help($section) {
       return t('Handles general site configuration for administrators.');
     case 'admin':
       return t('<p>Welcome to the administration section. Here you may control how your site functions.</p>');
+    case 'admin/settings/page-caching':
+      return t('Enabling the cache will offer a sufficient performance boost for most low-traffic and medium-traffic sites. Drupal can store and send compressed cached pages requested by "anonymous" users. By caching a web page, Drupal does not have to create the page each time someone wants to view it.');
     case 'admin/build/themes':
       return t('<p>Select which themes are available to your users and specify the default theme. To configure site-wide display settings, click the "configure" task above. Alternately, to override these settings in a specific theme, click the "configure" link for the corresponding theme. Note that different themes may have different regions available for rendering content like blocks. If you want consistency in what your users see, you may wish to enable only one theme.</p>');
     case 'admin/build/themes/settings':
@@ -586,12 +588,18 @@ function system_error_reporting_settings
 
 function system_page_caching_settings() {
 
+  $problem_modules = array_unique(array_merge(module_implements('init'), module_implements('exit')));
+  sort($problem_modules);
+  if (!is_array($problem_modules)) {
+    $problem_modules = array(t('no incompatibilities found'));
+  }
+
   $form['cache'] = array(
     '#type' => 'radios',
-    '#title' => t('Page cache'),
+    '#title' => t('Caching strategy'),
     '#default_value' => variable_get('cache', CACHE_DISABLED),
-    '#options' => array(CACHE_DISABLED => t('Disabled'), CACHE_ENABLED => t('Enabled')),
-    '#description' => t("Drupal has a caching mechanism which stores dynamically generated web pages in a database. By caching a web page, Drupal does not have to create the page each time someone wants to view it, instead it takes only one SQL query to display it, reducing response time and the server's load. Only pages requested by \"anonymous\" users are cached. In order to reduce server load and save bandwidth, Drupal stores and sends compressed cached pages.")
+    '#options' => array(CACHE_DISABLED => t('Disabled'), CACHE_STANDARD => t('Recommended'), CACHE_EXPERT => t('Expert (possible side effects)')),
+    '#description' => t("The 'Recommended' cache option is suitable for most sites without any side effects. 'Expert' caching causes Drupal to skip the loading of enabled modules when serving a cached page for a performance boost.  The following enabled modules are incompatible with expert caching and will be impaired: %modules", array('%modules' => implode(', ', $problem_modules)))
   );
 
   $period = drupal_map_assoc(array(0, 60, 180, 300, 600, 900, 1800, 2700, 3600, 10800, 21600, 32400, 43200, 86400), 'format_interval');
