Merge lp:~catch-drupal/pressflow/pressflow_implements into lp:pressflow

Proposed by Nathaniel Catchpole
Status: Rejected
Rejected by: David Strauss
Proposed branch: lp:~catch-drupal/pressflow/pressflow_implements
Merge into: lp:pressflow
Diff against target: 206 lines (+78/-27)
5 files modified
includes/common.inc (+2/-0)
includes/module.inc (+56/-5)
includes/path.inc (+1/-1)
install.php (+16/-20)
update.php (+3/-1)
To merge this branch: bzr merge lp:~catch-drupal/pressflow/pressflow_implements
Reviewer Review Type Date Requested Status
Pressflow Administrators Pending
Review via email: mp+49769@code.launchpad.net

This proposal supersedes a proposal from 2010-11-15.

Description of the change

Backport of Drupal 7 module_implements() caching. Adds one extra change to path.inc since the return value of $modules is now an associative array instead of numeric, otherwise identical to the core patch.

On a site with 150 modules instead, this reduced page execution time of module_implements() from around 4% of the request to less than 1%.

To post a comment you must log in.
100. By Nathaniel <catch@catch-toshiba>

Merging in trunk.

Revision history for this message
David Strauss (davidstrauss) wrote :

Pressflow 6 is now maintained on GitHub, so I'm marking this merge as rejected.

Unmerged revisions

100. By Nathaniel <catch@catch-toshiba>

Merging in trunk.

99. By Nathaniel Catchpole <catch@catch-laptop>

Merge in trunk.

98. By Nathaniel Catchpole <catch@catch-laptop>

 is now an associative array, so use reset instead of a hard-coded index.

97. By Nathaniel Catchpole <catch@catch-laptop>

