diff -uNr includes/bootstrap.inc includes/bootstrap.inc
--- includes/bootstrap.inc	2008-12-08 03:49:48.000000000 -0800
+++ includes/bootstrap.inc	2009-01-13 22:39:30.000000000 -0800
@@ -71,31 +71,36 @@
 define('DRUPAL_BOOTSTRAP_ACCESS', 3);
 
 /**
- * Fifth bootstrap phase: initialize session handling.
+ * Fifth bootstrap phase: initialize locking system.
  */
-define('DRUPAL_BOOTSTRAP_SESSION', 4);
+define('DRUPAL_BOOTSTRAP_LOCK', 4);
 
 /**
- * Sixth bootstrap phase: load bootstrap.inc and module.inc, start
+ * Sixth bootstrap phase: initialize session handling.
+ */
+define('DRUPAL_BOOTSTRAP_SESSION', 5);
+
+/**
+ * Seventh bootstrap phase: load bootstrap.inc and module.inc, start
  * the variable system and try to serve a page from the cache.
  */
-define('DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE', 5);
+define('DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE', 6);
 
 /**
- * Seventh bootstrap phase: find out language of the page.
+ * Eighth bootstrap phase: find out language of the page.
  */
-define('DRUPAL_BOOTSTRAP_LANGUAGE', 6);
+define('DRUPAL_BOOTSTRAP_LANGUAGE', 7);
 
 /**
- * Eighth bootstrap phase: set $_GET['q'] to Drupal path of request.
+ * Nineth bootstrap phase: set $_GET['q'] to Drupal path of request.
  */
-define('DRUPAL_BOOTSTRAP_PATH', 7);
+define('DRUPAL_BOOTSTRAP_PATH', 8);
 
 /**
  * Final bootstrap phase: Drupal is fully loaded; validate and fix
  * input data.
  */
