diff --git a/includes/menu.inc b/includes/menu.inc index fa5a71e..2dc3d37 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -2707,11 +2707,29 @@ function menu_reset_static_cache() { * in parallel and the current thread just waited for completion. */ function menu_rebuild() { + global $conf; if (!lock_acquire('menu_rebuild')) { // Wait for another request that is already doing this work. // We choose to block here since otherwise the router item may not // be available in menu_execute_active_handler() resulting in a 404. lock_wait('menu_rebuild'); + + // Refresh all variables written while waiting for the lock. This will + // ensure that $conf['menu_masks'] is set correctly. + variable_initialize($conf); + // Ensure that no further rebuild is triggered by this process. + if (isset($conf['menu_rebuild_needed'])) { + unset($conf['menu_rebuild_needed']); + } + return FALSE; + } + + // Account for a race condition where the menu needed rebuilding at the + // beginning of this request, but was subsequently rebuilt by another process + // in the meantime. In this case, avoid another rebuild. + variable_initialize($conf); + if (!variable_get('menu_rebuild_needed')) { + lock_release('menu_rebuild'); return FALSE; } @@ -2729,13 +2747,22 @@ function menu_rebuild() { variable_set('menu_rebuild_needed', TRUE); } else { - variable_del('menu_rebuild_needed'); + // Explicitly set the value to false so that variable_initialize() calls + // elsewhere in this function will overwrite $conf to FALSE when we hit + // race conditions. + variable_set('menu_rebuild_needed', FALSE); } } catch (Exception $e) { $transaction->rollback(); watchdog_exception('menu', $e); } + // Explicitly commit the transaction now, this ensures that the database + // operations during the menu rebuild are committed before the lock is made + // available again, since locks may not always reside in the same database + // connection. The lock is acquired outside of the transaction so should also + // be released outside of it. + unset($transaction); lock_release('menu_rebuild'); return TRUE;