Index: install.php
===================================================================
RCS file: /cvs/drupal/drupal/install.php,v
retrieving revision 1.113.2.10
diff -u -9 -p -r1.113.2.10 install.php
--- install.php	1 Mar 2010 09:36:01 -0000	1.113.2.10
+++ install.php	24 Mar 2010 14:07:06 -0000
@@ -34,56 +34,55 @@ function install_main() {
 
   // Load module basics (needed for hook invokes).
   include_once './includes/module.inc';
   $module_list['system']['filename'] = 'modules/system/system.module';
   $module_list['filter']['filename'] = 'modules/filter/filter.module';
   module_list(TRUE, FALSE, FALSE, $module_list);
   drupal_load('module', 'system');
   drupal_load('module', 'filter');
 
+  // Load the cache infrastructure using a "fake" cache implementation that
+  // does not attempt to write to the database. We need this during the initial
+  // part of the installer because the database is not available yet. We
+  // continue to use it even when the database does become available, in order
+  // to preserve consistency between interactive and command-line installations
+  // (the latter complete in one page request and therefore are forced to
+  // continue using the cache implementation they started with) and also
+  // because any data put in the cache during the installer is inherently
+  // suspect, due to the fact that Drupal is not fully set up yet.
+  require_once './includes/cache-install.inc';
+  $conf['cache_inc'] = './includes/cache-install.inc';
+
   // Install profile chosen, set the global immediately.
   // This needs to be done before the theme cache gets 
   // initialized in drupal_maintenance_theme().
   if (!empty($_GET['profile'])) {
     $profile = preg_replace('/[^a-zA-Z_0-9]/', '', $_GET['profile']);
   }
 
   // Set up theme system for the maintenance page.
   drupal_maintenance_theme();
 
   // Check existing settings.php.
   $verify = install_verify_settings();
 
   if ($verify) {
-    // Since we have a database connection, we use the normal cache system.
-    // This is important, as the installer calls into the Drupal system for
-    // the clean URL checks, so we should maintain the cache properly.
-    require_once './includes/cache.inc';
-    $conf['cache_inc'] = './includes/cache.inc';
-
     // Establish a connection to the database.
     require_once './includes/database.inc';
     db_set_active();
 
     // Check if Drupal is installed.
     $task = install_verify_drupal();
     if ($task == 'done') {
       install_already_done_error();
     }
   }
   else {
-    // Since no persistent storage is available yet, and functions that check
-    // for cached data will fail, we temporarily replace the normal cache
-    // system with a stubbed-out version that short-circuits the actual
-    // caching process and avoids any errors.
-    require_once './includes/cache-install.inc';
-    $conf['cache_inc'] = './includes/cache-install.inc';
-
     $task = NULL;
   }
 
   // No profile was passed in GET, ask the user.
   if (empty($_GET['profile'])) {
     if ($profile = install_select_profile()) {
       install_goto("install.php?profile=$profile");
     }
     else {
@@ -802,29 +801,26 @@ if (Drupal.jsEnabled) {
     drupal_set_title(st('@drupal installation complete', array('@drupal' => drupal_install_profile_name())));
     $messages = drupal_set_message();
     $output = '<p>'. st('Congratulations, @drupal has been successfully installed.', array('@drupal' => drupal_install_profile_name())) .'</p>';
     $output .= '<p>'. (isset($messages['error']) ? st('Please review the messages above before continuing on to <a href="@url">your new site</a>.', array('@url' => url(''))) : st('You may now visit <a href="@url">your new site</a>.', array('@url' => url('')))) .'</p>';
     $task = 'done';
   }
 
   // The end of the install process. Remember profile used.
   if ($task == 'done') {
-    // Rebuild menu to get content type links registered by the profile,
-    // and possibly any other menu items created through the tasks.
-    menu_rebuild();
+    // Flush all caches to ensure that any full bootstraps during the installer
+    // do not leave stale cached data, and that any content types or other items
+    // registered by the install profile are registered correctly.
+    drupal_flush_all_caches();
 
     // Register actions declared by any modules.
     actions_synchronize();
 
-    // Randomize query-strings on css/js files, to hide the fact that
-    // this is a new install, not upgraded yet.
-    _drupal_flush_css_js();
-
     variable_set('install_profile', $profile);
   }
 
   // Set task for user, and remember the task in the database.
   install_task_list($task);
   variable_set('install_task', $task);
 
   // Output page, if some output was required. Otherwise it is possible
   // that we are printing a JSON page and theme output should not be there.
Index: update.php
===================================================================
RCS file: /cvs/drupal/drupal/update.php,v
retrieving revision 1.252.2.3
diff -u -9 -p -r1.252.2.3 update.php
--- update.php	30 Mar 2009 11:15:11 -0000	1.252.2.3
+++ update.php	24 Mar 2010 14:07:06 -0000
@@ -1,9 +1,10 @@
+
 <?php
 // $Id: update.php,v 1.252.2.3 2009/03/30 11:15:11 goba Exp $
 
 /**
  * @file
  * Administrative page for handling updates from one Drupal version to another.
  *
  * Point your browser to "http://www.example.com/update.php" and follow the
  * instructions.
@@ -575,18 +576,20 @@ if (empty($op)) {
   require_once './includes/install.inc';
   require_once './includes/file.inc';
   require_once './modules/system/system.install';
 
   // Load module basics.
   include_once './includes/module.inc';
   $module_list['system']['filename'] = 'modules/system/system.module';
   $module_list['filter']['filename'] = 'modules/filter/filter.module';
   module_list(TRUE, FALSE, FALSE, $module_list);
+  module_implements('', FALSE, TRUE);
+
   drupal_load('module', 'system');
   drupal_load('module', 'filter');
 
   // Set up $language, since the installer components require it.
   drupal_init_language();
 
   // Set up theme system for the maintenance page.
   drupal_maintenance_theme();
 
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.756.2.80
diff -u -9 -p -r1.756.2.80 common.inc
--- includes/common.inc	4 Mar 2010 00:25:13 -0000	1.756.2.80
+++ includes/common.inc	24 Mar 2010 14:07:07 -0000
@@ -1617,18 +1617,21 @@ function l($text, $path, $options = arra
  * This function sets the page cache if appropriate, and allows modules to
  * react to the closing of the page by calling hook_exit().
  */
 function drupal_page_footer() {
   if (variable_get('cache', CACHE_DISABLED) != CACHE_DISABLED) {
     page_set_cache();
   }
 
   module_invoke_all('exit');
+
+  // Update the hook implementation cache.
+  module_implements('', FALSE, FALSE, TRUE);
 }
 
 /**
  * Form an associative array from a linear array.
  *
  * This function walks through the provided array and constructs an associative
  * array out of it. The keys of the resulting array will be the values of the
  * input array. The values will be the same as the keys unless a function is
  * specified, in which case the output of the function is used for the values
Index: includes/module.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/module.inc,v
retrieving revision 1.115.2.3
diff -u -9 -p -r1.115.2.3 module.inc
--- includes/module.inc	16 Nov 2009 17:17:35 -0000	1.115.2.3
+++ includes/module.inc	24 Mar 2010 14:07:07 -0000
@@ -400,39 +400,89 @@ function module_hook($module, $hook) {
 
 /**
  * Determine which modules are implementing a hook.
  *
  * @param $hook
  *   The name of the hook (e.g. "help" or "menu").
  * @param $sort
  *   By default, modules are ordered by weight and filename, settings this option
  *   to TRUE, module list will be ordered by module name.
- * @param $refresh
+ * @param $reset
  *   For internal use only: Whether to force the stored list of hook
  *   implementations to be regenerated (such as after enabling a new module,
  *   before processing hook_enable).
+ * @param $write_cache
+ *   For internal use only: Update the persistent cache of hook implementations.
  * @return
  *   An array with the names of the modules which are implementing this hook.
  */
-function module_implements($hook, $sort = FALSE, $refresh = FALSE) {
+function module_implements($hook, $sort = FALSE, $reset = FALSE, $write_cache = FALSE) {
   static $implementations;
 
-  if ($refresh) {
+  // We maintain a persistent cache of hook implementations in addition to the
+  // static cache to avoid looping through every module and every hook on each
+  // request. Benchmarks show that the benefit of this caching outweighs the
+  // additional database hit even when using the default database caching
+  // backend and only a small number of modules are enabled. The cost of the
+  // cache_get() is more or less constant and reduced further when non-database
+  // caching backends are used, so there will be more significant gains when a
+  // large number of modules are installed or hooks invoked, since this can
+  // quickly lead to module_hook() being called several thousand times
+  // per request.
+  if ($reset) {
     $implementations = array();
+    cache_set('module_implements', array());
     return;
   }
 
+  if ($write_cache) {
+    // Check whether we should write the cache. We do not want to cache hooks
+    // which are only invoked on HTTP POST requests since these do not need to
+    // be optimized as tightly, and not doing so keeps the cache entry smaller.
+    if (isset($implementations['#write_cache']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD')) {
+      unset($implementations['#write_cache']);
+      cache_set('module_implements', $implementations);
+    }
+    return;
+  }
+
+  // Fetch implementations from cache.
+  if (empty($implementations)) {
+    $cache = cache_get('module_implements');
+    if (!$cache) {
+      $implementations = array();
+    }
+    else {
+      $implementations = $cache->data;
+    }
+  }
+
   if (!isset($implementations[$hook])) {
     $implementations[$hook] = array();
     $list = module_list(FALSE, TRUE, $sort);
     foreach ($list as $module) {
       if (module_hook($module, $hook)) {
-        $implementations[$hook][] = $module;
+        $implementations[$hook][$module] = $module;
+        // We added something to the cache, so write it when we are done.
+        $implementations['#write_cache'] = TRUE;
+      }
+    }
+  }
+  else {
+    foreach ($implementations[$hook] as $module) {
+      // It is possible that a module removed a hook implementation without the
+      // implementations cache being rebuilt yet, so we check module_hook() on
+      // each request to avoid undefined function errors.
+      if (!module_hook($module, $hook)) {
+        // Clear out the stale implementation from the cache and force a cache
+        // refresh to forget about no longer existing hook implementations.
+        unset($implementations[$hook][$module]);
+        $implementations['#write_cache'] = TRUE;
       }
     }
   }
 
   // The explicit cast forces a copy to be made. This is needed because
   // $implementations[$hook] is only a reference to an element of
   // $implementations and if there are nested foreaches (due to nested node
   // API calls, for example), they would both manipulate the same array's
   // references, which causes some modules' hooks not to be called.
