Index: memcache.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/memcache/memcache.inc,v
retrieving revision 1.28.2.12
diff -u -p -r1.28.2.12 memcache.inc
--- memcache.inc        26 Aug 2010 07:22:31 -0000      1.28.2.12
+++ memcache.inc        6 Sep 2010 12:10:40 -0000
@@ -3,6 +3,11 @@

 require_once 'dmemcache.inc';

+/**
+ * Defines the period after which wildcard clears are not considered valid.
+ */
+define('MEMCACHE_WILDCARD_INVALIDATE', 86400 * 28);
+
 /** Implementation of cache.inc with memcache logic included **/

 class MemCacheDrupal implements DrupalCacheInterface {
@@ -32,11 +37,22 @@ class MemCacheDrupal implements DrupalCa
   }

   protected function valid($cid, $cache) {
+    static $wildcard_flushes;
+    static $invalidate;
+    if (!isset($wildcard_flushes)) {
+      $wildcard_flushes = variable_get('memcache_wildcard_flushes', array());
+    }
+    if (!isset($invalidate)) {
+      $invalidate = variable_get('memcache_wildcard_invalidate', MEMCACHE_WILDCARD_INVALIDATE);
+    }
     if (!is_object($cache)) {
       return FALSE;
     }

-    if (!$this->wildcard_valid($cid, $cache)) {
+    // wildcard_valid() has some overhead due to hashing cids and a
+    // dmemcache_get_multi() to fetch the flushes. Since some bins never
+    // have wildcard clears with a cid, we can shortcut these checks.
+    if (!empty($wildcard_flushes[$this->bin]) && $wildcard_flushes[$this->bin] <= time() - $invalidate && !$this->wildcard_valid($cid, $cache))  {
       return FALSE;
     }

@@ -68,7 +84,15 @@ class MemCacheDrupal implements DrupalCa
     // TODO: Can we log when a sempahore expires versus being intentionally
     // freed to track when this is happening?
     $item_expired = isset($cache->expire) && $cache->expire !== CACHE_PERMANENT && $cache->expire <= time();
-    return !(($item_flushed_globally || $item_expired) && dmemcache_add($cid .'_semaphore', '', variable_get('memcache_stampede_semaphore', 15), $this->bin));
+    if ($item_flushed_globally || $item_expired) {
+      // To avoid a stampede, return TRUE despite the item being expired if
+      // a previous process set the stampede semaphore already. However only
+      // do this if the data is less than 30 minutes stale.
+      if (dmemcache_add($cid . '_semaphore', '', variable_get('memcache_stampede_semaphore', 15), $this->bin) || (REQUEST_TIME - $cache->expire) >= variable_get('memcache_max_staleness', 1800 )) {
+        return FALSE;
+      }
+    }
+    return TRUE;
   }

   function set($cid, $data, $expire = CACHE_PERMANENT, array $headers = NULL) {
@@ -200,6 +224,11 @@ class MemCacheDrupal implements DrupalCa
       }
     }
     if ($flush) {
+      if (!empty($cid)) {
+        $wildcard_flushes = variable_get('memcache_wildcard_flushes', array());
+        $wildcard_flushes[$this->bin] = time();
+        variable_set('memcache_wildcard_flushes', $wildcard_flushes);
+      }
       $hash = $this->hash_cid($cid);
       $wildcard = dmemcache_key('.wildcard-' . $this->bin . $hash, $this->bin);
       if (isset($wildcards[$this->bin][$cid][$wildcard])) {

