Index: memcache.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/memcache/memcache.inc,v
retrieving revision 1.15.2.8.2.19
diff -u -p -r1.15.2.8.2.19 memcache.inc
--- memcache.inc	1 Oct 2010 14:24:36 -0000	1.15.2.8.2.19
+++ memcache.inc	3 Oct 2010 11:09:00 -0000
@@ -6,11 +6,6 @@
 require_once 'dmemcache.inc';
 
 /**
- * Defines the period after which wildcard clears are not considered valid.
- */
-define('MEMCACHE_WILDCARD_INVALIDATE', 86400 * 28);
-
-/**
  * Return data from the persistent cache.
  * 
  * Data may be stored as either plain text or as serialized data.
@@ -32,19 +27,9 @@ function cache_get($cid, $table = 'cache
     return FALSE;
   }
 
-  $wildcard_timestamps = variable_get('memcache_wildcard_timestamps', array());
-  $wildcard_invalidate = variable_get('memcache_wildcard_invalidate', MEMCACHE_WILDCARD_INVALIDATE);
-
-  // Only validate against wildcard flushes if this table has seen a recent
-  // wildcard flush, as there is overhead in checking for wildcard flushes.
-  if (!empty($wildcard_timestamps[$table]) &&
-      $wildcard_timestamps[$table] >= ($_SERVER['REQUEST_TIME'] - $wildcard_invalidate)) {
-    // Previously cached content won't have ->flushes defined.  We could
-    // force flush, but instead leave this up to the site admin.
-    $flushes = isset($cache->flushes) ? (int)$cache->flushes : 0;
-    if ($flushes < memcache_wildcard_flushes($cid, $table)) {
-      return FALSE;
-    }
+  $flushes = isset($cache->flushes) ? (int)$cache->flushes : 0;
+  if ($flushes < memcache_wildcard_flushes($cid, $table)) {
+    return FALSE;
   }
 
   $cache_tables = isset($_SESSION['cache_flush']) ? $_SESSION['cache_flush'] : NULL;
@@ -96,9 +81,14 @@ function cache_set($cid, $data, $table =
   // Record the previous number of wildcard flushes affecting our cid.
   $cache->flushes = memcache_wildcard_flushes($cid, $table);
   if ($expire == CACHE_TEMPORARY) {
-    // Convert CACHE_TEMPORARY (-1) into something that will live in memcache
-    // until the next flush.
-    $cache->expire = $_SERVER['REQUEST_TIME'] + 2591999;
+    // Temporary items live for the minimum cache lifetime,
+    // or are not cached if no minimum is set.
+    if ($minimum = variable_get('cache_lifetime', 0)) {
+      $cache->expire = $_SERVER['REQUEST_TIME'] + $minimum;
+    }
+    else {
+      return;
+    }
   }
   // Expire time is in seconds if less than 30 days, otherwise is a timestamp.
   else if ($expire != CACHE_PERMANENT && $expire < 2592000) {
@@ -183,39 +173,10 @@ function cache_clear_all($cid = NULL, $t
 }
 
 /**
- * We hash cids to keep them a consistent, managable length.  Alternative algorithms
- * can be specified if you're looking for better performance (benchmark first!).
- * Hash collissions are not a big deal, simply leads to all collided items being
- * flushed together.
+ * Hash long cids to keep them a consistent, managable length.
  */
 function memcache_hash_cid($cid) {
-  static $hashes = array();
-  $memcache_hash = variable_get('memcache_hash', 'md5');
-  if (function_exists($memcache_hash)) {
-    $hashes[$cid] = $memcache_hash($cid);
-  }
-  else {
-    $hashes[$cid] = $cid;
-  }
-  return $hashes[$cid];
-}
-
-/**
- * Determine all possible hashes that could match our cid.  We optimize away
- * the overhead of checking all possible matches by using multiget.
- */
-function memcache_multihash_cid($cid, $table) {
-  static $hashes = array();
-  if (!isset($hashes[$table])) {
-    $hashes[$table] = array();
-  }
-  if (!isset($hashes[$table][$cid])) {
-    for ($i = 0; $i <= strlen($cid); $i++) {
-      $subcid = substr($cid, 0, $i);
-      $hashes[$table][$cid][$subcid] = '.wildcard-'. $table . memcache_hash_cid($subcid);
-    }
-  }
-  return $hashes[$table][$cid];
+  return (strlen($cid) > 160) ? md5($cid) : $cid;
 }
 
 /**
@@ -234,35 +195,54 @@ function memcache_wildcard_flushes($cid,
  */
 function memcache_wildcards($cid, $table, $flush = FALSE) {
   static $wildcards = array();
-
-  $wildcard_timestamps = variable_get('memcache_wildcard_timestamps', array());
-  $wildcard_invalidate = variable_get('memcache_wildcard_invalidate', MEMCACHE_WILDCARD_INVALIDATE);
-  // If this bin has never had a wildcard flush, or the last wildcard flush
-  // was more than a month ago, simply return an empty array to indicate that
-  // it has never been flushed and to avoid the overhead of a wildcard lookup.
-  if (!$flush && (!isset($wildcard_timestamps[$table]) ||
-      $wildcard_timestamps[$table] <= ($_SERVER['REQUEST_TIME'] - $wildcard_invalidate))) {
-    return array();
-  }
+  static $all_wildcards = array();
 
   if (!isset($wildcards[$table]) || !isset($wildcards[$table][$cid])) {
-    $multihash = memcache_multihash_cid($cid, $table);
-    $wildcards[$table][$cid] = dmemcache_get_multi($multihash, $table);
-    if (!is_array($wildcards[$table][$cid])) {
+    if (!isset($wildcards[$table][$cid])) {
       $wildcards[$table][$cid] = array();
     }
-  }
-  if ($flush) {
-    if (!empty($cid)) {
-      // Avoid too many variable_set() by only recording a flush for
-      // a fraction of the wildcard invalidation variable. Defaults to
-      // 28 / 4 = one week.
-      if (!isset($wildcard_timestamps[$table]) ||
-          ($_SERVER['REQUEST_TIME'] - $wildcard_timestamps[$table] > $wildcard_invalidate / 4)) {
-        $wildcard_timestamps[$table] = $_SERVER['REQUEST_TIME'];
-        variable_set('memcache_wildcard_timestamps', $wildcard_timestamps);
+
+    $lengths = variable_get('memcache_wildcard_lengths', array());
+    if (!empty($lengths[$table])) {
+      $multihash = array();
+
+      // Generate possible prefixes for this cid from known cleared lengths.
+      foreach (array_keys($lengths[$table]) as $i) {
+        $multihash[] = '.wildcard-' . $table . memcache_hash_cid(substr($cid, 0, $i));
+      }
+
+      // Retrieve any wildcards that we have already statically cached.
+      foreach ($multihash as $i => $key) {
+        $hash = dmemcache_key($key, $table);
+        if (isset($all_wildcards[$table][$hash])) {
+          $wildcards[$table][$cid][$hash] = $all_wildcards[$table][$hash];
+          unset($multihash[$i]);
+        }
+      }
+
+      // Use getMulti to retrieve any remaining wildcards.
+      if (!empty($multihash)) {
+        $multivalues = dmemcache_get_multi($multihash, $table);
+        if (is_array($multivalues)) {
+          foreach ($multihash as $key) {
+            $hash = dmemcache_key($key, $table);
+            // Force flush values to 0 for wildcards that were not found.
+            $wildcards[$table][$cid][$hash] = isset($multivalues[$hash]) ? $multivalues[$hash] : 0;
+          }
+        }
+
+        // Update the static cache.
+        if (!isset($all_wildcards[$table])) {
+          $all_wildcards[$table] = $wildcards[$table][$cid];
+        }
+        else {
+          $all_wildcards[$table] = array_merge($all_wildcards[$table], $wildcards[$table][$cid]);
+        }
       }
     }
+  }
+
+  if ($flush) {
     $hash = memcache_hash_cid($cid, $table);
     $wildcard = dmemcache_key('.wildcard-' . $table . $hash, $table);
     if (isset($wildcards[$table][$cid][$wildcard])) {
@@ -274,6 +254,14 @@ function memcache_wildcards($cid, $table
       $wildcards[$table][$cid][$wildcard] = 1;
       dmemcache_set('.wildcard-' . $table . $hash, 1, 0, $table);
     }
+
+    // Remember that a wildcard of this length was flushed.
+    $length = strlen($cid);
+    $lengths = variable_get('memcache_wildcard_lengths', array());
+    if (!isset($lengths[$table][$length])) {
+      $lengths[$table][$length] = $_SERVER['REQUEST_TIME'];
+      variable_set('memcache_wildcard_lengths', $lengths);
+    }
   }
   return $wildcards[$table][$cid];
 }
