diff --git a/core/includes/cache.inc b/core/includes/cache.inc
index 06b0ab1..9dba4c8 100644
--- a/core/includes/cache.inc
+++ b/core/includes/cache.inc
@@ -40,6 +40,25 @@ function cache($bin = 'cache') {
 }
 
 /**
+ * Deletes the items associated with given list of tags.
+ *
+ * Many sites have more than one active cache backend, and each backend my use
+ * a different strategy for storing tags against cache items, and deleting cache
+ * items associated with a given tag.
+ *
+ * When deleting a given list of tags, we iterate over each cache backend, and
+ * and call deleteTags() on each.
+ *
+ * @param array $tags
+ *   The list of tags to invalidate cache items for.
+ */
+function cache_delete_tags(array $tags) {
+  foreach (CacheFactory::getBackends() as $bin => $class) {
+    cache($bin)->invalidateTags($tags);
+  }
+}
+
+/**
  * Invalidates the items associated with given list of tags.
  *
  * Many sites have more than one active cache backend, and each backend my use
@@ -47,12 +66,12 @@ function cache($bin = 'cache') {
  * cache items associated with a given tag.
  *
  * When invalidating a given list of tags, we iterate over each cache backend,
- * and call invalidate on each.
+ * and call invalidateTags() on each.
  *
  * @param array $tags
  *   The list of tags to invalidate cache items for.
  */
