Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions includes/common.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1621,6 +1621,9 @@ function drupal_page_footer() {
}

module_invoke_all('exit');

// Update the hook implementation cache.
module_implements('', FALSE, FALSE, TRUE);
}

/**
Expand Down
70 changes: 62 additions & 8 deletions includes/module.inc
Original file line number Diff line number Diff line change
Expand Up @@ -242,15 +242,15 @@ function module_load_install($module) {

/**
* Load a module include file.
*
*
* Examples:
* @code
* // Load node.admin.inc from the node module.
* module_load_include('inc', 'node', 'node.admin');
* // Load content_types.inc from the node module.
* module_load_include('inc', 'node', 'content_types');
* module_load_include('inc', 'node', 'content_types');
* @endcode
*
*
* Do not use this function to load an install file. Use module_load_install()
* instead.
*
Expand All @@ -259,7 +259,7 @@ function module_load_install($module) {
* @param $module
* The module to which the include file belongs.
* @param $name
* Optionally, specify the base file name (without the $type extension).
* Optionally, specify the base file name (without the $type extension).
* If not set, $module is used.
*/
function module_load_include($type, $module, $name = NULL) {
Expand Down Expand Up @@ -405,22 +405,62 @@ function module_hook($module, $hook) {
* @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) {
static $verified;

// 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();
$verified = 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])) {
// The hook is not cached, so ensure that whether or not it has
// implementations, that the cache is updated at the end of the request.
$implementations['#write_cache'] = TRUE;
$implementations[$hook] = array();
$list = module_list(FALSE, TRUE, $sort);
foreach ($list as $module) {
Expand All @@ -429,6 +469,20 @@ function module_implements($hook, $sort = FALSE, $refresh = FALSE) {
}
}
}
elseif (empty($verified[$hook])) {
foreach ($implementations[$hook] as $key => $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][$key]);
$implementations['#write_cache'] = TRUE;
}
}
$verified[$hook] = TRUE;
}

// The explicit cast forces a copy to be made. This is needed because
// $implementations[$hook] is only a reference to an element of
Expand Down
36 changes: 16 additions & 20 deletions install.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ function install_main() {
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().
Expand All @@ -61,12 +73,6 @@ function install_main() {
$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();
Expand All @@ -78,13 +84,6 @@ function install_main() {
}
}
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;
}

Expand Down Expand Up @@ -815,17 +814,14 @@ function install_tasks($profile, $task) {

// 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);
}

Expand Down
4 changes: 3 additions & 1 deletion update.php
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ function update_check_requirements() {
$op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
if (empty($op)) {
// Minimum load of components.
drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);

require_once './includes/install.inc';
require_once './includes/file.inc';
Expand All @@ -605,6 +605,8 @@ function update_check_requirements() {
$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');

Expand Down