? includes/handlers.inc ? modules/system/system.path_lazy.inc ? modules/system/system.path_precache.inc Index: includes/bootstrap.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v retrieving revision 1.275 diff -u -p -r1.275 bootstrap.inc --- includes/bootstrap.inc 19 Apr 2009 19:10:07 -0000 1.275 +++ includes/bootstrap.inc 22 Apr 2009 02:48:45 -0000 @@ -1215,6 +1215,8 @@ function _drupal_bootstrap($phase) { exit; } // Prepare for non-cached page workflow. + require_once DRUPAL_ROOT . '/' . variable_get('lock_inc', 'includes/lock.inc'); + lock_init(); drupal_page_header(); // If the session has not already been started and output buffering is // not enabled, the session must be started now before the HTTP headers Index: includes/lock.inc =================================================================== RCS file: includes/lock.inc diff -N includes/lock.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/lock.inc 22 Apr 2009 02:48:45 -0000 @@ -0,0 +1,181 @@ + $lock['expire']) { + db_query("DELETE FROM {semaphore} WHERE name = '%s' AND value = '%s'", $name, $lock['value']); + return (bool)db_affected_rows(); + } + return FALSE; +} + +/** + * Wait for a lock to be released. + * + * @param $name + * The name of the lock. + * @param $delay + * The maximum number of seconds to wait. + * @return TRUE if the lock holds, FALSE if it is available. + */ +function lock_wait($name, $delay = 30) { + + while ($delay--) { + sleep(1); + if (lock_may_be_available($name)) { + return FALSE; + } + } + return TRUE; +} + +/** + * Release a lock previously acquired by lock_acquire(). + * + * @param $name + * The name of the lock. + */ +function lock_release($name) { + global $locks; + + unset($locks[$name]); + db_query("DELETE FROM {semaphore} WHERE name = '%s' AND value = '%s'", $name, _lock_id()); +} + +/** + * Release all previously acquired locks. + */ +function lock_release_all() { + global $locks; + + $locks = array(); + db_query("DELETE FROM {semaphore} WHERE value = '%s'", _lock_id()); +} + +/** + * @} End of "defgroup locks". + */ Index: includes/menu.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/menu.inc,v retrieving revision 1.321 diff -u -p -r1.321 menu.inc --- includes/menu.inc 19 Apr 2009 19:10:07 -0000 1.321 +++ includes/menu.inc 22 Apr 2009 02:48:45 -0000 @@ -1818,16 +1818,28 @@ function menu_cache_clear_all() { * is different and leaves stale data in the menu tables. */ function menu_rebuild() { - variable_del('menu_rebuild_needed'); + if (!lock_acquire('menu_rebuild')) { + // Wait for another request that is already doing this work. + lock_wait('menu_rebuild'); + return FALSE; + } + list($menu, $masks) = menu_router_build(); _menu_router_save($menu, $masks); - _menu_navigation_links_rebuild($menu); - menu_cache_clear_all(); - // Clear the page and block caches. - _menu_clear_page_cache(); + if (lock_renew('menu_rebuild')) { + _menu_navigation_links_rebuild($menu); + // Clear the menu, page and block caches. + menu_cache_clear_all(); + _menu_clear_page_cache(); + } if (defined('MAINTENANCE_MODE')) { variable_set('menu_rebuild_needed', TRUE); } + else { + variable_del('menu_rebuild_needed'); + } + lock_release('menu_rebuild'); + return TRUE; } /** Index: modules/system/system.install =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.install,v retrieving revision 1.316 diff -u -p -r1.316 system.install --- modules/system/system.install 20 Apr 2009 02:23:16 -0000 1.316 +++ modules/system/system.install 22 Apr 2009 02:48:45 -0000 @@ -1110,6 +1110,31 @@ function system_schema() { 'primary key' => array('filename'), ); + $schema['semaphore'] = array( + 'description' => 'Table for storing locks and other flags that should not be cached by the variable system.', + 'fields' => array( + 'name' => array( + 'description' => 'Primary Key: Unique name.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => ''), + 'value' => array( + 'description' => 'A value.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => ''), + 'expire' => array( + 'description' => 'A Unix timestamp with microseconds indicating when the semaphore should expire.', + 'type' => 'float', + 'size' => 'big', + 'not null' => TRUE), + ), + 'indexes' => array('expire' => array('expire')), + 'primary key' => array('name'), + ); + $schema['sessions'] = array( 'description' => "Drupal's session handlers read and write into the sessions table. Each record represents a user session, either anonymous or authenticated.", 'fields' => array( @@ -3244,6 +3269,37 @@ function system_update_7020() { } /** + * Add semaphore table. + */ +function system_update_7021() { + $ret = array(); + + $schema['semaphore'] = array( + 'fields' => array( + 'name' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => ''), + 'value' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => ''), + 'expire' => array( + 'type' => 'float', + 'size' => 'big', + 'not null' => TRUE), + ), + 'indexes' => array('expire' => array('expire')), + 'primary key' => array('name'), + ); + db_create_table($ret, 'semaphore', $schema['semaphore']); + + return $ret; +} + +/** * @} End of "defgroup updates-6.x-to-7.x" * The next series of updates should start at 8000. */ Index: modules/locale/locale.module =================================================================== RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v retrieving revision 1.238 diff -u -p -r1.238 locale.module --- modules/locale/locale.module 31 Mar 2009 02:02:21 -0000 1.238 +++ modules/locale/locale.module 22 Apr 2009 02:48:45 -0000 @@ -372,7 +372,7 @@ function locale($string = NULL, $langcod if ($cache = cache_get('locale:' . $langcode, 'cache')) { $locale_t[$langcode] = $cache->data; } - else { + elseif (lock_acquire('locale_cache_' . $langcode)) { // Refresh database stored cache of translations for given language. // We only store short strings used in current version, to improve // performance and consume less memory. @@ -381,6 +381,7 @@ function locale($string = NULL, $langcod $locale_t[$langcode][$data->source] = (empty($data->translation) ? TRUE : $data->translation); } cache_set('locale:' . $langcode, $locale_t[$langcode]); + lock_release('locale_cache_' . $langcode); } } }