=== modified file 'includes/cache.inc'
--- includes/cache.inc	2010-05-18 18:26:30 +0000
+++ includes/cache.inc	2010-08-14 21:18:00 +0000
@@ -46,8 +46,8 @@ function _cache_get_object($bin) {
  * @return
  *   The cache or FALSE on failure.
  */
-function cache_get($cid, $bin = 'cache') {
-  return _cache_get_object($bin)->get($cid);
+function cache_get($cid, $bin = 'cache', $include_invalid = FALSE) {
+  return _cache_get_object($bin)->get($cid, $include_invalid);
 }
 
 /**
@@ -134,7 +134,7 @@ function cache_get_multiple(array &$cids
  *   - A Unix timestamp: Indicates that the item should be kept at least until
  *     the given time, after which it behaves like CACHE_TEMPORARY.
  */
-function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT) {
+function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT, $version = NULL) {
   return _cache_get_object($bin)->set($cid, $data, $expire);
 }
 
@@ -230,7 +230,7 @@ interface DrupalCacheInterface {
    * @return
    *   The cache or FALSE on failure.
    */
-  function get($cid);
+  function get($cid, $include_invalid = FALSE);
 
   /**
    * Return data from the persistent cache when given an array of cache IDs.
@@ -262,7 +262,7 @@ interface DrupalCacheInterface {
    *   - A Unix timestamp: Indicates that the item should be kept at least until
    *     the given time, after which it behaves like CACHE_TEMPORARY.
    */
-  function set($cid, $data, $expire = CACHE_PERMANENT);
+  function set($cid, $data, $expire = CACHE_PERMANENT, $version = NULL);
 
 
   /**
@@ -304,11 +304,16 @@ class DrupalDatabaseCache implements Dru
     $this->bin = $bin;
   }
 
-  function get($cid) {
+  function get($cid, $include_invalid = FALSE;) {
     try {
       // Garbage collection necessary when enforcing a minimum cache lifetime.
       $this->garbageCollection($this->bin);
-      $cache = db_query("SELECT data, created, expire, serialized FROM {" . $this->bin . "} WHERE cid = :cid", array(':cid' => $cid))->fetchObject();
+      if ($include_invalid) {
+        $cache = db_query("SELECT data, created, expire, serialized, version FROM {" . $this->bin . "} WHERE cid = :cid", array(':cid' => $cid))->fetchObject();
+      }
+      else {
+        $cache = db_query("SELECT data, created, expire, serialized FROM {" . $this->bin . "} WHERE cid = :cid AND version = version_valid", array(':cid' => $cid))->fetchObject();
+      }
       return $this->prepareItem($cache);
     }
     catch (Exception $e) {
@@ -325,6 +330,7 @@ class DrupalDatabaseCache implements Dru
       $query = db_select($this->bin);
       $query->fields($this->bin, array('cid', 'data', 'created', 'expire', 'serialized'));
       $query->condition($this->bin . '.cid', $cids, 'IN');
+      $query->where("$this->bin.version = $this->bin.version_valid');
       $result = $query->execute();
       $cache = array();
       foreach ($result as $item) {
@@ -401,7 +407,7 @@ class DrupalDatabaseCache implements Dru
     return $cache;
   }
 
-  function set($cid, $data, $expire = CACHE_PERMANENT) {
+  function set($cid, $data, $expire = CACHE_PERMANENT, $version = NULL) {
     $fields = array(
       'serialized' => 0,
       'created' => REQUEST_TIME,
@@ -415,10 +421,20 @@ class DrupalDatabaseCache implements Dru
       $fields['data'] = $data;
       $fields['serialized'] = 0;
     }
-
+    $key = array('cid' => $cid);
+    if (isset($version)) {
+      // If the version has changed since then the merge will not find the
+      // record so it will try to insert which will fail because $cid is
+      // the primary key. We already through away errors from db_merge().
+      $key['version'] = $version;
+      // If the query succeeds, then the version did not change since the
+      // beginning of the request so now we need to set the version_valid
+      // field to the same value to indicate that the record is valid.
+      $fields['version_valid'] = $version;
+    }
     try {
       db_merge($this->bin)
-        ->key(array('cid' => $cid))
+        ->key($key)
         ->fields($fields)
         ->execute();
     }
@@ -446,28 +462,45 @@ class DrupalDatabaseCache implements Dru
         elseif (REQUEST_TIME > ($cache_flush + variable_get('cache_lifetime', 0))) {
           // Clear the cache for everyone, cache_lifetime seconds have
           // passed since the first request to clear the cache.
-          db_delete($this->bin)
+          db_update($this->bin)
+            ->fields(array('expire', REQUEST_TIME + 300))
+            ->expression('version', 'version_valid + 1')
             ->condition('expire', CACHE_PERMANENT, '<>')
             ->condition('expire', REQUEST_TIME, '<')
             ->execute();
+          db_delete($this->bin)
+            ->expression('version', 'version_valid + 1', '<>')
+            ->condition('expire', REQUEST_TIME, '<')
+            ->execute();
           variable_set('cache_flush_' . $this->bin, 0);
         }
       }
       else {
         // No minimum cache lifetime, flush all temporary cache entries now.
-        db_delete($this->bin)
+        db_update($this->bin)
+          ->fields(array('expire', REQUEST_TIME + 300))
+          ->expression('version', 'version_valid + 1')
           ->condition('expire', CACHE_PERMANENT, '<>')
           ->condition('expire', REQUEST_TIME, '<')
           ->execute();
+        db_delete($this->bin)
+          ->expression('version', 'version_valid + 1', '<>')
+          ->condition('expire', REQUEST_TIME, '<')
+          ->execute();
       }
     }
     else {
       if ($wildcard) {
         if ($cid == '*') {
-          db_truncate($this->bin)->execute();
+          db_update($this->bin)
+            ->fields(array('expire' => REQUEST_TIME + 300))
+            ->expression('version', 'version_valid + 1')
+            ->execute();
         }
         else {
-          db_delete($this->bin)
+          db_update($this->bin)
+            ->fields(array('expire' => REQUEST_TIME + 300))
+            ->expression('version', 'version_valid + 1')
             ->condition('cid', db_like($cid) . '%', 'LIKE')
             ->execute();
         }
@@ -475,14 +508,18 @@ class DrupalDatabaseCache implements Dru
       elseif (is_array($cid)) {
         // Delete in chunks when a large array is passed.
         do {
-          db_delete($this->bin)
+          db_update($this->bin)
+            ->fields(array('expire' => REQUEST_TIME + 300))
+            ->expression('version', 'version_valid + 1')
             ->condition('cid', array_splice($cid, 0, 1000), 'IN')
             ->execute();
         }
         while (count($cid));
       }
       else {
-        db_delete($this->bin)
+        db_update($this->bin)
+          ->fields(array('expire' => REQUEST_TIME + 300))
+          ->expression('version', 'version_valid + 1')
           ->condition('cid', $cid)
           ->execute();
       }

=== modified file 'includes/common.inc'
--- includes/common.inc	2010-08-14 03:15:01 +0000
+++ includes/common.inc	2010-08-14 20:52:20 +0000
@@ -5255,20 +5255,23 @@ function show(&$element) {
  *   A markup string containing the rendered content of the element, or FALSE
  *   if no cached copy of the element is available.
  */
-function drupal_render_cache_get($elements) {
+function drupal_render_cache_get(&$elements) {
   if (!in_array($_SERVER['REQUEST_METHOD'], array('GET', 'HEAD')) || !$cid = drupal_render_cid_create($elements)) {
     return FALSE;
   }
   $bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'cache';
-
-  if (!empty($cid) && $cache = cache_get($cid, $bin)) {
-    // Add additional libraries, JavaScript, CSS and other data attached
-    // to this element.
-    if (isset($cache->data['#attached'])) {
-      drupal_process_attached($cache->data);
+  $cache = cache_get($cid, bin, TRUE);
+  if ($cache) {
+    $elements['#cache']['version'] = $cache->version;
+    if ($cache->version == $cache->version_valid) {
+      // Add additional libraries, JavaScript, CSS and other data attached
+      // to this element.
+      if (isset($cache->data['#attached'])) {
+        drupal_process_attached($cache->data);
+      }
+      // Return the rendered output.
+      return $cache->data['#markup'];
     }
-    // Return the rendered output.
-    return $cache->data['#markup'];
   }
   return FALSE;
 }
@@ -5303,9 +5306,11 @@ function drupal_render_cache_set(&$marku
   if (isset($elements['#attached'])) {
     $data['#attached'] = $elements['#attached'];
   }
-  $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);
+  $cache = $elements['#cache'] + array(
+    'bin' => 'cache',
+    'expire' => CACHE_PERMANENT',
+    'version' => NULL,
+  cache_set($cid, $data, $cache['bin'], $cache['expire'], $cache['version']);
 }
 
 /**

=== modified file 'modules/filter/filter.module'
--- modules/filter/filter.module	2010-08-01 19:50:33 +0000
+++ modules/filter/filter.module	2010-08-14 20:52:52 +0000
@@ -688,9 +688,11 @@ function check_markup($text, $format_id 
   $cache_id = '';
   if ($cache) {
     $cache_id = $format->format . ':' . $langcode . ':' . hash('sha256', $text);
-    if ($cached = cache_get($cache_id, 'cache_filter')) {
+    $cached = cache_get($cache_id, 'cache_filter', TRUE);
+    if ($cached && $cached->version == $cached->version_valid) {
       return $cached->data;
     }
+    $cache_version = $cached ? $cached->version : NULL;
   }
 
   // Convert all Windows and Mac newlines to a single newline, so filters only
@@ -719,7 +721,7 @@ function check_markup($text, $format_id 
 
   // Store in cache with a minimum expiration time of 1 day.
   if ($cache) {
-    cache_set($cache_id, $text, 'cache_filter', REQUEST_TIME + (60 * 60 * 24));
+    cache_set($cache_id, $text, 'cache_filter', REQUEST_TIME + (60 * 60 * 24), $cache_version);
   }
 
   return $text;

=== modified file 'modules/system/system.install'
--- modules/system/system.install	2010-07-31 12:29:31 +0000
+++ modules/system/system.install	2010-08-14 19:27:27 +0000
@@ -656,6 +656,18 @@ function system_schema() {
         'not null' => TRUE,
         'default' => 0,
       ),
+      'version' => array(
+        'description' => 'A Unix timestamp indicating when the cache entry should expire, or 0 for never.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'version_valid' => array(
+        'description' => 'A Unix timestamp indicating when the cache entry should expire, or 0 for never.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
     ),
     'indexes' => array(
       'expire' => array('expire'),

