? module_implements.patch ? module_implements_2.patch ? simpletest-speedup.patch ? sites/default/files ? sites/default/settings.php Index: index.php =================================================================== RCS file: /cvs/drupal/drupal/index.php,v retrieving revision 1.95 diff -u -p -r1.95 index.php --- index.php 21 Aug 2008 19:36:35 -0000 1.95 +++ index.php 12 Sep 2008 04:40:59 -0000 @@ -14,6 +14,7 @@ require_once './includes/bootstrap.inc'; drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); + $return = menu_execute_active_handler(); // Menu status constants are integers; page content is a string. Index: includes/bootstrap.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v retrieving revision 1.224 diff -u -p -r1.224 bootstrap.inc --- includes/bootstrap.inc 8 Sep 2008 21:24:30 -0000 1.224 +++ includes/bootstrap.inc 12 Sep 2008 04:40:59 -0000 @@ -820,7 +820,7 @@ function watchdog($type, $message, $vari ); // Call the logging hooks to log/process the message - foreach (module_implements('watchdog', TRUE) as $module) { + foreach (module_implements('watchdog') as $module) { module_invoke($module, 'watchdog', $log_message); } } @@ -1430,31 +1430,6 @@ function registry_rebuild() { } /** - * Save hook implementations cache. - * - * @param $hook - * Array with the hook name and list of modules that implement it. - * @param $write_to_persistent_cache - * Whether to write to the persistent cache. - */ -function registry_cache_hook_implementations($hook, $write_to_persistent_cache = FALSE) { - static $implementations; - - if ($hook) { - // Newer is always better, so overwrite anything that's come before. - $implementations[$hook['hook']] = $hook['modules']; - } - - if ($write_to_persistent_cache === TRUE) { - // Only write this to cache if the implementations data we are going to cache - // is different to what we loaded earlier in the request. - if ($implementations != module_implements()) { - cache_set('hooks', $implementations, 'cache_registry'); - } - } -} - -/** * Save the files required by the registry for this path. */ function registry_cache_path_files() { Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.792 diff -u -p -r1.792 common.inc --- includes/common.inc 10 Sep 2008 04:13:01 -0000 1.792 +++ includes/common.inc 12 Sep 2008 04:41:01 -0000 @@ -640,7 +640,7 @@ function _drupal_get_last_caller($backtr // The first trace is the call itself. // It gives us the line and the file of the last call. $call = $backtrace[0]; - + // The second call give us the function where the call originated. if (isset($backtrace[1])) { if (isset($backtrace[1]['class'])) { @@ -1526,7 +1526,7 @@ function drupal_page_footer() { module_invoke_all('exit'); - registry_cache_hook_implementations(FALSE, TRUE); + module_implements(); registry_cache_path_files(); } Index: includes/menu.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/menu.inc,v retrieving revision 1.288 diff -u -p -r1.288 menu.inc --- includes/menu.inc 5 Sep 2008 08:24:08 -0000 1.288 +++ includes/menu.inc 12 Sep 2008 04:41:03 -0000 @@ -1726,7 +1726,7 @@ function menu_router_build($reset = FALS // We need to manually call each module so that we can know which module // a given item came from. $callbacks = array(); - foreach (module_implements('menu', NULL, TRUE) as $module) { + foreach (module_implements('menu') as $module) { $router_items = call_user_func($module . '_menu'); if (isset($router_items) && is_array($router_items)) { foreach (array_keys($router_items) as $path) { @@ -1884,7 +1884,7 @@ function _menu_delete_item($item, $force * - plid The mlid of the parent. * - router_path The path of the relevant router item. * @return - * The mlid of the saved menu link, or FALSE if the menu link could not be + * The mlid of the saved menu link, or FALSE if the menu link could not be * saved. */ function menu_link_save(&$item) { Index: includes/module.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/module.inc,v retrieving revision 1.124 diff -u -p -r1.124 module.inc --- includes/module.inc 21 Aug 2008 19:36:36 -0000 1.124 +++ includes/module.inc 12 Sep 2008 04:41:05 -0000 @@ -384,9 +384,6 @@ function module_hook($module, $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 * For internal use only: Whether to force the stored list of hook * implementations to be regenerated (such as after enabling a new module, @@ -396,32 +393,63 @@ function module_hook($module, $hook) { * An array with the names of the modules which are implementing this hook. * If $hook is NULL then it will return the implementation cache. */ -function module_implements($hook = NULL, $sort = FALSE, $refresh = FALSE) { - static $implementations = array(); +function module_implements($hook = NULL, $refresh = FALSE) { + static $implementations = array(), $loaded = array(), $cache; - if (!isset($hook)) { + if (defined('MAINTENANCE_MODE')) { + $implementations = array(); + foreach (module_list() as $module) { + if (module_hook($module, $hook)) { + $implementations[] = $module; + } + } return $implementations; } if ($refresh) { $implementations = array(); + $loaded = array(); + cache_clear_all('hooks', 'cache_registry'); } - if (!defined('MAINTENANCE_MODE') && empty($implementations) && ($cache = cache_get('hooks', 'cache_registry'))) { + if (!$hook) { + // Only write this to cache if the implementations data we are going to cache + // is different to what we loaded earlier in the request. + if (!$refresh && $cache && $implementations != $cache->data) { + cache_set('hooks', $implementations, 'cache_registry'); + } + return; + } + + if (empty($implementations) && ($cache = cache_get('hooks', 'cache_registry'))) { $implementations = $cache->data; } - if ($hook) { + if (empty($loaded[$hook])) { + if (isset($implementations[$hook])) { + $cached = TRUE; + // The implementations may not be in memory yet. + foreach ($implementations[$hook] as $module) { + $function = $module .'_'. $hook; + // If the implementations are already cached but there are functions + // to be looked up, then we discard the cache. The per router path + // caching will make this rare. + if (!function_exists($function)) { + unset($implementations[$hook]); + break; + } + } + } if (!isset($implementations[$hook])) { $implementations[$hook] = array(); - foreach (module_list() as $module) { - if (module_hook($module, $hook)) { - $implementations[$hook][] = $module; - } + $result = db_query("SELECT name, filename, module FROM {registry} WHERE type = 'function' AND hook = '%s'", $hook); + while ($function = db_fetch_object($result)) { + $implementations[$hook][] = $function->module; + drupal_function_exists($function->name); } } - registry_cache_hook_implementations(array('hook' => $hook, 'modules' => $implementations[$hook])); - - return $implementations[$hook]; + $loaded[$hook] = TRUE; } + + return $implementations[$hook]; } /** Index: includes/registry.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/registry.inc,v retrieving revision 1.3 diff -u -p -r1.3 registry.inc --- includes/registry.inc 21 Aug 2008 19:36:36 -0000 1.3 +++ includes/registry.inc 12 Sep 2008 04:41:05 -0000 @@ -45,7 +45,7 @@ function _registry_rebuild() { if ($module->status) { $dir = dirname($module->filename); foreach ($module->info['files'] as $file) { - $files["./$dir/$file"] = array(); + $files["./$dir/$file"] = array('module' => $module); } } } @@ -67,6 +67,7 @@ function _registry_rebuild() { } _registry_parse_files($files); + module_implements('', FALSE, TRUE); cache_clear_all('*', 'cache_registry', TRUE); } @@ -84,7 +85,7 @@ function registry_get_parsed_files() { * Parse all files that have changed since the registry was last built, and save their function and class listings. * * @param $files - * The list of files to check and parse. + * The list of files to check and parse. */ function _registry_parse_files($files) { $changed_files = array(); @@ -95,7 +96,7 @@ function _registry_parse_files($files) { if ($new_file || $md5 != $file['md5']) { // We update the md5 after we've saved the files resources rather than here, so if we // don't make it through this rebuild, the next run will reparse the file. - _registry_parse_file($filename, $contents); + _registry_parse_file($filename, $file, $contents); $file['md5'] = $md5; db_merge('registry_file') ->key(array('filename' => $filename)) @@ -109,11 +110,13 @@ function _registry_parse_files($files) { * Parse a file and save its function and class listings. * * @param $filename - * Name of the file we are going to parse. + * Name of the file we are going to parse. + * @param $file + * An associative array about the file. Only the module key is used. * @param $contents - * Contents of the file we are going to parse as a string. + * Contents of the file we are going to parse as a string. */ -function _registry_parse_file($filename, $contents) { +function _registry_parse_file($filename, $file, $contents) { static $map = array(T_FUNCTION => 'function', T_CLASS => 'class', T_INTERFACE => 'interface'); // Delete registry entries for this file, so we can insert the new resources. db_delete('registry')->condition('filename', $filename)->execute(); @@ -123,6 +126,20 @@ function _registry_parse_file($filename, if (is_array($token) && isset($map[$token[0]])) { $type = $map[$token[0]]; if ($resource_name = _registry_get_resource_name($tokens, $type)) { + $hook = ''; + $module = ''; + if ($type == 'function' && isset($file['module'])) { + $module = $file['module']->name; + $n = strlen($module); + if (substr($resource_name, 0, $n) == $module) { + $hook = substr($resource_name, $n + 1); + } + } + $fields = array( + 'filename' => $filename, + 'module' => $module, + 'hook' => $hook, + ); // Because some systems, such as cache, currently use duplicate function // names in separate files an insert query cannot be used here as it // would cause a key constraint violation. Instead we use a merge query. @@ -132,7 +149,7 @@ function _registry_parse_file($filename, // filename instead of another. // TODO: Convert this back to an insert query after all duplicate // function names have been purged from Drupal. - db_merge('registry')->key(array('name' => $resource_name, 'type' => $type))->fields(array('filename' => $filename))->execute(); + db_merge('registry')->key(array('name' => $resource_name, 'type' => $type))->fields($fields)->execute(); // We skip the body because classes may contain functions. _registry_skip_body($tokens); Index: modules/simpletest/tests/registry.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/registry.test,v retrieving revision 1.1 diff -u -p -r1.1 registry.test --- modules/simpletest/tests/registry.test 14 Aug 2008 09:18:28 -0000 1.1 +++ modules/simpletest/tests/registry.test 12 Sep 2008 04:41:05 -0000 @@ -29,7 +29,7 @@ class RegistryParseFileTestCase extends * testRegistryParseFile */ function testRegistryParseFile() { - _registry_parse_file($this->fileName, $this->getFileContents()); + _registry_parse_file($this->fileName, array(), $this->getFileContents()); foreach (array('functionName', 'className', 'interfaceName') as $resource) { $foundName = db_result(db_query("SELECT name FROM {registry} WHERE name = '%s'", $this->$resource)); $this->assertTrue($this->$resource == $foundName, t('Resource "@resource" found.', array('@resource' => $this->$resource))); Index: modules/system/system.install =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.install,v retrieving revision 1.263 diff -u -p -r1.263 system.install --- modules/system/system.install 6 Sep 2008 08:36:21 -0000 1.263 +++ modules/system/system.install 12 Sep 2008 04:41:06 -0000 @@ -1091,6 +1091,18 @@ function system_schema() { 'length' => 255, 'not null' => TRUE, ), + 'module' => array( + 'description' => t('Name of the module the file belongs to.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ), + 'hook' => array( + 'description' => t('Name of the hook this function implements, if any.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ), ), 'primary key' => array('name', 'type'), );