-define('DRUPAL_BOOTSTRAP_FULL', 8);
+define('DRUPAL_BOOTSTRAP_FULL', 9);
 
 /**
  * Role ID for anonymous users; should match what's in the "role" table.
@@ -945,6 +950,7 @@
  *     DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE: try to call a non-database cache fetch routine.
  *     DRUPAL_BOOTSTRAP_DATABASE: initialize database layer.
  *     DRUPAL_BOOTSTRAP_ACCESS: identify and reject banned hosts.
+ *     DRUPAL_BOOTSTRAP_LOCK: initialize locking system.
  *     DRUPAL_BOOTSTRAP_SESSION: initialize session handling.
  *     DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE: load bootstrap.inc and module.inc, start
  *       the variable system and try to serve a page from the cache.
@@ -953,7 +959,7 @@
  *     DRUPAL_BOOTSTRAP_FULL: Drupal is fully loaded, validate and fix input data.
  */
 function drupal_bootstrap($phase) {
-  static $phases = array(DRUPAL_BOOTSTRAP_CONFIGURATION, DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE, DRUPAL_BOOTSTRAP_DATABASE, DRUPAL_BOOTSTRAP_ACCESS, DRUPAL_BOOTSTRAP_SESSION, DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE, DRUPAL_BOOTSTRAP_LANGUAGE, DRUPAL_BOOTSTRAP_PATH, DRUPAL_BOOTSTRAP_FULL), $phase_index = 0;
+  static $phases = array(DRUPAL_BOOTSTRAP_CONFIGURATION, DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE, DRUPAL_BOOTSTRAP_DATABASE, DRUPAL_BOOTSTRAP_ACCESS, DRUPAL_BOOTSTRAP_LOCK, DRUPAL_BOOTSTRAP_SESSION, DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE, DRUPAL_BOOTSTRAP_LANGUAGE, DRUPAL_BOOTSTRAP_PATH, DRUPAL_BOOTSTRAP_FULL), $phase_index = 0;
 
   while ($phase >= $phase_index && isset($phases[$phase_index])) {
     $current_phase = $phases[$phase_index];
@@ -1003,6 +1009,11 @@
       }
       break;
 
+    case DRUPAL_BOOTSTRAP_LOCK:
+      require_once variable_get('lock_inc', './includes/lock.inc');
+      lock_init();
+      break;
+
     case DRUPAL_BOOTSTRAP_SESSION:
       require_once variable_get('session_inc', './includes/session.inc');
       session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy_sid', 'sess_gc');
diff -uNr includes/lock.inc includes/lock.inc
--- includes/lock.inc	1969-12-31 16:00:00.000000000 -0800
+++ includes/lock.inc	2009-01-13 22:39:15.000000000 -0800
@@ -0,0 +1,101 @@
+<?php
+// $Id $
+
+/**
+ * @file
+ * Lock handling for concurrent requests.
+ */
+
+/**
+ * Initialize the locking system.
+ */
+function lock_init() {
+  global $locks;
+  $locks = array();
+  register_shutdown_function('lock_release_all');
+}
+
+/**
+ * Acquire a lock, do not block if it fails.
+ *
+ * @param $name
+ *   The name of the lock.
+ * @return TRUE if the lock was acquired, FALSE if it failed.
+ */
+function lock_acquire($name) {
+  global $locks;
+  if (isset($locks[$name])) {
+    return TRUE;
+  }
+  else {
+    // try to acquire the lock
+    $lock = cache_get($name, 'cache_lock');
+    if ($lock === FALSE) {
+      $locks[$name] = TRUE;
+      cache_set($name, $locks[$name], 'cache_lock', CACHE_TEMPORARY);
+      return TRUE;
+    }
+    else {
+      return FALSE;
+    }
+  }
+}
+
+/**
+ * Wait for a lock to be released.  We do this in ms so that we can wait a minimum
+ * of 1ms.  Typically you might want to lock for 100ms or so but not a full second.
+ * Be aware that locking and checking a server can put a pretty significant load on
+ * the cache server.
+ *
+ * @param $name
+ *   The name of the lock.
+ * @param $timeout
+ *   The timeout to wait for the lock in milliseconds (ms). Defaults to 2 seconds
+ * @param $interval
+ *   The amount of time to wait before checking for the lock again.  Defaults to 100ms.
+ * @return TRUE if the lock was acquired, FALSE if it failed.
+ */
+function lock_wait($name, $timeout = 2000, $interval = 100) {
+  global $locks;
+  if (isset($locks[$name])) {
+    return TRUE;
+  }
+  else {
+    list($start,) = explode(" ", microtime());
+    while (($lock = cache_get($name, 'cache_lock')) && $lock !== FALSE) {
+      usleep($interval * 1000);
+      list($time,) = explode(" ", microtime());
+      if ((($time - $start) * 1000) >= $timeout) {
+        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;
+  if (isset($locks[$name])) {
+    cache_clear_all($name, 'cache_lock');
+    unset($locks[$name]);
+  }
+}
+
+/**
+ * Release all previously acquired locks.
+ */
+function lock_release_all() {
+  global $locks;
+  if (!empty($locks)) {
+    foreach ($locks as $lock_id => $value) {
+      cache_clear_all($lock_id, 'cache_lock');
+      unset($locks[$lock_id]);
+    }
+  }
+}
\ No newline at end of file
diff -uNr includes/menu.inc includes/menu.inc
--- includes/menu.inc	2008-11-10 09:30:39.000000000 -0800
+++ includes/menu.inc	2009-01-13 22:41:37.000000000 -0800
@@ -1651,6 +1651,9 @@
  * is different and leaves stale data in the menu tables.
  */
 function menu_rebuild() {
+  if (!lock_acquire('menu_rebuild')) {
+    return FALSE;
+  }
   variable_del('menu_rebuild_needed');
   menu_cache_clear_all();
   $menu = menu_router_build(TRUE);
@@ -1660,6 +1663,7 @@
   if (defined('MAINTENANCE_MODE')) {
     variable_set('menu_rebuild_needed', TRUE);
   }
+  lock_release('menu_rebuild');
 }
 
 /**
@@ -1667,7 +1671,6 @@
  */
 function menu_router_build($reset = FALSE) {
   static $menu;
-
   if (!isset($menu) || $reset) {
     if (!$reset && ($cache = cache_get('router:', 'cache_menu')) && isset($cache->data)) {
       $menu = $cache->data;
diff -uNr modules/locale/locale.module modules/locale/locale.module
--- modules/locale/locale.module	2008-10-20 02:31:06.000000000 -0700
+++ modules/locale/locale.module	2009-01-13 22:40:07.000000000 -0800
@@ -357,14 +357,17 @@
         $locale_t[$langcode] = $cache->data;
       }
       else {
-        // 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.
-        $result = db_query("SELECT s.source, t.translation, t.language FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = '%s' WHERE s.textgroup = 'default' AND s.version = '%s' AND LENGTH(s.source) < 75", $langcode, VERSION);
-        while ($data = db_fetch_object($result)) {
-          $locale_t[$langcode][$data->source] = (empty($data->translation) ? TRUE : $data->translation);
+        if (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.
+          $result = db_query("SELECT s.source, t.translation, t.language FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = '%s' WHERE s.textgroup = 'default' AND s.version = '%s' AND LENGTH(s.source) < 75", $langcode, VERSION);
+          while ($data = db_fetch_object($result)) {
+            $locale_t[$langcode][$data->source] = (empty($data->translation) ? TRUE : $data->translation);
+          }
+          cache_set('locale:'. $langcode, $locale_t[$langcode]);
+          lock_release('locale_cache_' . $langcode);
         }
-        cache_set('locale:'. $langcode, $locale_t[$langcode]);
       }
     }
   }