#557542: module_implements() caching.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'includes/common.inc'
2--- includes/common.inc 2011-06-01 07:13:05 +0000
3+++ includes/common.inc 2011-07-25 06:23:28 +0000
4@@ -1619,6 +1619,8 @@
5 if ($cache != CACHE_DISABLED && $cache != CACHE_EXTERNAL) {
6 page_set_cache();
7 }
8+ // Update the hook implementation cache.
9+ module_implements('', FALSE, FALSE, TRUE);
10
11 module_invoke_all('exit');
12 }
13
14=== modified file 'includes/module.inc'
15--- includes/module.inc 2011-05-26 02:56:05 +0000
16+++ includes/module.inc 2011-07-25 06:23:28 +0000
17@@ -405,27 +405,78 @@
18 * @param $sort
19 * By default, modules are ordered by weight and filename, settings this option
20 * to TRUE, module list will be ordered by module name.
21- * @param $refresh
22+ * @param $reset
23 * For internal use only: Whether to force the stored list of hook
24 * implementations to be regenerated (such as after enabling a new module,
25 * before processing hook_enable).
26+ * @param $write_cache
27+ * For internal use only: Update the persistent cache of hook implementations.
28 * @return
29 * An array with the names of the modules which are implementing this hook.
30 */
31-function module_implements($hook, $sort = FALSE, $refresh = FALSE) {
32+function module_implements($hook, $sort = FALSE, $reset = FALSE, $write_cache = FALSE) {
33 static $implementations;
34
35- if ($refresh) {
36+ // We maintain a persistent cache of hook implementations in addition to the
37+ // static cache to avoid looping through every module and every hook on each
38+ // request. Benchmarks show that the benefit of this caching outweighs the
39+ // additional database hit even when using the default database caching
40+ // backend and only a small number of modules are enabled. The cost of the
41+ // cache_get() is more or less constant and reduced further when non-database
42+ // caching backends are used, so there will be more significant gains when a
43+ // large number of modules are installed or hooks invoked, since this can
44+ // quickly lead to module_hook() being called several thousand times
45+ // per request.
46+ if ($reset) {
47 $implementations = array();
48- return;
49+ cache_set('module_implements', array());
50+ return;
51+ }
52+
53+ if ($write_cache) {
54+ // Check whether we should write the cache. We do not want to cache hooks
55+ // which are only invoked on HTTP POST requests since these do not need to
56+ // be optimized as tightly, and not doing so keeps the cache entry smaller.
57+ if (isset($implementations['#write_cache']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD')) {
58+ unset($implementations['#write_cache']);
59+ cache_set('module_implements', $implementations);
60+ }
61+ return;
62+ }
63+
64+ // Fetch implementations from cache.
65+ if (empty($implementations)) {
66+ $cache = cache_get('module_implements');
67+ if (!$cache) {
68+ $implementations = array();
69+ }
70+ else {
71+ $implementations = $cache->data;
72+ }
73 }
74
75 if (!isset($implementations[$hook])) {
76+ // The hook is not cached, so ensure that whether or not it has
77+ // implementations, that the cache is updated at the end of the request.
78+ $implementations['#write_cache'] = TRUE;
79 $implementations[$hook] = array();
80 $list = module_list(FALSE, TRUE, $sort);
81 foreach ($list as $module) {
82 if (module_hook($module, $hook)) {
83- $implementations[$hook][] = $module;
84+ $implementations[$hook][$module] = $module;
85+ }
86+ }
87+ }
88+ else {
89+ foreach ($implementations[$hook] as $module) {
90+ // It is possible that a module removed a hook implementation without the
91+ // implementations cache being rebuilt yet, so we check module_hook() on
92+ // each request to avoid undefined function errors.
93+ if (!module_hook($module, $hook)) {
94+ // Clear out the stale implementation from the cache and force a cache
95+ // refresh to forget about no longer existing hook implementations.
96+ unset($implementations[$hook][$module]);
97+ $implementations['#write_cache'] = TRUE;
98 }
99 }
100 }
101
102=== modified file 'includes/path.inc'
103--- includes/path.inc 2011-05-26 02:58:29 +0000
104+++ includes/path.inc 2011-07-25 06:23:28 +0000
105@@ -50,7 +50,7 @@
106 if (!isset($hook_module)) {
107 $modules = module_implements('lookup_path');
108 if (count($modules) > 0) {
109- $hook_module = $modules[0];
110+ $hook_module = reset($modules);
111 } else {
112 $hook_module = FALSE;
113 }
114
115=== modified file 'install.php'
116--- install.php 2011-05-26 02:58:29 +0000
117+++ install.php 2011-07-25 06:23:28 +0000
118@@ -47,6 +47,18 @@
119 drupal_load('module', 'system');
120 drupal_load('module', 'filter');
121
122+ // Load the cache infrastructure using a "fake" cache implementation that
123+ // does not attempt to write to the database. We need this during the initial
124+ // part of the installer because the database is not available yet. We
125+ // continue to use it even when the database does become available, in order
126+ // to preserve consistency between interactive and command-line installations
127+ // (the latter complete in one page request and therefore are forced to
128+ // continue using the cache implementation they started with) and also
129+ // because any data put in the cache during the installer is inherently
130+ // suspect, due to the fact that Drupal is not fully set up yet.
131+ require_once './includes/cache-install.inc';
132+ $conf['cache_inc'] = './includes/cache-install.inc';
133+
134 // Install profile chosen, set the global immediately.
135 // This needs to be done before the theme cache gets
136 // initialized in drupal_maintenance_theme().
137@@ -61,12 +73,6 @@
138 $verify = install_verify_settings();
139
140 if ($verify) {
141- // Since we have a database connection, we use the normal cache system.
142- // This is important, as the installer calls into the Drupal system for
143- // the clean URL checks, so we should maintain the cache properly.
144- require_once './includes/cache.inc';
145- $conf['cache_inc'] = './includes/cache.inc';
146-
147 // Establish a connection to the database.
148 require_once './includes/database.inc';
149 db_set_active();
150@@ -78,13 +84,6 @@
151 }
152 }
153 else {
154- // Since no persistent storage is available yet, and functions that check
155- // for cached data will fail, we temporarily replace the normal cache
156- // system with a stubbed-out version that short-circuits the actual
157- // caching process and avoids any errors.
158- require_once './includes/cache-install.inc';
159- $conf['cache_inc'] = './includes/cache-install.inc';
160-
161 $task = NULL;
162 }
163
164@@ -815,17 +814,14 @@
165
166 // The end of the install process. Remember profile used.
167 if ($task == 'done') {
168- // Rebuild menu to get content type links registered by the profile,
169- // and possibly any other menu items created through the tasks.
170- menu_rebuild();
171+ // Flush all caches to ensure that any full bootstraps during the installer
172+ // do not leave stale cached data, and that any content types or other items
173+ // registered by the install profile are registered correctly.
174+ drupal_flush_all_caches();
175
176 // Register actions declared by any modules.
177 actions_synchronize();
178
179- // Randomize query-strings on css/js files, to hide the fact that
180- // this is a new install, not upgraded yet.
181- _drupal_flush_css_js();
182-
183 variable_set('install_profile', $profile);
184 }
185
186
187=== modified file 'update.php'
188--- update.php 2011-05-26 02:58:29 +0000
189+++ update.php 2011-07-25 06:23:28 +0000
190@@ -594,7 +594,7 @@
191 $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
192 if (empty($op)) {
193 // Minimum load of components.
194- drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
195+ drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
196
197 require_once './includes/install.inc';
198 require_once './includes/file.inc';
199@@ -605,6 +605,8 @@
200 $module_list['system']['filename'] = 'modules/system/system.module';
201 $module_list['filter']['filename'] = 'modules/filter/filter.module';
202 module_list(TRUE, FALSE, FALSE, $module_list);
203+ module_implements('', FALSE, TRUE);
204+
205 drupal_load('module', 'system');
206 drupal_load('module', 'filter');
207

Subscribers

People subscribed via source and target branches

to status/vote changes: