Index: dmemcache.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/memcache/dmemcache.inc,v
retrieving revision 1.1.2.7.2.21
diff -u -p -r1.1.2.7.2.21 dmemcache.inc
--- dmemcache.inc	3 Nov 2010 19:18:42 -0000	1.1.2.7.2.21
+++ dmemcache.inc	9 Nov 2010 23:09:10 -0000
@@ -33,6 +33,7 @@ $_memcache_statistics = array();
 function dmemcache_set($key, $value, $exp = 0, $bin = 'cache') {
   global $_memcache_statistics;
   $full_key = dmemcache_key($key, $bin);
+  $semaphore_key = $key . '_semaphore';
   $success = FALSE;
   if ($mc = dmemcache_object($bin)) {
     if (class_exists('Memcached')) {
@@ -43,6 +44,9 @@ function dmemcache_set($key, $value, $ex
     }
   }
   $_memcache_statistics[] = array('set', $bin, $full_key, (int)$success);
+  if ($success) {
+    dmemcache_delete($semaphore_key);
+  }
   return $success;
 }
 
@@ -97,7 +101,16 @@ function dmemcache_add($key, $value, $ex
  */
 function dmemcache_get($key, $bin = 'cache') {
   global $_memcache_statistics;
+  static $stampede_semaphore_ttl, $stampede_retry_count, $stampede_protection_enabled;
+
+  if ($stampede_semaphore_ttl === NULL) {
+    $stampede_protection_enabled = variable_get('memcache_stampede_protection', FALSE);
+    $stampede_semaphore_ttl = variable_get('memcache_stampede_semaphore', 5);
+    $stampede_retry_count = variable_get('memcache_stampede_retry_count', 10);
+  }
+
   $full_key = dmemcache_key($key, $bin);
+  $semaphore_key = $key . '_semaphore';
   $statistics = array('get', $bin, $full_key);
   $success = '0';
   if ($mc = dmemcache_object($bin)) {
@@ -110,15 +123,33 @@ function dmemcache_get($key, $bin = 'cac
       // cache stampedes. 
       // By default the cache stampede semaphore is held for 15 seconds.  This
       // can be adjusted by setting the memcache_stampede_semaphore variable.
-      // TODO: Can we log when a sempahore expires versus being intentionally
+      // TODO: Can we log when a semaphore expires versus being intentionally
       // freed to track when this is happening?
-      if (isset($result->expire) && $result->expire !== CACHE_PERMANENT && $result->expire <= $_SERVER['REQUEST_TIME'] && dmemcache_add($full_key .'_semaphore', '', variable_get('memcache_stampede_semaphore', 15))) {
+      if (isset($result->expire) && $result->expire !== CACHE_PERMANENT && $result->expire <= $_SERVER['REQUEST_TIME'] && dmemcache_add($semaphore_key, '', $stampede_semaphore_ttl)) {
         $result = FALSE;
       }
       else {
         $success = '1';
       }
     }
+    else {
+      if ($stampede_protection_enabled) {
+        // Try to avoid a cache stampede by acquiring a cache stampede semaphore.
+        if (!dmemcache_add($semaphore_key, '', $stampede_semaphore_ttl)) {
+          // Another process has the semaphore, so lets give it some time to
+          // regenerate the item, then try to fetch it from cache.
+          $attempts = 0;
+          do {
+            if (usleep(100000) && ($result = $mc->get($full_key))) {
+              // We got the item from cache, great $success!
+              $success = '1';
+            }
+          }
+          while (!$result && ++$attempts < $stampede_retry_count);
+        }
+      }
+    }
+
     $statistics[] = $success;
     $_memcache_statistics[] = $statistics;
 