-function cache_invalidate(array $tags) {
+function cache_invalidate_tags(array $tags) {
   foreach (CacheFactory::getBackends() as $bin => $class) {
     cache($bin)->invalidateTags($tags);
   }
diff --git a/core/includes/common.inc b/core/includes/common.inc
index e7ebd1f..d427d38 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -6788,7 +6788,7 @@ function drupal_flush_all_caches() {
   // This is executed based on old/previously known information, which is
   // sufficient, since new extensions cannot have any primed caches yet.
   foreach (module_invoke_all('cache_flush') as $bin) {
-    cache($bin)->flush();
+    cache($bin)->deleteAll();
   }
 
   // Flush asset file caches.
diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index f21bd1f..46003f9 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -2620,7 +2620,7 @@ function menu_cache_clear($menu_name = 'navigation') {
  * might have been made to the router items or menu links.
  */
 function menu_cache_clear_all() {
-  cache('menu')->flush();
+  cache('menu')->deleteAll();
   menu_reset_static_cache();
 }
 
@@ -3249,13 +3249,13 @@ function _menu_clear_page_cache() {
   // Clear the page and block caches, but at most twice, including at
   //  the end of the page load when there are multiple links saved or deleted.
   if ($cache_cleared == 0) {
-    cache_invalidate(array('content' => TRUE));
+    cache_invalidate_tags(array('content' => TRUE));
     // Keep track of which menus have expanded items.
     _menu_set_expanded_menus();
     $cache_cleared = 1;
   }
   elseif ($cache_cleared == 1) {
-    drupal_register_shutdown_function('cache_invalidate', array('content', TRUE));
+    drupal_register_shutdown_function('cache_invalidate_tags', array('content', TRUE));
     // Keep track of which menus have expanded items.
     drupal_register_shutdown_function('_menu_set_expanded_menus');
     $cache_cleared = 2;
diff --git a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php
index 2140960..ea023d8 100644
--- a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php
+++ b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php
@@ -38,8 +38,8 @@ namespace Drupal\Core\Cache;
  * To access your custom cache bin, specify the name of the bin when storing
  * or retrieving cached data:
  * @code
- *  cache_set($cid, $data, 'custom_bin', $expire);
- *  cache_get($cid, 'custom_bin');
+ *  cache('custom_bin')->set($cid, $data, $expire);
+ *  cache('custom_bin')->get($cid);
  * @endcode
  *
  * @see cache()
@@ -48,9 +48,7 @@ namespace Drupal\Core\Cache;
 interface CacheBackendInterface {
 
   /**
-   * Indicates that the item should never be removed unless explicitly selected.
-   *
-   * The item may be removed using cache()->delete() with a cache ID.
+   * Indicates that the item should never be removed unless explicitly deleted.
    */
   const CACHE_PERMANENT = 0;
 
@@ -65,45 +63,48 @@ interface CacheBackendInterface {
   /**
    * Returns data from the persistent cache.
    *
-   * Data may be stored as either plain text or as serialized data. cache_get()
-   * will automatically return unserialized objects and arrays.
-   *
-   * @param $cid
+   * @param string $cid
    *   The cache ID of the data to retrieve.
+   * @param boolean $allowInvalid
+   *   (optional) If TRUE, a cache item may be returned even if it is expired or
+   *   has been invalidated. The "valid" property of the returned object
+   *   indicates whether the item is valid or not. Defaults to FALSE.
    *
-   * @return
-   *   The cache or FALSE on failure.
+   * @return object|false
+   *   The cache item or FALSE on failure.
    */
-  function get($cid);
+  function get($cid, $allowInvalid = FALSE);
 
   /**
    * Returns data from the persistent cache when given an array of cache IDs.
    *
-   * @param $cids
+   * @param array $cids
    *   An array of cache IDs for the data to retrieve. This is passed by
    *   reference, and will have the IDs successfully returned from cache
    *   removed.
+   * @param bool $allowInvalid
+   *   (optional) If TRUE, cache items may be returned even if they have expired
+   *   or been invalidated. The "valid" property of the returned objects
+   *   indicates whether each item is valid or not. Defaults to FALSE.
    *
-   * @return
-   *   An array of the items successfully returned from cache indexed by cid.
+   * @return array
+   *   An array of cache item objects indexed by cache ID.
    */
-  function getMultiple(&$cids);
+  function getMultiple(&$cids, $allowInvalid = FALSE);
 
   /**
    * Stores data in the persistent cache.
    *
-   * @param $cid
+   * @param string $cid
    *   The cache ID of the data to store.
-   * @param $data
-   *   The data to store in the cache. Complex data types will be automatically
-   *   serialized before insertion.
-   *   Strings will be stored as plain text and not serialized.
-   * @param $expire
+   * @param mixed $data
+   *   The data to store in the cache.
+   * @param int $expire
    *   One of the following values:
-   *   - CacheBackendInterface::CACHE_PERMANENT: Indicates that the item
-   *     should never be removed unless cache->delete($cid) is used explicitly.
-   *   - A Unix timestamp: Indicates that the item should be kept at least until
-   *     the given time.
+   *   - CacheBackendInterface::CACHE_PERMANENT: Indicates that the item should
+   *     not be removed unless unless it is deleted explicitly.
+   *   - A Unix timestamp: Indicates that the item will be considered invalid
+   *     after this time.
    * @param array $tags
    *   An array of tags to be stored with the cache item. These should normally
    *   identify objects used to build the cache item, which should trigger
@@ -116,39 +117,72 @@ interface CacheBackendInterface {
   /**
    * Deletes an item from the cache.
    *
-   * @param $cid
-   *    The cache ID to delete.
+   * @param string $cid
+   *   The cache ID to delete.
    */
   function delete($cid);
 
   /**
    * Deletes multiple items from the cache.
    *
-   * @param $cids
-   *   An array of $cids to delete.
+   * @param array $cids
+   *   An array of cache IDs to delete.
    */
-  function deleteMultiple(Array $cids);
+  function deleteMultiple(array $cids);
 
   /**
-   * Deletes items from the cache using a wildcard prefix.
+   * Deletes items from the cache with this specified cache ID prefix.
    *
-   * @param $prefix
-   *   A wildcard prefix.
+   * @param string $prefix
+   *   A cache ID prefix.
    */
   function deletePrefix($prefix);
 
   /**
-   * Flushes all cache items in a bin.
+   * Deletes items with any of the specified tags.
+   *
+   * @param array $tags
+   *   Associative array of tags, in the same format that is passed to
+   *   CacheBackendInterface::set().
+   *
+   * @see CacheBackendInterface::set()
+   */
+  function deleteTags(array $tags);
+
+  /**
+   * Delete all cache items in a bin.
+   */
+  function deleteAll();
+
+  /**
+   * Delete expired items from the cache.
+   */
+  function deleteExpired();
+
+  /**
+   * Marks items as invalid.
+   *
+   * Invalid items may be returned in later calls to get(), if the $allowInvalid
+   * argument is TRUE.
+   *
+   * @param string $cid
+   *   The cache ID to invalidate.
    */
-  function flush();
+  function invalidate($cid);
 
   /**
-   * Expires temporary items from the cache.
+   * Marks items as invalid.
+   *
+   * Invalid items may be returned in later calls to get(), if the $allowInvalid
+   * argument is TRUE.
+   *
+   * @param string $cids
+   *   An array of cache IDs to invalidate.
    */
-  function expire();
+  function invalidateMultiple(array $cids);
 
   /**
-   * Invalidates each tag in the $tags array.
+   * Invalidates items with any of the specified tags.
    *
    * @param array $tags
    *   Associative array of tags, in the same format that is passed to
@@ -160,6 +194,8 @@ interface CacheBackendInterface {
 
   /**
    * Performs garbage collection on a cache bin.
+   *
+   * The backend may choose to delete expired or invalidated items.
    */
   function garbageCollection();
 
diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
index d4de8bf..f62a422 100644
--- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php
+++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
@@ -9,6 +9,7 @@ namespace Drupal\Core\Cache;
 
 use Drupal\Core\Database\Database;
 use Exception;
+use PDO;
 
 /**
  * Defines a default cache implementation.
@@ -24,11 +25,6 @@ class DatabaseBackend implements CacheBackendInterface {
   protected $bin;
 
   /**
-   * A static cache of all tags checked during the request.
-   */
-  protected static $tagCache = array();
-
-  /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::__construct().
    */
   function __construct($bin) {
@@ -43,16 +39,16 @@ class DatabaseBackend implements CacheBackendInterface {
   /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::get().
    */
-  function get($cid) {
+  function get($cid, $allowInvalid = FALSE) {
     $cids = array($cid);
-    $cache = $this->getMultiple($cids);
+    $cache = $this->getMultiple($cids, $allowInvalid);
     return reset($cache);
   }
 
   /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::getMultiple().
    */
-  function getMultiple(&$cids) {
+  function getMultiple(&$cids, $allowInvalid = FALSE) {
     try {
       // When serving cached pages, the overhead of using ::select() was found
       // to add around 30% overhead to the request. Since $this->bin is a
@@ -61,10 +57,10 @@ class DatabaseBackend implements CacheBackendInterface {
       // is used here only due to the performance overhead we would incur
       // otherwise. When serving an uncached page, the overhead of using
       // ::select() is a much smaller proportion of the request.
-      $result = Database::getConnection()->query('SELECT cid, data, created, expire, serialized, tags, checksum FROM {' . Database::getConnection()->escapeTable($this->bin) . '} WHERE cid IN (:cids)', array(':cids' => $cids));
+      $result = Database::getConnection()->query('SELECT cid, data, created, expire, serialized, tags, checksum_invalidations, checksum_deletions FROM {' . Database::getConnection()->escapeTable($this->bin) . '} WHERE cid IN (:cids)', array(':cids' => $cids));
       $cache = array();
       foreach ($result as $item) {
-        $item = $this->prepareItem($item);
+        $item = $this->prepareItem($item, $allowInvalid);
         if ($item) {
           $cache[$item->cid] = $item;
         }
@@ -87,24 +83,39 @@ class DatabaseBackend implements CacheBackendInterface {
    *
    * @param stdClass $cache
    *   An item loaded from cache_get() or cache_get_multiple().
+   * @param bool $allowInvalid
+   *   If FALSE, the method returns FALSE if the cache item is not valid.
    *
-   * @return mixed
-   *   The item with data unserialized as appropriate or FALSE if there is no
-   *   valid item to load.
+   * @return mixed|false
+   *   The item with data unserialized as appropriate and a property indicating
+   *   whether the item is valid, or FALSE if there is no valid item to load.
    */
-  protected function prepareItem($cache) {
+  protected function prepareItem($cache, $allowInvalid) {
     global $user;
 
     if (!isset($cache->data)) {
       return FALSE;
     }
 
-    // The cache data is invalid if any of its tags have been cleared since.
-    if ($cache->tags) {
-      $cache->tags = explode(' ', $cache->tags);
-      if (!$this->validTags($cache->checksum, $cache->tags)) {
-        return FALSE;
-      }
+    $flat_tags = $cache->tags ? explode(' ', $cache->tags) : array();
+
+    $checksum = $this->checksumTags($flat_tags);
+
+    // Check if deleteTags() has been called with any of the entry's tags.
+    if ($cache->checksum_deletions != $checksum['deletions']) {
+      return FALSE;
+    }
+
+    // Check expire time.
+    $cache->valid = $cache->expire == CacheBackendInterface::CACHE_PERMANENT || $cache->expire >= REQUEST_TIME;
+
+    // Check if invalidateTags() has been called with any of the entry's tags.
+    if ($cache->checksum_invalidations != $checksum['invalidations']) {
+      $cache->valid = FALSE;
+    }
+
+    if (!$allowInvalid && !$cache->valid) {
+      return FALSE;
     }
 
     // Unserialize and return the cached data.
@@ -119,12 +130,15 @@ class DatabaseBackend implements CacheBackendInterface {
    * Implements Drupal\Core\Cache\CacheBackendInterface::set().
    */
   function set($cid, $data, $expire = CacheBackendInterface::CACHE_PERMANENT, array $tags = array()) {
+    $flat_tags = $this->flattenTags($tags);
+    $checksum = $this->checksumTags($flat_tags);
     $fields = array(
       'serialized' => 0,
       'created' => REQUEST_TIME,
       'expire' => $expire,
-      'tags' => implode(' ', $this->flattenTags($tags)),
-      'checksum' => $this->checksumTags($tags),
+      'tags' => implode(' ', $flat_tags),
+      'checksum_invalidations' => $checksum['invalidations'],
+      'checksum_deletions' => $checksum['deletions'],
     );
     if (!is_string($data)) {
       $fields['data'] = serialize($data);
@@ -169,6 +183,21 @@ class DatabaseBackend implements CacheBackendInterface {
   }
 
   /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::deleteTags().
+   */
+  public function deleteTags(array $tags) {
+    $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache');
+    foreach ($this->flattenTags($tags) as $tag) {
+      unset($tag_cache[$tag]);
+      Database::getConnection()->merge('cache_tags')
+        ->insertFields(array('deletions' => 1))
+        ->expression('deletions', 'deletions + 1')
+        ->key(array('tag' => $tag))
+        ->execute();
+    }
+  }
+
+  /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::deletePrefix().
    */
   function deletePrefix($prefix) {
@@ -180,14 +209,14 @@ class DatabaseBackend implements CacheBackendInterface {
   /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::flush().
    */
-  function flush() {
+  function deleteAll() {
     Database::getConnection()->truncate($this->bin)->execute();
   }
 
   /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::expire().
    */
-  function expire() {
+  function deleteExpired() {
     Database::getConnection()->delete($this->bin)
       ->condition('expire', CacheBackendInterface::CACHE_PERMANENT, '<>')
       ->condition('expire', REQUEST_TIME, '<')
@@ -195,26 +224,46 @@ class DatabaseBackend implements CacheBackendInterface {
   }
 
   /**
-   * Implements Drupal\Core\Cache\CacheBackendInterface::garbageCollection().
+   * Implements Drupal\Core\Cache\CacheBackendInterface::invalidate().
    */
-  function garbageCollection() {
-    $this->expire();
+  function invalidate($cid) {
+    $this->invalidateMultiple(array($cid));
   }
 
   /**
-   * Compares two checksums of tags. Used to determine whether to serve a cached
-   * item or treat it as invalidated.
-   *
-   * @param integer @checksum
-   *   The initial checksum to compare against.
-   * @param array @tags
-   *   An array of tags to calculate a checksum for.
-   *
-   * @return boolean
-   *   TRUE if the checksums match, FALSE otherwise.
+   * Implements Drupal\Core\Cache\CacheBackendInterface::invalideMultiple().
+   */
+  function invalidateMultiple(array $cids) {
+    // Update in chunks when a large array is passed.
+    do {
+      Database::getConnection()->update($this->bin)
+        ->fields(array('expire' => REQUEST_TIME - 1))
+        ->condition('cid', array_splice($cids, 0, 1000), 'IN')
+        ->execute();
+    }
+    while (count($cids));
+  }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateTags().
    */
-  protected function validTags($checksum, array $tags) {
-    return $checksum == $this->checksumTags($tags);
+  public function invalidateTags(array $tags) {
+    $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache');
+    foreach ($this->flattenTags($tags) as $tag) {
+      unset($tag_cache[$tag]);
+      Database::getConnection()->merge('cache_tags')
+        ->insertFields(array('invalidations' => 1))
+        ->expression('invalidations', 'invalidations + 1')
+        ->key(array('tag' => $tag))
+        ->execute();
+    }
+  }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::garbageCollection().
+   */
+  function garbageCollection() {
+    $this->deleteExpired();
   }
 
   /**
@@ -224,7 +273,7 @@ class DatabaseBackend implements CacheBackendInterface {
    *   Associative array of tags to flatten.
    *
    * @return
-   *   Numeric array of flattened tag identifiers.
+   *   Numeric array of flat tag identifiers.
    */
   protected function flattenTags(array $tags) {
     if (isset($tags[0])) {
@@ -246,51 +295,42 @@ class DatabaseBackend implements CacheBackendInterface {
   }
 
   /**
-   * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateTags().
-   */
-  public function invalidateTags(array $tags) {
-    foreach ($this->flattenTags($tags) as $tag) {
-      unset(self::$tagCache[$tag]);
-      Database::getConnection()->merge('cache_tags')
-        ->key(array('tag' => $tag))
-        ->fields(array('invalidations' => 1))
-        ->expression('invalidations', 'invalidations + 1')
-        ->execute();
-    }
-  }
-
-  /**
    * Returns the sum total of validations for a given set of tags.
    *
    * @param array $tags
-   *   Associative array of tags.
+   *   Array of flat tags.
    *
    * @return integer
    *   Sum of all invalidations.
+   *
+   * @see Drupal\Core\Cache\DatabaseBackend::flattenTags()
    */
-  protected function checksumTags($tags) {
-    $checksum = 0;
-    $query_tags = array();
+  protected function checksumTags($flat_tags) {
+    $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache', array());
 
-    foreach ($this->flattenTags($tags) as $tag) {
-      if (isset(self::$tagCache[$tag])) {
-        $checksum += self::$tagCache[$tag];
-      }
-      else {
-        $query_tags[] = $tag;
-      }
-   }
+    $checksum = array(
+      'invalidations' => 0,
+      'deletions' => 0,
+    );
+
+    $query_tags = array_diff($flat_tags, array_keys($tag_cache));
     if ($query_tags) {
       try {
-        if ($db_tags = Database::getConnection()->query('SELECT tag, invalidations FROM {cache_tags} WHERE tag IN (:tags)', array(':tags' => $query_tags))->fetchAllKeyed()) {
-          self::$tagCache = array_merge(self::$tagCache, $db_tags);
-          $checksum += array_sum($db_tags);
-        }
+        $db_tags = Database::getConnection()->query('SELECT tag, invalidations, deletions FROM {cache_tags} WHERE tag IN (:tags)', array(':tags' => $query_tags))->fetchAllAssoc('tag', PDO::FETCH_ASSOC);
+        $tag_cache += $db_tags;
       }
       catch (Exception $e) {
         // The database may not be available, so we'll ignore cache_set requests.
       }
+      // Fill static cache with empty objects for tags not found in the database.
+      $tag_cache += array_fill_keys(array_diff($query_tags, array_keys($db_tags)), $checksum);
+    }
+
+    foreach ($flat_tags as $tag) {
+      $checksum['invalidations'] += $tag_cache[$tag]['invalidations'];
+      $checksum['deletions'] += $tag_cache[$tag]['deletions'];
     }
+
     return $checksum;
   }
 
diff --git a/core/lib/Drupal/Core/Cache/InstallBackend.php b/core/lib/Drupal/Core/Cache/InstallBackend.php
index b507684..3c7a6bb 100644
--- a/core/lib/Drupal/Core/Cache/InstallBackend.php
+++ b/core/lib/Drupal/Core/Cache/InstallBackend.php
@@ -36,14 +36,14 @@ class InstallBackend extends DatabaseBackend {
   /**
    * Overrides Drupal\Core\Cache\DatabaseBackend::get().
    */
-  function get($cid) {
+  function get($cid, $allowInvalid = FALSE) {
     return FALSE;
   }
 
   /**
    * Overrides Drupal\Core\Cache\DatabaseBackend::getMultiple().
    */
-  function getMultiple(&$cids) {
+  function getMultiple(&$cids, $allowInvalid = FALSE) {
     return array();
   }
 
@@ -89,36 +89,72 @@ class InstallBackend extends DatabaseBackend {
   }
 
   /**
-   * Overrides Drupal\Core\Cache\DatabaseBackend::invalidateTags().
+   * Overrides Drupal\Core\Cache\DatabaseBackend::deleteAll().
    */
-  function invalidateTags(array $tags) {
+  function deleteAll() {
     try {
       if (class_exists('Drupal\Core\Database\Database')) {
-        parent::invalidateTags($tags);
+        parent::deleteAll();
       }
     }
     catch (Exception $e) {}
   }
 
   /**
-   * Overrides Drupal\Core\Cache\DatabaseBackend::flush().
+   * Overrides Drupal\Core\Cache\DatabaseBackend::deleteExpired().
    */
-  function flush() {
+  function deleteExpired() {
     try {
       if (class_exists('Drupal\Core\Database\Database')) {
-        parent::flush();
+        parent::deleteExpired();
       }
     }
     catch (Exception $e) {}
   }
 
   /**
-   * Overrides Drupal\Core\Cache\DatabaseBackend::expire().
+   * Overrides Drupal\Core\Cache\DatabaseBackend::deleteTags().
    */
-  function expire() {
+  function deleteTags(array $tags) {
     try {
       if (class_exists('Drupal\Core\Database\Database')) {
-        parent::expire();
+        parent::deleteTags($tags);
+      }
+    }
+    catch (Exception $e) {}
+  }
+
+  /**
+   * Overrides Drupal\Core\Cache\DatabaseBackend::invalidate().
+   */
+  function invalidate($cid) {
+    try {
+      if (class_exists('Drupal\Core\Database\Database')) {
+        parent::invalidate($cid);
+      }
+    }
+    catch (Exception $e) {}
+  }
+
+  /**
+   * Overrides Drupal\Core\Cache\DatabaseBackend::invalidateMultiple().
+   */
+  function invalidateMultiple(array $cids) {
+    try {
+      if (class_exists('Drupal\Core\Database\Database')) {
+        parent::invalidateMultiple($cids);
+      }
+    }
+    catch (Exception $e) {}
+  }
+
+  /**
+   * Overrides Drupal\Core\Cache\DatabaseBackend::invalidateTags().
+   */
+  function invalidateTags(array $tags) {
+    try {
+      if (class_exists('Drupal\Core\Database\Database')) {
+        parent::invalidateTags($tags);
       }
     }
     catch (Exception $e) {}
diff --git a/core/lib/Drupal/Core/Cache/MemoryBackend.php b/core/lib/Drupal/Core/Cache/MemoryBackend.php
index 021b818..32ec501 100644
--- a/core/lib/Drupal/Core/Cache/MemoryBackend.php
+++ b/core/lib/Drupal/Core/Cache/MemoryBackend.php
@@ -24,11 +24,6 @@ class MemoryBackend implements CacheBackendInterface {
   protected $cache = array();
 
   /**
-   * All tags invalidated during the request.
-   */
-  protected $invalidatedTags = array();
-
-  /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::__construct().
    */
   public function __construct($bin) {
@@ -37,9 +32,9 @@ class MemoryBackend implements CacheBackendInterface {
   /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::get().
    */
-  public function get($cid) {
+  public function get($cid, $allowInvalid = FALSE) {
     if (isset($this->cache[$cid])) {
-      return $this->prepareItem($this->cache[$cid]);
+      return $this->prepareItem($this->cache[$cid], $allowInvalid);
     }
     else {
       return FALSE;
@@ -49,13 +44,13 @@ class MemoryBackend implements CacheBackendInterface {
   /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::getMultiple().
    */
-  public function getMultiple(&$cids) {
+  public function getMultiple(&$cids, $allowInvalid = FALSE) {
     $ret = array();
 
     $items = array_intersect_key($this->cache, array_flip($cids));
 
     foreach ($items as $item) {
-      $item = $this->prepareItem($item);
+      $item = $this->prepareItem($item, $allowInvalid);
       if ($item) {
         $ret[$item->cid] = $item;
       }
@@ -79,13 +74,15 @@ class MemoryBackend implements CacheBackendInterface {
    *   The item with data as appropriate or FALSE if there is no
    *   valid item to load.
    */
-  protected function prepareItem($cache) {
+  protected function prepareItem($cache, $allowInvalid) {
     if (!isset($cache->data)) {
       return FALSE;
     }
 
-    // The cache data is invalid if any of its tags have been cleared since.
-    if (count($cache->tags) && $this->hasInvalidatedTags($cache)) {
+    // Check expire time.
+    $cache->valid = $cache->expire == CacheBackendInterface::CACHE_PERMANENT || $cache->expire >= REQUEST_TIME;
+
+    if (!$allowInvalid && !$cache->valid) {
       return FALSE;
     }
 
@@ -99,28 +96,12 @@ class MemoryBackend implements CacheBackendInterface {
     $this->cache[$cid] = (object) array(
       'cid' => $cid,
       'data' => $data,
+      'created' => REQUEST_TIME,
       'expire' => $expire,
-      'tags' => $tags,
-      'checksum' => $this->checksum($this->flattenTags($tags)),
+      'flat_tags' => $this->flattenTags($tags),
     );
   }
 
-  /*
-   * Calculates a checksum so data can be invalidated using tags.
-   */
-  function checksum($tags) {
-    $checksum = "";
-
-    foreach($tags as $tag) {
-      // Has the tag already been invalidated.
-      if (isset($this->invalidatedTags[$tag])) {
-        $checksum = $checksum . $tag . ':' . $this->invalidatedTags[$tag];
-      }
-    }
-
-    return $checksum;
-  }
-
   /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::delete().
    */
@@ -147,37 +128,60 @@ class MemoryBackend implements CacheBackendInterface {
   }
 
   /**
-   * Implements Drupal\Core\Cache\CacheBackendInterface::flush().
+   * Implements Drupal\Core\Cache\CacheBackendInterface::deleteTags().
+   */
+  public function deleteTags(array $tags) {
+    $flat_tags = $this->flattenTags($tags);
+    foreach ($this->cache as $cid => $item) {
+      if (array_intersect($flat_tags, $item->flat_tags)) {
+        unset($this->cache[$cid]);
+      }
+    }
+  }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::deleteAll().
    */
-  public function flush() {
+  public function deleteAll() {
     $this->cache = array();
   }
 
   /**
-   * Implements Drupal\Core\Cache\CacheBackendInterface::expire().
+   * Implements Drupal\Core\Cache\CacheBackendInterface::deleteExpired().
    *
-   * Cache expiration is not implemented for PHP ArrayBackend as this backend
-   * only persists during a single request and expiration are done using
+   * Cache expiration is not implemented for MemoryBackend as this backend only
+   * persists during a single request and expiration are done using
    * REQUEST_TIME.
    */
-  public function expire() {
+  public function deleteExpired() {
   }
 
   /**
-   * Checks to see if any of the tags associated with a cache object have been
-   * invalidated.
-   *
-   * @param object @cache
-   *   An cache object to calculate and compare it's original checksum for.
-   *
-   * @return boolean
-   *   TRUE if the a tag has been invalidated, FALSE otherwise.
+   * Implements Drupal\Core\Cache\CacheBackendInterface::invalidate().
    */
-  protected function hasInvalidatedTags($cache) {
-    if ($cache->checksum != $this->checksum($this->flattenTags($cache->tags))) {
-      return TRUE;
+  public function invalidate($cid) {
+    $this->cache[$cid]->expire = REQUEST_TIME - 1;
+  }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple().
+   */
+  public function invalidateMultiple(array $cids) {
+    foreach ($cids as $cid) {
+      $this->cache[$cid]->expire = REQUEST_TIME - 1;
+    }
+  }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateTags().
+   */
+  public function invalidateTags(array $tags) {
+    $flat_tags = $this->flattenTags($tags);
+    foreach ($this->cache as $cid => $item) {
+      if (array_intersect($flat_tags, $item->flat_tags)) {
+        $this->cache[$cid]->expire = REQUEST_TIME - 1;
+      }
     }
-    return FALSE;
   }
 
   /**
@@ -187,7 +191,7 @@ class MemoryBackend implements CacheBackendInterface {
    *   Associative array of tags to flatten.
    *
    * @return
-   *   An array of flattened tag identifiers.
+   *   An array of flat tag identifiers.
    */
   protected function flattenTags(array $tags) {
     if (isset($tags[0])) {
@@ -209,21 +213,6 @@ class MemoryBackend implements CacheBackendInterface {
   }
 
   /**
-   * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateTags().
-   */
-  public function invalidateTags(array $tags) {
-    $flat_tags = $this->flattenTags($tags);
-    foreach($flat_tags as $tag) {
-      if (isset($this->invalidatedTags[$tag])) {
-        $this->invalidatedTags[$tag] = $this->invalidatedTags[$tag] + 1;
-      }
-      else {
-        $this->invalidatedTags[$tag] = 1;
-      }
-    }
-  }
-
-  /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::isEmpty().
    */
   public function isEmpty() {
diff --git a/core/lib/Drupal/Core/Cache/NullBackend.php b/core/lib/Drupal/Core/Cache/NullBackend.php
index dedd033..1a483a6 100644
--- a/core/lib/Drupal/Core/Cache/NullBackend.php
+++ b/core/lib/Drupal/Core/Cache/NullBackend.php
@@ -28,14 +28,14 @@ class NullBackend implements CacheBackendInterface {
   /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::get().
    */
-  function get($cid) {
+  function get($cid, $allowInvalid = FALSE) {
     return FALSE;
   }
 
   /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::getMultiple().
    */
-  function getMultiple(&$cids) {
+  function getMultiple(&$cids, $allowInvalid = FALSE) {
     return array();
   }
 
@@ -60,19 +60,29 @@ class NullBackend implements CacheBackendInterface {
   function deletePrefix($prefix) {}
 
   /**
-   * Implements Drupal\Core\Cache\CacheBackendInterface::flush().
+   * Implements Drupal\Core\Cache\CacheBackendInterface::deleteAll().
    */
-  function flush() {}
+  function deleteAll() {}
 
   /**
-   * Implements Drupal\Core\Cache\CacheBackendInterface::expire().
+   * Implements Drupal\Core\Cache\CacheBackendInterface::deleteExpired().
    */
-  function expire() {}
+  function deleteExpired() {}
 
   /**
-   * Implements Drupal\Core\Cache\CacheBackendInterface::garbageCollection().
+   * Implements Drupal\Core\Cache\CacheBackendInterface::deleteTags().
    */
-  function garbageCollection() {}
+  function deleteTags(array $tags) {}
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::invalidate().
+   */
+  public function invalidate($cid) {}
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple().
+   */
+  public function invalidateMultiple(array $cids) {}
 
   /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateTags().
@@ -80,6 +90,11 @@ class NullBackend implements CacheBackendInterface {
   public function invalidateTags(array $tags) {}
 
   /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::garbageCollection().
+   */
+  function garbageCollection() {}
+
+  /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::isEmpty().
    */
   function isEmpty() {
diff --git a/core/lib/Drupal/Core/Database/Query/Merge.php b/core/lib/Drupal/Core/Database/Query/Merge.php
index 547a223..13637a5 100644
--- a/core/lib/Drupal/Core/Database/Query/Merge.php
+++ b/core/lib/Drupal/Core/Database/Query/Merge.php
@@ -421,6 +421,7 @@ class Merge extends Query implements ConditionInterface {
             $insert->useDefaults($this->defaultFields);
           }
           $insert->execute();
+          #mail('chsc@chsc.dk', __METHOD__, ''.$insert.print_r(debug_backtrace(),1));exit;
           return self::STATUS_INSERT;
         }
         catch (Exception $e) {
@@ -442,6 +443,7 @@ class Merge extends Query implements ConditionInterface {
             $update->expression($field, $data['expression'], $data['arguments']);
           }
         }
+        #mail('chsc@chsc.dk', __METHOD__, ''.$update);
         $update->execute();
         return self::STATUS_UPDATE;
       }
diff --git a/core/modules/aggregator/aggregator.parser.inc b/core/modules/aggregator/aggregator.parser.inc
index bacaa84..ff2e522 100644
--- a/core/modules/aggregator/aggregator.parser.inc
+++ b/core/modules/aggregator/aggregator.parser.inc
@@ -45,7 +45,7 @@ function aggregator_aggregator_parse($feed) {
     $feed->modified = $modified;
 
     // Clear the page and block caches.
-    cache_invalidate(array('content' => TRUE));
+    cache_invalidate_tags(array('content' => TRUE));
 
     return TRUE;
   }
diff --git a/core/modules/block/block.admin.inc b/core/modules/block/block.admin.inc
index 848298f..a5668c8 100644
--- a/core/modules/block/block.admin.inc
+++ b/core/modules/block/block.admin.inc
@@ -205,7 +205,7 @@ function block_admin_display_form_submit($form, &$form_state) {
     throw $e;
   }
   drupal_set_message(t('The block settings have been updated.'));
-  cache_invalidate(array('content' => TRUE));
+  cache_invalidate_tags(array('content' => TRUE));
 }
 
 /**
@@ -603,7 +603,7 @@ function block_admin_configure_submit($form, &$form_state) {
       throw $e;
     }
     drupal_set_message(t('The block configuration has been saved.'));
-    cache_invalidate(array('content' => TRUE));
+    cache_invalidate_tags(array('content' => TRUE));
     $form_state['redirect'] = 'admin/structure/block';
   }
 }
@@ -712,7 +712,7 @@ function block_add_block_form_submit($form, &$form_state) {
   }
 
   drupal_set_message(t('The block has been created.'));
-  cache_invalidate(array('content' => TRUE));
+  cache_invalidate_tags(array('content' => TRUE));
   $form_state['redirect'] = 'admin/structure/block';
 }
 
@@ -760,7 +760,7 @@ function block_custom_block_delete_submit($form, &$form_state) {
     ->execute();
 
   drupal_set_message(t('The block %name has been removed.', array('%name' => $form_state['values']['info'])));
-  cache_invalidate(array('content' => TRUE));
+  cache_invalidate_tags(array('content' => TRUE));
   $form_state['redirect'] = 'admin/structure/block';
   return;
 }
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php
index 90327f9..f3520d7 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php
@@ -74,7 +74,7 @@ class BlockCacheTest extends WebTestBase {
     $this->assertText($old_content, t('Block is served from the cache.'));
 
     // Clear the cache and verify that the stale data is no longer there.
-    cache_invalidate(array('content' => TRUE));
+    cache_invalidate_tags(array('content' => TRUE));
     $this->drupalGet('');
     $this->assertNoText($old_content, t('Block cache clear removes stale cache data.'));
     $this->assertText($current_content, t('Fresh block content is displayed after clearing the cache.'));
diff --git a/core/modules/comment/comment.admin.inc b/core/modules/comment/comment.admin.inc
index 6210cc5..54cc238 100644
--- a/core/modules/comment/comment.admin.inc
+++ b/core/modules/comment/comment.admin.inc
@@ -194,7 +194,7 @@ function comment_admin_overview_submit($form, &$form_state) {
   }
   drupal_set_message(t('The update has been performed.'));
   $form_state['redirect'] = 'admin/content/comment';
-  cache_invalidate(array('content' => TRUE));
+  cache_invalidate_tags(array('content' => TRUE));
 }
 
 /**
@@ -242,7 +242,7 @@ function comment_multiple_delete_confirm($form, &$form_state) {
 function comment_multiple_delete_confirm_submit($form, &$form_state) {
   if ($form_state['values']['confirm']) {
     comment_delete_multiple(array_keys($form_state['values']['comments']));
-    cache_invalidate(array('content' => TRUE));
+    cache_invalidate_tags(array('content' => TRUE));
     $count = count($form_state['values']['comments']);
     watchdog('content', 'Deleted @count comments.', array('@count' => $count));
     drupal_set_message(format_plural($count, 'Deleted 1 comment.', 'Deleted @count comments.'));
@@ -301,7 +301,7 @@ function comment_confirm_delete_submit($form, &$form_state) {
   drupal_set_message(t('The comment and all its replies have been deleted.'));
   watchdog('content', 'Deleted comment @cid and its replies.', array('@cid' => $comment->cid));
   // Clear the cache so an anonymous user sees that his comment was deleted.
-  cache_invalidate(array('content' => TRUE));
+  cache_invalidate_tags(array('content' => TRUE));
 
   $form_state['redirect'] = "node/$comment->nid";
 }
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index bd9c107..be2649c 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -2064,7 +2064,7 @@ function comment_unpublish_by_keyword_action_submit($form, $form_state) {
  */
 function comment_save_action(Comment $comment) {
   comment_save($comment);
-  cache_invalidate(array('content' => TRUE));
+  cache_invalidate_tags(array('content' => TRUE));
   watchdog('action', 'Saved comment %title', array('%title' => $comment->subject));
 }
 
diff --git a/core/modules/comment/lib/Drupal/comment/CommentFormController.php b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
index 7dae92d..91a62f9 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentFormController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
@@ -373,6 +373,6 @@ class CommentFormController extends EntityFormController {
     $form_state['redirect'] = $redirect;
     // Clear the block and page caches so that anonymous users see the comment
     // they have posted.
-    cache_invalidate(array('content' => TRUE));
+    cache_invalidate_tags(array('content' => TRUE));
   }
 }
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentBlockTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentBlockTest.php
index b43029f..66385f3 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentBlockTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentBlockTest.php
@@ -51,7 +51,7 @@ class CommentBlockTest extends CommentTestBase {
     user_role_revoke_permissions(DRUPAL_ANONYMOUS_RID, array('access comments'));
     // drupalCreateNode() does not automatically flush content caches unlike
     // posting a node from a node form.
-    cache_invalidate(array('content' => TRUE));
+    cache_invalidate_tags(array('content' => TRUE));
     $this->drupalGet('');
     $this->assertNoText($block['title'], t('Block was not found.'));
     user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access comments'));
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index 72b6d91..9e438b0 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -763,7 +763,7 @@ function _field_extra_fields_pre_render($elements) {
  * Clear the field info and field data caches.
  */
 function field_cache_clear() {
-  cache('field')->flush();
+  cache('field')->deleteAll();
   field_info_cache_clear();
 }
 
diff --git a/core/modules/forum/forum.admin.inc b/core/modules/forum/forum.admin.inc
index e3c564a..e128aa4 100644
--- a/core/modules/forum/forum.admin.inc
+++ b/core/modules/forum/forum.admin.inc
@@ -115,7 +115,7 @@ function forum_form_submit($form, &$form_state) {
     case SAVED_UPDATED:
       drupal_set_message(t('The @type %term has been updated.', array('%term' => $form_state['values']['name'], '@type' => $type)));
       // Clear the page and block caches to avoid stale data.
-      cache_invalidate(array('content' => TRUE));
+      cache_invalidate_tags(array('content' => TRUE));
       break;
   }
   $form_state['redirect'] = 'admin/structure/forum';
diff --git a/core/modules/image/image.api.php b/core/modules/image/image.api.php
index 163bf2c..2b32e24 100644
--- a/core/modules/image/image.api.php
+++ b/core/modules/image/image.api.php
@@ -116,7 +116,7 @@ function hook_image_style_delete($style) {
  */
 function hook_image_style_flush($style) {
   // Empty cached data that contains information about the style.
-  cache('mymodule')->flush();
+  cache('mymodule')->deleteAll();
 }
 
 /**
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index 45e76ea..3738752 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -909,9 +909,9 @@ function image_style_flush($style) {
 
   // Clear page caches when flushing.
   if (module_exists('block')) {
-    cache('block')->flush();
+    cache('block')->deleteAll();
   }
-  cache('page')->flush();
+  cache('page')->deleteAll();
 }
 
 /**
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php
index 1c7265c..292a49a 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php
@@ -249,7 +249,7 @@ class LocaleTranslationTest extends WebTestBase {
     // Test JavaScript translation rebuilding.
     file_unmanaged_delete($js_file);
     $this->assertTrue($result = !file_exists($js_file), t('JavaScript file deleted: %file', array('%file' => $result ? $js_file : t('found'))));
-    cache_invalidate(array('content' => TRUE));
+    cache_invalidate_tags(array('content' => TRUE));
     _locale_rebuild_js($langcode);
     $this->assertTrue($result = file_exists($js_file), t('JavaScript file rebuilt: %file', array('%file' => $result ? $js_file : t('not found'))));
   }
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 86689ac..d688d03 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -192,7 +192,7 @@ function locale_stream_wrappers() {
 function locale_language_insert($language) {
   // @todo move these two cache clears out. See http://drupal.org/node/1293252
   // Changing the language settings impacts the interface.
-  cache('page')->flush();
+  cache('page')->deleteAll();
   // Force JavaScript translation file re-creation for the new language.
   _locale_invalidate_js($language->langcode);
 }
@@ -203,7 +203,7 @@ function locale_language_insert($language) {
 function locale_language_update($language) {
   // @todo move these two cache clears out. See http://drupal.org/node/1293252
   // Changing the language settings impacts the interface.
-  cache('page')->flush();
+  cache('page')->deleteAll();
   // Force JavaScript translation file re-creation for the modified language.
   _locale_invalidate_js($language->langcode);
 }
@@ -224,7 +224,7 @@ function locale_language_delete($language) {
   _locale_invalidate_js($language->langcode);
 
   // Changing the language settings impacts the interface:
-  cache('page')->flush();
+  cache('page')->deleteAll();
 
   // Clearing all locale cache from database
   cache()->delete('locale:' . $language->langcode);
diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php
index b9bf7eb..59eb267 100644
--- a/core/modules/node/lib/Drupal/node/NodeFormController.php
+++ b/core/modules/node/lib/Drupal/node/NodeFormController.php
@@ -407,7 +407,7 @@ class NodeFormController extends EntityFormController {
     }
 
     // Clear the page and block caches.
-    cache_invalidate(array('content' => TRUE));
+    cache_invalidate_tags(array('content' => TRUE));
   }
 
   /**
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeBlockFunctionalTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeBlockFunctionalTest.php
index 0c86de2..666039d 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeBlockFunctionalTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeBlockFunctionalTest.php
@@ -113,7 +113,7 @@ class NodeBlockFunctionalTest extends NodeTestBase {
     $node4 = $this->drupalCreateNode($default_settings);
     // drupalCreateNode() does not automatically flush content caches unlike
     // posting a node from a node form.
-    cache_invalidate(array('content' => TRUE));
+    cache_invalidate_tags(array('content' => TRUE));
 
     // Test that all four nodes are shown.
     $this->drupalGet('');
diff --git a/core/modules/node/node.admin.inc b/core/modules/node/node.admin.inc
index db113f5..2014167 100644
--- a/core/modules/node/node.admin.inc
+++ b/core/modules/node/node.admin.inc
@@ -612,7 +612,7 @@ function node_admin_nodes_submit($form, &$form_state) {
     }
     call_user_func_array($function, $args);
 
-    cache_invalidate(array('content' => TRUE));
+    cache_invalidate_tags(array('content' => TRUE));
   }
   else {
     // We need to rebuild the form to go to a second step. For example, to
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index bca8d9b..dc61c8d 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -3552,7 +3552,7 @@ function node_access_rebuild($batch_mode = FALSE) {
   if (!isset($batch)) {
     drupal_set_message(t('Content permissions have been rebuilt.'));
     node_access_needs_rebuild(FALSE);
-    cache_invalidate(array('content' => TRUE));
+    cache_invalidate_tags(array('content' => TRUE));
   }
 }
 
@@ -3602,7 +3602,7 @@ function _node_access_rebuild_batch_finished($success, $results, $operations) {
   else {
     drupal_set_message(t('The content access permissions have not been properly rebuilt.'), 'error');
   }
-  cache_invalidate(array('content' => TRUE));
+  cache_invalidate_tags(array('content' => TRUE));
 }
 
 /**
diff --git a/core/modules/path/lib/Drupal/path/Tests/PathAliasTest.php b/core/modules/path/lib/Drupal/path/Tests/PathAliasTest.php
index dcaf945..835a981 100644
--- a/core/modules/path/lib/Drupal/path/Tests/PathAliasTest.php
+++ b/core/modules/path/lib/Drupal/path/Tests/PathAliasTest.php
@@ -50,12 +50,12 @@ class PathAliasTest extends PathTestBase {
 
     // Visit the system path for the node and confirm a cache entry is
     // created.
-    cache('path')->flush();
+    cache('path')->deleteAll();
     $this->drupalGet($edit['source']);
     $this->assertTrue(cache('path')->get($edit['source']), t('Cache entry was created.'));
 
     // Visit the alias for the node and confirm a cache entry is created.
-    cache('path')->flush();
+    cache('path')->deleteAll();
     $this->drupalGet($edit['alias']);
     // @todo The alias should actually have been cached with the system path as
     // the key, see the todo in drupal_cache_system_paths() in path.inc.
diff --git a/core/modules/poll/poll.module b/core/modules/poll/poll.module
index dc4722e..1bd4b22 100644
--- a/core/modules/poll/poll.module
+++ b/core/modules/poll/poll.module
@@ -759,7 +759,7 @@ function poll_vote($form, &$form_state) {
     ->condition('chid', $choice)
     ->execute();
 
-  cache_invalidate(array('content' => TRUE));
+  cache_invalidate_tags(array('content' => TRUE));
 
   if (!$user->uid) {
     // The vote is recorded so the user gets the result view instead of the
diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/CacheTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Cache/CacheTestBase.php
index e4b275e..49a3d21 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Cache/CacheTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Cache/CacheTestBase.php
@@ -98,6 +98,6 @@ abstract class CacheTestBase extends WebTestBase {
       $bin = $this->default_bin;
     }
 
-    cache($bin)->expire();
+    cache($bin)->deleteExpired();
   }
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php
index 5cc023b..5ca1dfa 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php
@@ -99,7 +99,7 @@ abstract class GenericCacheBackendUnitTestBase extends UnitTestBase {
     if (!isset($this->cachebackends[$bin])) {
       $this->cachebackends[$bin] = $this->createCacheBackend($bin);
       // Ensure the backend is empty.
-      $this->cachebackends[$bin]->flush();
+      $this->cachebackends[$bin]->deleteAll();
     }
     return $this->cachebackends[$bin];
   }
@@ -115,10 +115,10 @@ abstract class GenericCacheBackendUnitTestBase extends UnitTestBase {
 
   public function tearDown() {
     // Destruct the registered backend, each test will get a fresh instance,
-    // properly flushing it here ensure that on persistant data backends they
+    // properly emptying it here ensure that on persistant data backends they
     // will come up empty the next test.
     foreach ($this->cachebackends as $bin => $cachebackend) {
-      $this->cachebackends[$bin]->flush();
+      $this->cachebackends[$bin]->deleteAll();
     }
     unset($this->cachebackends);
 
@@ -134,19 +134,31 @@ abstract class GenericCacheBackendUnitTestBase extends UnitTestBase {
   public function testSetGet() {
     $backend = $this->getCacheBackend();
 
-    $data = 7;
     $this->assertIdentical(FALSE, $backend->get('test1'), "Backend does not contain data for cache id test1.");
-    $backend->set('test1', $data);
+    $backend->set('test1', 7);
     $cached = $backend->get('test1');
     $this->assert(is_object($cached), "Backend returned an object for cache id test1.");
-    $this->assertIdentical($data, $cached->data);
+    $this->assertIdentical(7, $cached->data);
+    $this->assertTrue($cached->valid, 'Item is marked as valid.');
+    $this->assertEqual($cached->created, REQUEST_TIME, 'Created time is correct.');
+    $this->assertEqual($cached->expire, CacheBackendInterface::CACHE_PERMANENT, 'Expire time is correct.');
 
-    $data = array('value' => 3);
     $this->assertIdentical(FALSE, $backend->get('test2'), "Backend does not contain data for cache id test2.");
-    $backend->set('test2', $data);
+    $backend->set('test2', array('value' => 3), REQUEST_TIME + 3);
     $cached = $backend->get('test2');
     $this->assert(is_object($cached), "Backend returned an object for cache id test2.");
-    $this->assertIdentical($data, $cached->data);
+    $this->assertIdentical(array('value' => 3), $cached->data);
+    $this->assertTrue($cached->valid, 'Item is marked as valid.');
+    $this->assertEqual($cached->created, REQUEST_TIME, 'Created time is correct.');
+    $this->assertEqual($cached->expire, REQUEST_TIME + 3, 'Expire time is correct.');
+
+    $backend->set('test3', 'foobar', REQUEST_TIME - 3);
+    $this->assertFalse($backend->get('test3'), 'Invalid item not returned.');
+    $cached = $backend->get('test3', TRUE);
+    $this->assert(is_object($cached), 'Backend returned an object for cache id test3.');
+    $this->assertFalse($cached->valid, 'Item is marked as valid.');
+    $this->assertEqual($cached->created, REQUEST_TIME, 'Created time is correct.');
+    $this->assertEqual($cached->expire, REQUEST_TIME - 3, 'Expire time is correct.');
   }
 
   /**
@@ -184,7 +196,7 @@ abstract class GenericCacheBackendUnitTestBase extends UnitTestBase {
       'test2' => '0',
       'test3' => '',
       'test4' => 12.64,
-      'test5' => false,
+      'test5' => FALSE,
       'test6' => array(1,2,3),
     );
 
@@ -222,7 +234,7 @@ abstract class GenericCacheBackendUnitTestBase extends UnitTestBase {
       'test7',
       'test21', // Cid does not exist.
       'test6',
-      'test19', // Cid does not exist until added before second getMulitple().
+      'test19', // Cid does not exist until added before second getMultiple().
       'test2',
     );
 
@@ -233,6 +245,10 @@ abstract class GenericCacheBackendUnitTestBase extends UnitTestBase {
     $this->assert(isset($ret['test3']), "Existing cache id test3 is set.");
     $this->assert(isset($ret['test6']), "Existing cache id test6 is set.");
     $this->assert(isset($ret['test7']), "Existing cache id test7 is set.");
+    // Test return - ensure that objects has expected properties.
+    $this->assertTrue($ret['test2']->valid, 'Item is marked as valid.');
+    $this->assertEqual($ret['test2']->created, REQUEST_TIME, 'Created time is correct.');
+    $this->assertEqual($ret['test2']->expire, CacheBackendInterface::CACHE_PERMANENT, 'Expire time is correct.');
     // Test return - ensure it does not contain nonexistent cache ids.
     $this->assertFalse(isset($ret['test19']), "Nonexistent cache id test19 is not set.");
     $this->assertFalse(isset($ret['test21']), "Nonexistent cache id test21 is not set.");
@@ -296,7 +312,8 @@ abstract class GenericCacheBackendUnitTestBase extends UnitTestBase {
   }
 
   /**
-   * Test Drupal\Core\Cache\CacheBackendInterface::deleteMultiple().
+   * Test Drupal\Core\Cache\CacheBackendInterface::delete() and
+   * Drupal\Core\Cache\CacheBackendInterface::deleteMultiple().
    */
   public function testDeleteMultiple() {
     $backend = $this->getCacheBackend();
@@ -310,8 +327,9 @@ abstract class GenericCacheBackendUnitTestBase extends UnitTestBase {
     $backend->set('test6', 13);
     $backend->set('test7', 17);
 
+    $backend->delete('test1');
+    $backend->delete('test23'); // Nonexistent key should not cause an error.
     $backend->deleteMultiple(array(
-      'test1',
       'test3',
       'test5',
       'test7',
@@ -371,92 +389,155 @@ abstract class GenericCacheBackendUnitTestBase extends UnitTestBase {
   }
 
   /**
-   * Test Drupal\Core\Cache\CacheBackendInterface::flush().
+   * Test Drupal\Core\Cache\CacheBackendInterface::deleteTags().
    */
-  public function testFlush() {
+  function testDeleteTags() {
+    $backend = $this->getCacheBackend();
+
+    // Create two cache entries with the same tag and tag value.
+    $backend->set('test_cid_invalidate1', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => 2));
+    $backend->set('test_cid_invalidate2', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => 2));
+    $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2'), 'Two cache items were created.');
+
+    // Delete test_tag of value 1. This should delete both entries.
+    $backend->deleteTags(array('test_tag' => 2));
+    $this->assertFalse($backend->get('test_cid_invalidate1') || $backend->get('test_cid_invalidate2'), 'Two cache items invalidated after deleting a cache tag.');
+    $this->assertFalse($backend->get('test_cid_invalidate1', TRUE) || $backend->get('test_cid_invalidate2', TRUE), 'Two cache items deleted after deleting a cache tag.');
+
+    // Create two cache entries with the same tag and an array tag value.
+    $backend->set('test_cid_invalidate1', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => array(1)));
+    $backend->set('test_cid_invalidate2', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => array(1)));
+    $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2'), 'Two cache items were created.');
+
+    // Delete test_tag of value 1. This should delete both entries.
+    $backend->deleteTags(array('test_tag' => array(1)));
+    $this->assertFalse($backend->get('test_cid_invalidate1') || $backend->get('test_cid_invalidate2'), 'Two cache items invalidated after deleted a cache tag.');
+    $this->assertFalse($backend->get('test_cid_invalidate1', TRUE) || $backend->get('test_cid_invalidate2', TRUE), 'Two cache items deleted after deleting a cache tag.');
+
+    // Create three cache entries with a mix of tags and tag values.
+    $backend->set('test_cid_invalidate1', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => array(1)));
+    $backend->set('test_cid_invalidate2', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => array(2)));
+    $backend->set('test_cid_invalidate3', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag_foo' => array(3)));
+    $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2') && $backend->get('test_cid_invalidate3'), 'Three cached items were created.');
+    $backend->deleteTags(array('test_tag_foo' => array(3)));
+    $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2'), 'Cached items not matching the tag were not deleted.');
+    $this->assertFalse($backend->get('test_cid_invalidated3', TRUE), 'Cache item matching the tag was deleted.');
+
+    // Create cache entry in multiple bins. Two cache entries
+    // (test_cid_invalidate1 and test_cid_invalidate2) still exist from previous
+    // tests.
+    $tags = array('test_tag' => array(1, 2, 3));
+    $bins = array('path', 'bootstrap', 'page');
+    foreach ($bins as $bin) {
+      $this->getCacheBackend($bin)->set('test', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, $tags);
+      $this->assertTrue($this->getCacheBackend($bin)->get('test'), 'Cache item was set in bin.');
+    }
+
+    // Delete tag in mulitple bins.
+    foreach ($bins as $bin) {
+      $this->getCacheBackend($bin)->deleteTags(array('test_tag' => array(2)));
+    }
+
+    // Test that cache entry has been deleted in multple bins.
+    foreach ($bins as $bin) {
+      $this->assertFalse($this->getCacheBackend($bin)->get('test', TRUE), 'Tag deletion affected item in bin.');
+    }
+    // Test that the cache entry with a matching tag has been invalidated.
+    $this->assertFalse($this->getCacheBackend($bin)->get('test_cid_invalidate2', TRUE), 'Cache items matching tag were deleted.');
+    // Test that the cache entry with without a matching tag still exists.
+    $this->assertTrue($this->getCacheBackend($bin)->get('test_cid_invalidate1'), 'Cache items not matching tag were not invalidated.');
+  }
+
+  /**
+   * Test Drupal\Core\Cache\CacheBackendInterface::deleteAll().
+   */
+  public function testDeleteAll() {
     $backend = $this->getCacheBackend();
 
     // Set both expiring and permanent keys.
     $backend->set('test1', 1, CacheBackendInterface::CACHE_PERMANENT);
     $backend->set('test2', 3, time() + 1000);
 
-    $backend->flush();
+    $backend->deleteAll();
 
-    $this->assertTrue($backend->isEmpty(), "Backend is empty after flush.");
+    $this->assertTrue($backend->isEmpty(), "Backend is empty after deleteAll().");
 
-    $this->assertIdentical(FALSE, $backend->get('test1'), "First key has been flushed.");
-    $this->assertIdentical(FALSE, $backend->get('test2'), "Second key has been flushed.");
+    $this->assertIdentical(FALSE, $backend->get('test1'), "First key has been deleted.");
+    $this->assertIdentical(FALSE, $backend->get('test2'), "Second key has been deleted.");
   }
 
   /**
-   * Check whether or not a cache entry exists.
-   *
-   * @param $cid
-   *   The cache id.
-   * @param $bin
-   *   The cache bin to use. If not provided the default test bin wil be used.
-   *
-   * @return
-   *   TRUE on pass, FALSE on fail.
+   * Test Drupal\Core\Cache\CacheBackendInterface::invalidate() and
+   * Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple().
    */
-  protected function checkCacheExists($cid, $bin = null) {
-    $cached = $this->getCacheBackend($bin)->get($cid);
-    return isset($cached->data);
+  function testInvalidate() {
+    $backend = $this->getCacheBackend();
+    $backend->set('test1', 1);
+    $backend->set('test2', 2);
+    $backend->set('test3', 2);
+    $backend->set('test4', 2);
+
+    $reference = array('test1', 'test2', 'test3', 'test4');
+
+    $cids = $reference;
+    $ret = $backend->getMultiple($cids);
+    $this->assertEqual(count($ret), 4, 'Four items returned.');
+
+    $backend->invalidate('test1');
+    $backend->invalidateMultiple(array('test2', 'test3'));
+
+    $cids = $reference;
+    $ret = $backend->getMultiple($cids);
+    $this->assertEqual(count($ret), 1, 'Only one item element returned.');
+
+    $cids = $reference;
+    $ret = $backend->getMultiple($cids, TRUE);
+    $this->assertEqual(count($ret), 4, 'Four items returned.');
   }
 
   /**
    * Test Drupal\Core\Cache\CacheBackendInterface::invalidateTags().
    */
-  function testClearTags() {
+  function testInvalidateTags() {
     $backend = $this->getCacheBackend();
 
     // Create two cache entries with the same tag and tag value.
-    $backend->set('test_cid_clear1', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => 2));
-    $backend->set('test_cid_clear2', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => 2));
-    $this->assertTrue($this->checkCacheExists('test_cid_clear1')
-                      && $this->checkCacheExists('test_cid_clear2'),
-                      'Two cache items were created.');
+    $backend->set('test_cid_invalidate1', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => 2));
+    $backend->set('test_cid_invalidate2', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => 2));
+    $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2'), 'Two cache items were created.');
+
     // Invalidate test_tag of value 1. This should invalidate both entries.
     $backend->invalidateTags(array('test_tag' => 2));
-    $this->assertFalse($this->checkCacheExists('test_cid_clear1')
-                      || $this->checkCacheExists('test_cid_clear2'),
-                      'Two caches removed after clearing a cache tag.');
+    $this->assertFalse($backend->get('test_cid_invalidate1') || $backend->get('test_cid_invalidate2'), 'Two cache items invalidated after invalidating a cache tag.');
+    $this->assertTrue($backend->get('test_cid_invalidate1', TRUE) && $backend->get('test_cid_invalidate2', TRUE), 'Cache items not deleted after invalidating a cache tag.');
 
     // Create two cache entries with the same tag and an array tag value.
-    $backend->set('test_cid_clear1', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => array(1)));
-    $backend->set('test_cid_clear2', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => array(1)));
-    $this->assertTrue($this->checkCacheExists('test_cid_clear1')
-                      && $this->checkCacheExists('test_cid_clear2'),
-                      'Two cache items were created.');
+    $backend->set('test_cid_invalidate1', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => array(1)));
+    $backend->set('test_cid_invalidate2', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => array(1)));
+    $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2'), 'Two cache items were created.');
+
     // Invalidate test_tag of value 1. This should invalidate both entries.
     $backend->invalidateTags(array('test_tag' => array(1)));
-    $this->assertFalse($this->checkCacheExists('test_cid_clear1')
-                      || $this->checkCacheExists('test_cid_clear2'),
-                      'Two caches removed after clearing a cache tag.');
+    $this->assertFalse($backend->get('test_cid_invalidate1') || $backend->get('test_cid_invalidate2'), 'Two caches removed after invalidating a cache tag.');
+    $this->assertTrue($backend->get('test_cid_invalidate1', TRUE) && $backend->get('test_cid_invalidate2', TRUE), 'Cache items not deleted after invalidating a cache tag.');
 
     // Create three cache entries with a mix of tags and tag values.
-    $backend->set('test_cid_clear1', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => array(1)));
-    $backend->set('test_cid_clear2', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => array(2)));
-    $backend->set('test_cid_clear3', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag_foo' => array(3)));
-    $this->assertTrue($this->checkCacheExists('test_cid_clear1')
-                      && $this->checkCacheExists('test_cid_clear2')
-                      && $this->checkCacheExists('test_cid_clear3'),
-                      'Two cached items were created.');
+    $backend->set('test_cid_invalidate1', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => array(1)));
+    $backend->set('test_cid_invalidate2', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag' => array(2)));
+    $backend->set('test_cid_invalidate3', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, array('test_tag_foo' => array(3)));
+    $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2') && $backend->get('test_cid_invalidate3'), 'Three cached items were created.');
     $backend->invalidateTags(array('test_tag_foo' => array(3)));
-    $this->assertTrue($this->checkCacheExists('test_cid_clear1')
-                      && $this->checkCacheExists('test_cid_clear2'),
-                      'Cached items not matching the tag were not cleared.');
-
-    $this->assertFalse($this->checkCacheExists('test_cid_clear3'),
-                      'Cached item matching the tag was removed.');
+    $this->assertTrue($backend->get('test_cid_invalidate1') && $backend->get('test_cid_invalidate2'), 'Cache items not matching the tag were not invalidated.');
+    $this->assertFalse($backend->get('test_cid_invalidated3'), 'Cached item matching the tag was removed.');
 
-    // Create cache entry in multiple bins. Two cache entries (test_cid_clear1
-    // and test_cid_clear2) still exist from previous tests.
+    // Create cache entry in multiple bins. Two cache entries
+    // (test_cid_invalidate1 and test_cid_invalidate2) still exist from previous
+    // tests.
     $tags = array('test_tag' => array(1, 2, 3));
     $bins = array('path', 'bootstrap', 'page');
     foreach ($bins as $bin) {
       $this->getCacheBackend($bin)->set('test', $this->defaultValue, CacheBackendInterface::CACHE_PERMANENT, $tags);
-      $this->assertTrue($this->checkCacheExists('test', $bin), 'Cache item was set in bin.');
+      $this->assertTrue($this->getCacheBackend($bin)->get('test'), 'Cache item was set in bin.');
     }
 
     // Invalidate tag in mulitple bins.
@@ -466,11 +547,11 @@ abstract class GenericCacheBackendUnitTestBase extends UnitTestBase {
 
     // Test that cache entry has been invalidated in multple bins.
     foreach ($bins as $bin) {
-      $this->assertFalse($this->checkCacheExists('test', $bin), 'Tag expire affected item in bin.');
+      $this->assertFalse($this->getCacheBackend($bin)->get('test'), 'Tag invalidation affected item in bin.');
     }
     // Test that the cache entry with a matching tag has been invalidated.
-    $this->assertFalse($this->checkCacheExists('test_cid_clear2', $bin), 'Cached items matching tag were cleared.');
+    $this->assertFalse($this->getCacheBackend($bin)->get('test_cid_invalidate2'), 'Cache items matching tag were invalidated.');
     // Test that the cache entry with without a matching tag still exists.
-    $this->assertTrue($this->checkCacheExists('test_cid_clear1', $bin), 'Cached items not matching tag were not cleared.');
+    $this->assertTrue($this->getCacheBackend($bin)->get('test_cid_invalidate1'), 'Cache items not matching tag were not invalidated.');
   }
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/InstallTest.php b/core/modules/system/lib/Drupal/system/Tests/Cache/InstallTest.php
index a2199c2..84313b9 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Cache/InstallTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Cache/InstallTest.php
@@ -96,7 +96,7 @@ class InstallTest extends CacheTestBase {
     $database_cache->set('cache_two', 'Two');
     $this->assertEqual($database_cache->get('cache_one')->data, 'One');
     $this->assertEqual($database_cache->get('cache_two')->data, 'Two');
-    $install_cache->flush();
+    $install_cache->deleteAll();
     $this->assertFalse($database_cache->get('cache_one'));
     $this->assertFalse($database_cache->get('cache_two'));
 
@@ -118,8 +118,8 @@ class InstallTest extends CacheTestBase {
       $install_cache->delete('cache_one');
       $install_cache->deleteMultiple(array('cache_one', 'cache_two'));
       $install_cache->deletePrefix('cache_');
-      $install_cache->flush();
-      $install_cache->expire();
+      $install_cache->deleteAll();
+      $install_cache->deleteExpired();
       $install_cache->garbageCollection();
       $install_cache->invalidateTags(array('tag'));
       $this->pass("The installer's cache backend can be used even when the cache database tables are unavailable.");
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index 2bf4343..a500334 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -735,7 +735,7 @@ function system_theme_settings_submit($form, &$form_state) {
   variable_set($key, $values);
   drupal_set_message(t('The configuration options have been saved.'));
 
-  cache_invalidate(array('content' => TRUE));
+  cache_invalidate_tags(array('content' => TRUE));
 }
 
 /**
@@ -1812,7 +1812,7 @@ function system_clear_cache_submit($form, &$form_state) {
  * @ingroup forms
  */
 function system_clear_page_cache_submit($form, &$form_state) {
-  cache('page')->flush();
+  cache('page')->deleteAll();
 }
 
 /**
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 4fe99f9..8e17bd9 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -667,6 +667,12 @@ function system_schema() {
         'not null' => TRUE,
         'default' => 0,
       ),
+      'deletions' => array(
+        'description' => 'Number incremented when the tag is deleted.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
     ),
     'primary key' => array('tag'),
   );
@@ -712,12 +718,18 @@ function system_schema() {
         'size' => 'big',
         'not null' => FALSE,
       ),
-      'checksum' => array(
+      'checksum_invalidations' => array(
         'description' => 'The tag invalidation sum when this entry was saved.',
         'type' => 'int',
         'not null' => TRUE,
         'default' => 0,
       ),
+      'checksum_deletions' => array(
+        'description' => 'The tag deletion sum when this entry was saved.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
     ),
     'indexes' => array(
       'expire' => array('expire'),
@@ -1550,12 +1562,18 @@ function system_schema_cache_8007() {
         'size' => 'big',
         'not null' => FALSE,
       ),
-      'checksum' => array(
+      'checksum_invalidations' => array(
         'description' => 'The tag invalidation sum when this entry was saved.',
         'type' => 'int',
         'not null' => TRUE,
         'default' => 0,
       ),
+      'checksum_deletions' => array(
+        'description' => 'The tag deletion sum when this entry was saved.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
     ),
     'indexes' => array(
       'expire' => array('expire'),
@@ -1676,12 +1694,18 @@ function system_update_8003() {
         'size' => 'big',
         'not null' => FALSE,
       ),
-      'checksum' => array(
+      'checksum_invalidations' => array(
         'description' => 'The tag invalidation sum when this entry was saved.',
         'type' => 'int',
         'not null' => TRUE,
         'default' => 0,
       ),
+      'checksum_deletions' => array(
+        'description' => 'The tag deletion sum when this entry was saved.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
     ),
     'indexes' => array(
       'expire' => array('expire'),
@@ -1752,6 +1776,12 @@ function system_update_8006() {
         'not null' => TRUE,
         'default' => 0,
       ),
+      'deletions' => array(
+        'description' => 'Number incremented when the tag is deleted.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
     ),
     'primary key' => array('tag'),
   );
@@ -1775,12 +1805,18 @@ function system_update_8007() {
         'size' => 'big',
         'not null' => FALSE,
       ));
-      db_add_field($table, 'checksum', array(
+      db_add_field($table, 'checksum_invalidations', array(
         'description' => 'The tag invalidation sum when this entry was saved.',
         'type' => 'int',
         'not null' => TRUE,
         'default' => 0,
       ));
+      db_add_field($table, 'checksum_deletions', array(
+        'description' => 'The tag deletion sum when this entry was saved.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ));
     }
   }
 }
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index e5dc768..0078cde 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -3482,7 +3482,7 @@ function system_cron() {
 
   $cache_bins = array_merge(module_invoke_all('cache_flush'), array('form', 'menu'));
   foreach ($cache_bins as $bin) {
-    cache($bin)->expire();
+    cache($bin)->deleteExpired();
   }
 
   // Cleanup the batch table and the queue for failed batches.
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php
index c7ee415..4fd859e 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php
@@ -167,7 +167,7 @@ class TermFormController extends EntityFormController {
         drupal_set_message(t('Updated term %term.', array('%term' => $term->label())));
         watchdog('taxonomy', 'Updated term %term.', array('%term' => $term->label()), WATCHDOG_NOTICE, l(t('edit'), 'taxonomy/term/' . $term->tid . '/edit'));
         // Clear the page and block caches to avoid stale data.
-        cache_invalidate(array('content' => TRUE));
+        cache_invalidate_tags(array('content' => TRUE));
         break;
     }
 
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyStorageController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyStorageController.php
index dd5b478..9f246e8 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyStorageController.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyStorageController.php
@@ -84,6 +84,6 @@ class VocabularyStorageController extends DatabaseStorageController {
   public function resetCache(array $ids = NULL) {
     drupal_static_reset('taxonomy_vocabulary_get_names');
     parent::resetCache($ids);
-    cache_invalidate(array('content' => TRUE));
+    cache_invalidate_tags(array('content' => TRUE));
   }
 }
diff --git a/core/modules/taxonomy/taxonomy.admin.inc b/core/modules/taxonomy/taxonomy.admin.inc
index ecef0b5..5e1b133 100644
--- a/core/modules/taxonomy/taxonomy.admin.inc
+++ b/core/modules/taxonomy/taxonomy.admin.inc
@@ -562,7 +562,7 @@ function taxonomy_term_confirm_delete_submit($form, &$form_state) {
   if (!isset($_GET['destination'])) {
     $form_state['redirect'] = 'admin/structure/taxonomy';
   }
-  cache_invalidate(array('content' => TRUE));
+  cache_invalidate_tags(array('content' => TRUE));
   return;
 }
 
@@ -602,7 +602,7 @@ function taxonomy_vocabulary_confirm_delete_submit($form, &$form_state) {
   drupal_set_message(t('Deleted vocabulary %name.', array('%name' => $form_state['values']['name'])));
   watchdog('taxonomy', 'Deleted vocabulary %name.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE);
   $form_state['redirect'] = 'admin/structure/taxonomy';
-  cache_invalidate(array('content' => TRUE));
+  cache_invalidate_tags(array('content' => TRUE));
   return;
 }
 
diff --git a/core/modules/user/lib/Drupal/user/ProfileFormController.php b/core/modules/user/lib/Drupal/user/ProfileFormController.php
index d2a7e81..c80be72 100644
--- a/core/modules/user/lib/Drupal/user/ProfileFormController.php
+++ b/core/modules/user/lib/Drupal/user/ProfileFormController.php
@@ -55,7 +55,7 @@ class ProfileFormController extends AccountFormController {
 
     // Clear the page cache because pages can contain usernames and/or profile
     // information:
-    cache_invalidate(array('content' => TRUE));
+    cache_invalidate_tags(array('content' => TRUE));
 
     drupal_set_message(t('The changes have been saved.'));
   }
diff --git a/core/modules/user/user.admin.inc b/core/modules/user/user.admin.inc
index f9b1c23..1feffd4 100644
--- a/core/modules/user/user.admin.inc
+++ b/core/modules/user/user.admin.inc
@@ -776,7 +776,7 @@ function user_admin_permissions_submit($form, &$form_state) {
   drupal_set_message(t('The changes have been saved.'));
 
   // Clear the cached pages and blocks.
-  cache_invalidate(array('content' => TRUE));
+  cache_invalidate_tags(array('content' => TRUE));
 }
 
 /**
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 3b69966..cfcecf2 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1969,7 +1969,7 @@ function _user_cancel($edit, $account, $method) {
   }
 
   // Clear the cache for anonymous users.
-  cache_invalidate(array('content' => TRUE));
+  cache_invalidate_tags(array('content' => TRUE));
 }
 
 /**
diff --git a/core/update.php b/core/update.php
index 52cf3d0..941f2ec 100644
--- a/core/update.php
+++ b/core/update.php
@@ -267,7 +267,7 @@ function update_info_page() {
   _drupal_flush_css_js();
   // Flush the cache of all data for the update status module.
   if (db_table_exists('cache_update')) {
-    cache('update')->flush();
+    cache('update')->deleteAll();
   }
 
   update_task_list('info');
