Index: includes/bootstrap.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v retrieving revision 1.206.2.11 diff -u -p -r1.206.2.11 bootstrap.inc --- includes/bootstrap.inc 25 Feb 2009 13:49:54 -0000 1.206.2.11 +++ includes/bootstrap.inc 21 Apr 2009 20:13:49 -0000 @@ -1052,6 +1052,8 @@ function _drupal_bootstrap($phase) { exit; } // Prepare for non-cached page workflow. + require_once variable_get('lock_inc', './includes/lock.inc'); + lock_init(); drupal_page_header(); break; 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 21 Apr 2009 20:13:49 -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.255.2.30 diff -u -p -r1.255.2.30 menu.inc --- includes/menu.inc 30 Mar 2009 12:12:52 -0000 1.255.2.30 +++ includes/menu.inc 21 Apr 2009 20:13:49 -0000 @@ -1669,15 +1669,31 @@ function menu_cache_clear_all() { * is different and leaves stale data in the menu tables. */ function menu_rebuild() { - variable_del('menu_rebuild_needed'); - menu_cache_clear_all(); + if (!lock_acquire('menu_rebuild')) { + // Wait for another request that is already doing this work. + lock_wait('menu_rebuild'); + return FALSE; + } + $menu = menu_router_build(TRUE); + if (lock_renew('menu_rebuild')) { + _menu_navigation_links_rebuild($menu); + // Clear the page and block caches. + menu_cache_clear_all(); + _menu_clear_page_cache(); + } + _menu_navigation_links_rebuild($menu); // Clear the page and block caches. _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.238.2.12 diff -u -p -r1.238.2.12 system.install --- modules/system/system.install 25 Feb 2009 14:02:46 -0000 1.238.2.12 +++ modules/system/system.install 21 Apr 2009 20:13:49 -0000 @@ -956,6 +956,31 @@ function system_schema() { 'primary key' => array('mlid'), ); + $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( @@ -2548,6 +2573,37 @@ function system_update_6049() { } /** + * Add semaphore table. + */ +function system_update_6050() { + $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-5.x-to-6.x" * The next series of updates should start at 7000. */