Index: includes/bootstrap.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v retrieving revision 1.389 diff -u -p -r1.389 bootstrap.inc --- includes/bootstrap.inc 18 May 2010 18:33:30 -0000 1.389 +++ includes/bootstrap.inc 20 May 2010 05:37:37 -0000 @@ -2076,7 +2076,20 @@ function _drupal_bootstrap_page_cache() exit; } else { - header('X-Drupal-Cache: MISS'); + // Cache miss. Avoid a stampede. + require_once DRUPAL_ROOT . '/' . variable_get('lock_inc', 'includes/lock.inc'); + lock_initialize(); + $name = $GLOBALS['base_root'] . request_uri(); + if (!lock_acquire($name, 1)) { + // Some other request is building cache. Wait, then re-run this function. + header('X-Drupal-Cache: WAIT'); + lock_wait($name); + return _drupal_bootstrap_page_cache(); + } + else { + // Proceed with page build; cache its result, then release the lock. + header('X-Drupal-Cache: MISS'); + } } } } Index: includes/cache.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/cache.inc,v retrieving revision 1.48 diff -u -p -r1.48 cache.inc --- includes/cache.inc 18 May 2010 18:26:30 -0000 1.48 +++ includes/cache.inc 20 May 2010 05:37:37 -0000 @@ -421,6 +421,9 @@ class DrupalDatabaseCache implements Dru ->key(array('cid' => $cid)) ->fields($fields) ->execute(); + if ($this->bin == 'cache_page') { + file_put_contents('/tmp/cache.txt', $this->bin . "\n", FILE_APPEND); + } } catch (Exception $e) { // The database may not be available, so we'll ignore cache_set requests. Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.1168 diff -u -p -r1.1168 common.inc --- includes/common.inc 19 May 2010 19:22:24 -0000 1.1168 +++ includes/common.inc 20 May 2010 05:37:39 -0000 @@ -4544,6 +4544,7 @@ function drupal_page_set_cache() { $cache->data['body'] = gzencode($cache->data['body'], 9, FORCE_GZIP); } cache_set($cache->cid, $cache->data, 'cache_page', $cache->expire); + lock_release($cache->cid); } return $cache; } @@ -5187,7 +5188,7 @@ function drupal_render_cache_get($elemen } $bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'cache'; - if (!empty($cid) && $cache = cache_get($cid, $bin)) { + if ($cache = cache_get($cid, $bin)) { // Add additional libraries, JavaScript, CSS and other data attached // to this element. if (isset($cache->data['#attached'])) { @@ -5196,7 +5197,18 @@ function drupal_render_cache_get($elemen // Return the rendered output. return $cache->data['#markup']; } - return FALSE; + else { + // Cache miss. Avoid a stampede. + if (!lock_acquire($cid, 1)) { + // Some other request is building cache. Wait, then re-run this function. + lock_wait($cid); + return drupal_render_cache_get($elements); + } + else { + // Proceed with rendering, cache the result, and then release the lock. + return FALSE; + } + } } /** @@ -5232,6 +5244,7 @@ function drupal_render_cache_set(&$marku $bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'cache'; $expire = isset($elements['#cache']['expire']) ? $elements['#cache']['expire'] : CACHE_PERMANENT; cache_set($cid, $data, $bin, $expire); + lock_release($cid); } /** Index: includes/lock.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/lock.inc,v retrieving revision 1.4 diff -u -p -r1.4 lock.inc --- includes/lock.inc 6 May 2010 15:20:18 -0000 1.4 +++ includes/lock.inc 20 May 2010 05:37:39 -0000 @@ -198,8 +198,9 @@ function lock_wait($name, $delay = 30) { while ($delay--) { // This function should only be called by a request that failed to get a // lock, so we sleep first to give the parallel request a chance to finish - // and release the lock. - sleep(1); + // and release the lock. Use usleep for 100ms, instead of sleep(1), so that + // processes don't wait around too much longer than necessary. + usleep(100000); if (lock_may_be_available($name)) { // No longer need to wait. return FALSE;