diff --git a/core/core.services.yml b/core/core.services.yml
index a83af34..610b486 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -158,7 +158,7 @@ services:
     tags:
       - { name: service_collector, call: addInvalidator, tag: cache_tags_invalidator }
   cache_tags.invalidator.checksum:
-    class: Drupal\Core\Cache\DatabaseCacheTagsChecksum
+    class: Drupal\Core\Cache\CacheCacheTagsChecksum
     arguments: ['@database']
     tags:
       - { name: cache_tags_invalidator}
diff --git a/core/lib/Drupal/Core/Cache/ApcuRawBackend.php b/core/lib/Drupal/Core/Cache/ApcuRawBackend.php
new file mode 100644
index 0000000..d9e0ede
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/ApcuRawBackend.php
@@ -0,0 +1,234 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\ApcuRawBackend.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * Stores cache items in the Alternative PHP Cache User Cache (APCu).
+ */
+class ApcuRawBackend implements CacheRawBackendInterface {
+
+  /**
+   * The name of the cache bin to use.
+   *
+   * @var string
+   */
+  protected $bin;
+
+  /**
+   * Prefix for all keys in the storage that belong to this site.
+   *
+   * @var string
+   */
+  protected $sitePrefix;
+
+  /**
+   * Prefix for all keys in this cache bin.
+   *
+   * Includes the site-specific prefix in $sitePrefix.
+   *
+   * @var string
+   */
+  protected $binPrefix;
+
+  /**
+   * Constructs a new ApcuBackend instance.
+   *
+   * @param string $bin
+   *   The name of the cache bin.
+   * @param string $site_prefix
+   *   The prefix to use for all keys in the storage that belong to this site.
+   * @param \Drupal\Core\Cache\CacheTagsChecksumInterface $checksum_provider
+   *   The cache tags checksum provider.
+   */
+  public function __construct($bin, $site_prefix) {
+    $this->bin = $bin;
+    $this->sitePrefix = $site_prefix;
+    $this->binPrefix = $this->sitePrefix . '::' . $this->bin . '::';
+  }
+
+  /**
+   * Prepends the APC user variable prefix for this bin to a cache item ID.
+   *
+   * @param string $cid
+   *   The cache item ID to prefix.
+   *
+   * @return string
+   *   The APCu key for the cache item ID.
+   */
+  public function getApcuKey($cid) {
+    return $this->binPrefix . $cid;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($cid) {
+    $success = FALSE;
+    $data = apc_fetch($this->getApcuKey($cid), $success);
+    if (!$success) {
+      return FALSE;
+    }
+    return $this->prepareItem($cid, $data);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMultiple(&$cids) {
+    // Translate the requested cache item IDs to APCu keys.
+    $map = array();
+    foreach ($cids as $cid) {
+      $map[$this->getApcuKey($cid)] = $cid;
+    }
+
+    $result = apc_fetch(array_keys($map));
+    $cache = array();
+    if ($result) {
+      foreach ($result as $key => $item) {
+        $item = $this->prepareItem($key, $item);
+        $cache[$map[$key]] = $item;
+      }
+    }
+    unset($result);
+
+    $cids = array_diff($cids, array_keys($cache));
+    return $cache;
+  }
+
+  /**
+   * Returns all cached items, optionally limited by a cache ID prefix.
+   *
+   * APCu is a memory cache, shared across all server processes. To prevent
+   * cache item clashes with other applications/installations, every cache item
+   * is prefixed with a unique string for this site. Therefore, functions like
+   * apc_clear_cache() cannot be used, and instead, a list of all cache items
+   * belonging to this application need to be retrieved through this method
+   * instead.
+   *
+   * @param string $prefix
+   *   (optional) A cache ID prefix to limit the result to.
+   *
+   * @return \APCIterator
+   *   An APCIterator containing matched items.
+   */
+  protected function getAll($prefix = '') {
+    return new \APCIterator('user', '/^' . preg_quote($this->getApcuKey($prefix), '/') . '/');
+  }
+
+  /**
+   * Prepares a cached item.
+   *
+   * Checks that the item is either permanent or did not expire.
+   *
+   * @param string $cid
+   *   The cache id.
+   * @param mixed $data
+   *   An item retrieved from the cache.
+   *
+   * @return \stdClass
+   *   The cache item as a Drupal cache object.
+   */
+  protected function prepareItem($cid, $data) {
+    return (object) array('data' => $data, 'cid' => $cid);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($cid, $data, $expire = CacheBackendInterface::CACHE_PERMANENT) {
+    // APC Serializes/Unserializes automatically plus
+    // we want to store native types unserialized when possible.
+    apc_store($this->getApcuKey($cid), $data);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setMultiple(array $items = array()) {
+    foreach ($items as $cid => $item) {
+      $this->set($cid, $item['data'], isset($item['expire']) ? $item['expire'] : CacheBackendInterface::CACHE_PERMANENT);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($cid) {
+    apc_delete($this->getApcuKey($cid));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteMultiple(array $cids) {
+    apc_delete(array_map(array($this, 'getApcuKey'), $cids));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteAll() {
+    apc_delete(new \APCIterator('user', '/^' . preg_quote($this->binPrefix, '/') . '/'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function garbageCollection() {
+    // APC performs garbage collection automatically.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function removeBin() {
+    apc_delete(new \APCIterator('user', '/^' . preg_quote($this->binPrefix, '/') . '/'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function counter($cid, $increment, $default = 0, $expire = CacheRawBackendInterface::PERMANENT) {
+    $success = FALSE;
+    apc_inc($this->getApcuKey($cid), $increment, $success);
+    if ($success) {
+      apc_store($this->getApcuKey($cid), $default, $expire);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function counterMultiple(array $cids, $increment, $default = 0, $expire = CacheRawBackendInterface::PERMANENT) {
+    foreach ($cids as $cid) {
+      $this->counter($cid, $increment, $default, $expire);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function touch($cid, $expire = CacheRawBackendInterface::PERMANENT) {
+    $success = FALSE;
+    $data = apc_fetch($cid, $success);
+    if (!$success) {
+      throw new \Exception("Cannot touch a non existent item.");
+    }
+    apc_store($this->getApcuKey($cid), $data, $expire);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function touchMultiple(array $cids, $expire = CacheRawBackendInterface::PERMANENT) {
+    foreach ($cids as $cid) {
+      $this->touch($cid, $expire);
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Cache/CacheCacheTagsChecksum.php b/core/lib/Drupal/Core/Cache/CacheCacheTagsChecksum.php
new file mode 100644
index 0000000..5ab06f5
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/CacheCacheTagsChecksum.php
@@ -0,0 +1,200 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\CacheCacheTagsChecksum.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * Cache tags invalidations checksum implementation that uses the database.
+ */
+class CacheCacheTagsChecksum implements CacheTagsChecksumInterface, CacheTagsInvalidatorInterface {
+
+  /**
+   * Backend storage
+   *
+   * @var CacheRawBackendInterface|CacheBackendInterface
+   */
+  protected $backend = NULL;
+
+
+  /**
+   * Contains already loaded cache invalidations from the database.
+   *
+   * @var array
+   */
+  protected $tagCache = array();
+
+  /**
+   * A list of tags that have already been invalidated in this request.
+   *
+   * Used to prevent the invalidation of the same cache tag multiple times.
+   *
+   * @var array
+   */
+  protected $invalidatedTags = array();
+
+  /**
+   * Constructs a ChainedFastCacheTagsChecksum object.
+   */
+  public function __construct($connection) {
+    // TODO:: THIS IS A QUICK WORKAROUND TO TEST THE SOLUTION.
+    $bin = 'tags';
+
+
+    $strategy = 0;
+
+    switch($strategy) {
+      case 'new-cache-api':
+        // Little mess here, ChainedFastRawBackend needs acces to a copy
+        // of the fastBackend in order to determine the correct binary name
+        // to use for the fast backend because due to lack of timestamps on
+        // CacheRawBackend the only way to handle invalidations is to variate
+        // the binary name itself.
+        $consitentBackend = new DatabaseRawBackend($connection, $bin);
+        $fastBackendInvalidations = new ApcuRawBackend('chained-fast-invalidations', 'siteprefix');
+        $fastBin = ChainedFastRawBackend::getFastBinNameFromPersistent($consitentBackend, $fastBackendInvalidations, $bin);
+        $fastBackend = new ApcuRawBackend($fastBin, 'siteprefix');
+        $this->backend = new ChainedFastRawBackend($consitentBackend, $fastBackend, $fastBackendInvalidations, $bin, $fastBin);
+        break;
+      case 'old-cache-api':
+        $this->backend = new ChainedFastBackend(
+           new DatabaseBackend($connection, new DummyTagChecksum(), $bin),
+           new ApcuBackend($bin, 'siteprefix', new DummyTagChecksum()),
+          $bin
+        );
+        break;
+    }
+  }
+
+  /**
+   * Increments a cache key.
+   *
+   * TODO:// Cache backends SHOULD have this functionality!!!
+   * Many backends: wincache, couchbase, apcu, etc..
+   * already support this natively. The problem is that
+   * these backends expect the raw value to be stored as the cache
+   * data while Drupal is storing this data inside a cache
+   * object.
+   *
+   * @param string $cid
+   * @param int $increment
+   * @param int $default
+   */
+  protected function counter($cid, $increment, $default = 1) {
+    if ($this->backend instanceof CacheBackendInterface) {
+      $this->counter_old_cache_api($cid, $increment, $default);
+    }
+    else if ($this->backend instanceof CacheRawBackendInterface) {
+      $this->backend->counter($cid, $increment, $default);
+    }
+  }
+
+  /**
+   * The old cache API does not support native counters
+   * so we need to do this manually.
+   *
+   * @param string $cid
+   * @param int $increment
+   * @param mixed $default
+   */
+  protected function counter_old_cache_api($cid, $increment, $default = 1) {
+    $data = NULL;
+    if ($cache = $this->backend->get($cid)) {
+      $data = $cache->data + $increment;
+    }
+    else {
+      $data = $default;
+    }
+    $this->backend->set($cid, $data);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function invalidateTags(array $tags) {
+    foreach ($tags as $tag) {
+      // Only invalidate tags once per request unless they are written again.
+      if (isset($this->invalidatedTags[$tag])) {
+        unset($tags[$tag]);
+        continue;
+      }
+      $this->invalidatedTags[$tag] = TRUE;
+      unset($this->tagCache[$tag]);
+      $this->counter($tag, 1);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCurrentChecksum(array $tags) {
+    // Remove tags that were already invalidated during this request from the
+    // static caches so that another invalidation can occur later in the same
+    // request. Without that, written cache items would not be invalidated
+    // correctly.
+    foreach ($tags as $tag) {
+      unset($this->invalidatedTags[$tag]);
+    }
+    return $this->calculateChecksum($tags);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isValid($checksum, array $tags) {
+    return $checksum == $this->calculateChecksum($tags);
+  }
+
+  /**
+   * Calculates the current checksum for a given set of tags.
+   *
+   * @param array $tags
+   *   The array of tags to calculate the checksum for.
+   *
+   * @return int
+   *   The calculated checksum.
+   */
+  protected function calculateChecksum(array $tags) {
+    $checksum = 0;
+
+    $query_tags = array_diff($tags, array_keys($this->tagCache));
+    if ($query_tags) {
+      $db_tags = array();
+
+      foreach($this->backend->getMultiple($query_tags) as $cid => $cache) {
+        $db_tags[$cid] = $cache->data;
+      }
+
+      // If we were not retrieve a tag (because it has never been invalidated) make
+      // sure that we initialize it, othewise the storage backend will keep looking
+      // for it once again and again in the persistent backend, and that is something
+      // we want to avoid!
+      $missing_tags = array_diff($query_tags, array_keys($db_tags));
+      foreach ($missing_tags as $tag) {
+        $this->counter($tag, 1);
+      }
+
+      $this->tagCache += $db_tags;
+
+      // Fill static cache with empty objects for tags not found in the database.
+      $this->tagCache += array_fill_keys($missing_tags, 0);
+    }
+
+    foreach ($tags as $tag) {
+      $checksum += $this->tagCache[$tag];
+    }
+
+    return $checksum;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function reset() {
+    $this->tagCache = array();
+    $this->invalidatedTags = array();
+  }
+}
diff --git a/core/lib/Drupal/Core/Cache/CacheRawBackendInterface.php b/core/lib/Drupal/Core/Cache/CacheRawBackendInterface.php
new file mode 100644
index 0000000..dea2a8f
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/CacheRawBackendInterface.php
@@ -0,0 +1,205 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\CacheRawBackendInterface.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * Defines an interface for cache implementations.
+ *
+ * A simple cache backend implementation, that exposes
+ * the underlying storage in the most simple way possible.
+ *
+ * @ingroup cache
+ */
+interface CacheRawBackendInterface {
+
+  /**
+   * Indicates that the item should never be removed unless explicitly deleted.
+   */
+  const CACHE_PERMANENT = -1;
+
+  /**
+   * Returns data from the persistent cache.
+   *
+   * @param string $cid
+   *   The cache ID of the data to retrieve.
+   *
+   * @return object|false
+   *   The cache item or FALSE on failure.
+   *
+   * @see \Drupal\Core\Cache\CacheRawBackendInterface::getMultiple()
+   */
+  public function get($cid);
+
+  /**
+   * Returns data from the persistent cache when given an array of cache IDs.
+   *
+   * @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.
+   *
+   * @return array
+   *   An array of cache item objects indexed by cache ID.
+   *
+   * @see \Drupal\Core\Cache\CacheRawBackendInterface::get()
+   */
+  public function getMultiple(&$cids);
+
+  /**
+   * Stores data in the persistent cache.
+   *
+   * Core cache implementations set the created time on cache item with
+   * microtime(TRUE) rather than REQUEST_TIME_FLOAT, because the created time
+   * of cache items should match when they are created, not when the request
+   * started. Apart from being more accurate, this increases the chance an
+   * item will legitimately be considered valid.
+   *
+   * @param string $cid
+   *   The cache ID of the data to store.
+   * @param mixed $data
+   *   The data to store in the cache.
+   *   Some storage engines only allow objects up to a maximum of 1MB in size to
+   *   be stored by default. When caching large arrays or similar, take care to
+   *   ensure $data does not exceed this size.
+   * @param int $expire
+   *   One of the following values:
+   *   - CacheBackendInterface::CACHE_PERMANENT: Indicates that the item should
+   *     not be removed unless it is deleted explicitly.
+   *   - A Unix timestamp: Indicates that the item will be considered invalid
+   *     after this time, i.e. it will not be returned by get() unless
+   *     $allow_invalid has been set to TRUE. When the item has expired, it may
+   *     be permanently deleted by the garbage collector at any time.
+   *
+   * @see \Drupal\Core\Cache\CacheRawBackendInterface::get()
+   * @see \Drupal\Core\Cache\CacheRawBackendInterface::getMultiple()
+   */
+  public function set($cid, $data, $expire = CacheRawBackendInterface::PERMANENT);
+
+  /**
+   * Store multiple items in the persistent cache.
+   *
+   * @param array $items
+   *   An array of cache items, keyed by cid. In the form:
+   *   @code
+   *   $items = array(
+   *     $cid => array(
+   *       // Required.
+   *       'data' => $data,
+   *       // Optional, defaults to CacheRawBackendInterface::CACHE_PERMANENT.
+   *       'expire' => CacheRawBackendInterface::CACHE_PERMANENT,
+   *     ),
+   *   );
+   *   @endcode
+   */
+  public function setMultiple(array $items);
+
+  /**
+   * Deletes an item from the cache.
+   *
+   * If the cache item is being deleted because it is no longer "fresh", you may
+   * consider using invalidate() instead. This allows callers to retrieve the
+   * invalid item by calling get() with $allow_invalid set to TRUE. In some cases
+   * an invalid item may be acceptable rather than having to rebuild the cache.
+   *
+   * @param string $cid
+   *   The cache ID to delete.
+   *
+   * @see \Drupal\Core\Cache\CacheRawBackendInterface::deleteMultiple()
+   * @see \Drupal\Core\Cache\CacheRawBackendInterface::deleteAll()
+   */
+  public function delete($cid);
+
+  /**
+   * Deletes multiple items from the cache.
+   *
+   * If the cache items are being deleted because they are no longer "fresh",
+   * you may consider using invalidateMultiple() instead. This allows callers to
+   * retrieve the invalid items by calling get() with $allow_invalid set to TRUE.
+   * In some cases an invalid item may be acceptable rather than having to
+   * rebuild the cache.
+   *
+   * @param array $cids
+   *   An array of cache IDs to delete.
+   *
+   * @see \Drupal\Core\Cache\CacheRawBackendInterface::delete()
+   * @see \Drupal\Core\Cache\CacheRawBackendInterface::deleteAll()
+   */
+  public function deleteMultiple(array $cids);
+
+  /**
+   * Deletes all cache items in a bin.
+   *
+   * @see \Drupal\Core\Cache\CacheRawBackendInterface::delete()
+   * @see \Drupal\Core\Cache\CacheRawBackendInterface::deleteMultiple()
+   */
+  public function deleteAll();
+
+  /**
+   * Add an increment (can be negative) to the stored cache data. Only
+   * works for stored numeric data.
+   * 
+   * @param string $cide
+   *   The cache ID or array of ID's.
+   * @param int $increment 
+   *   The amount to increment or decrement.
+   * @param int $default 
+   *   Default value.
+   * @param int $expire
+   *   Expiration.
+   */
+  public function counter($cid, $increment, $default = 0, $expire = CacheRawBackendInterface::PERMANENT);
+
+  /**
+   * Add an increment (can be negative) to the stored cache data. Only
+   * works for stored numeric data.
+   * 
+   * @param string[] $cide
+   *   The cache ID or array of ID's.
+   * @param int $increment 
+   *   The amount to increment or decrement.
+   * @param int $default 
+   *   Default value.
+   * @param int $expire
+   *   Expiration.
+   */
+  public function counterMultiple(array $cids, $increment, $default = 0, $expire = CacheRawBackendInterface::PERMANENT);
+
+  /**
+   * Update the expiration of an item without
+   * having to set the item again on the cache.
+   * 
+   * @param string|string[] $cid 
+   *   The cache ID or array of ID's.
+   * @param int $expire 
+   *   Expiration.
+   */
+  public function touch($cid, $expire = CacheRawBackendInterface::PERMANENT);
+
+  /**
+   * Update the expiration of an item without
+   * having to set the item again on the cache.
+   * 
+   * @param string[] $cid 
+   *   The cache ID or array of ID's.
+   * @param int $expire 
+   *   Expiration.
+   */
+  public function touchMultiple(array $cids, $expire = CacheRawBackendInterface::PERMANENT);
+
+  /**
+   * Performs garbage collection on a cache bin.
+   *
+   * The backend may choose to delete expired or invalidated items.
+   */
+  public function garbageCollection();
+
+  /**
+   * Remove a cache bin.
+   */
+  public function removeBin();
+}
diff --git a/core/lib/Drupal/Core/Cache/ChainedFastBackend.php b/core/lib/Drupal/Core/Cache/ChainedFastBackend.php
index 051f38d..612769a 100644
--- a/core/lib/Drupal/Core/Cache/ChainedFastBackend.php
+++ b/core/lib/Drupal/Core/Cache/ChainedFastBackend.php
@@ -58,6 +58,13 @@ class ChainedFastBackend implements CacheBackendInterface, CacheTagsInvalidatorI
   const LAST_WRITE_TIMESTAMP_PREFIX = 'last_write_timestamp_';
 
   /**
+   * Identifier for the current webhead/process
+   *
+   * @var string
+   */
+  protected $headId;
+
+  /**
    * @var string
    */
   protected $bin;
@@ -77,6 +84,13 @@ class ChainedFastBackend implements CacheBackendInterface, CacheTagsInvalidatorI
   protected $fastBackend;
 
   /**
+   * Last time this binary has been marked as outdated.
+   *
+   * @var int
+   */
+  protected $last_invalidation = NULL;
+
+  /**
    * The time at which the last write to this cache bin happened.
    *
    * @var float
@@ -84,6 +98,31 @@ class ChainedFastBackend implements CacheBackendInterface, CacheTagsInvalidatorI
   protected $lastWriteTimestamp;
 
   /**
+   * Wether or not invalidations should
+   * be persisted at shutdown.
+   *
+   * @var bool
+   */
+  protected $persistOnShutdown;
+
+  /**
+   * Generate or retrieve a key that identifies
+   * the instance of the fastBackend.
+   *
+   * @return string
+   */
+  protected function GetHeadId() {
+    if ($cache = $this->fastBackend->get('headid')) {
+      return $cache->data;
+    }
+
+    // Generate a unique ID for this fast backend.
+    $id = uniqid(microtime(TRUE), TRUE);
+    $this->fastBackend->set('headid', $id);
+    return $id;
+  }
+
+  /**
    * Constructs a ChainedFastBackend object.
    *
    * @param \Drupal\Core\Cache\CacheBackendInterface $consistent_backend
@@ -96,7 +135,9 @@ class ChainedFastBackend implements CacheBackendInterface, CacheTagsInvalidatorI
   public function __construct(CacheBackendInterface $consistent_backend, CacheBackendInterface $fast_backend, $bin) {
     $this->consistentBackend = $consistent_backend;
     $this->fastBackend = $fast_backend;
+    $this->headId = $this->GetHeadId();
     $this->bin = 'cache_' . $bin;
+    $this->persistOnShutdown = TRUE; //\Drupal\Core\Site\Settings::get('cache_persist_defer', FALSE);
     $this->lastWriteTimestamp = NULL;
   }
 
@@ -167,11 +208,18 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) {
     // backend, retrieve them from the consistent backend and store them in the
     // fast one.
     if ($cids) {
+      $missing = array();
       foreach ($this->consistentBackend->getMultiple($cids, $allow_invalid) as $item) {
         $cache[$item->cid] = $item;
-        // Don't write the cache tags to the fast backend as any cache tag
-        // invalidation results in an invalidation of the whole fast backend.
-        $this->fastBackend->set($item->cid, $item->data, $item->expire);
+        $missing[$item->cid] = (array) $item;
+      }
+      if (!empty($missing)) {
+        $this->fastBackend->setMultiple($missing);
+      }
+      // This means that the persistent backend has no lastWriteTimestamp
+      // but we were able to retrieve data from it....
+      if (!$last_write_timestamp && !empty($missing)) {
+        $this->markAsOutdated();
       }
     }
 
@@ -183,10 +231,8 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) {
    */
   public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array()) {
     $this->consistentBackend->set($cid, $data, $expire, $tags);
+    $this->fastBackend->set($cid, $data, $expire, $tags);
     $this->markAsOutdated();
-    // Don't write the cache tags to the fast backend as any cache tag
-    // invalidation results in an invalidation of the whole fast backend.
-    $this->fastBackend->set($cid, $data, $expire);
   }
 
   /**
@@ -194,13 +240,8 @@ public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array
    */
   public function setMultiple(array $items) {
     $this->consistentBackend->setMultiple($items);
-    $this->markAsOutdated();
-    // Don't write the cache tags to the fast backend as any cache tag
-    // invalidation results in an invalidation of the whole fast backend.
-    foreach ($items as &$item) {
-      unset($item['tags']);
-    }
     $this->fastBackend->setMultiple($items);
+    $this->markAsOutdated();
   }
 
   /**
@@ -208,6 +249,7 @@ public function setMultiple(array $items) {
    */
   public function delete($cid) {
     $this->consistentBackend->deleteMultiple(array($cid));
+    $this->fastBackend->deleteMultiple(array($cid));
     $this->markAsOutdated();
   }
 
@@ -216,6 +258,7 @@ public function delete($cid) {
    */
   public function deleteMultiple(array $cids) {
     $this->consistentBackend->deleteMultiple($cids);
+    $this->fastBackend->deleteMultiple($cids);
     $this->markAsOutdated();
   }
 
@@ -224,6 +267,7 @@ public function deleteMultiple(array $cids) {
    */
   public function deleteAll() {
     $this->consistentBackend->deleteAll();
+    $this->fastBackend->deleteAll();
     $this->markAsOutdated();
   }
 
@@ -239,6 +283,7 @@ public function invalidate($cid) {
    */
   public function invalidateMultiple(array $cids) {
     $this->consistentBackend->invalidateMultiple($cids);
+    $this->fastBackend->invalidateMultiple($cids);
     $this->markAsOutdated();
   }
 
@@ -249,6 +294,9 @@ public function invalidateTags(array $tags) {
     if ($this->consistentBackend instanceof CacheTagsInvalidatorInterface) {
       $this->consistentBackend->invalidateTags($tags);
     }
+    if ($this->fastBackend instanceof CacheTagsInvalidatorInterface) {
+      $this->fastBackend->invalidateTags($tags);
+    }
     $this->markAsOutdated();
   }
 
@@ -257,6 +305,7 @@ public function invalidateTags(array $tags) {
    */
   public function invalidateAll() {
     $this->consistentBackend->invalidateAll();
+    $this->fastBackend->invalidateAll();
     $this->markAsOutdated();
   }
 
@@ -289,7 +338,17 @@ public function reset() {
   protected function getLastWriteTimestamp() {
     if ($this->lastWriteTimestamp === NULL) {
       $cache = $this->consistentBackend->get(self::LAST_WRITE_TIMESTAMP_PREFIX . $this->bin);
-      $this->lastWriteTimestamp = $cache ? $cache->data : 0;
+      if ($cache && $cache->data['head'] != $this->headId) {
+        $this->lastWriteTimestamp = $cache->data['timestamp'];
+      }
+      else {
+        // If we are here this means that either the binary has never been invalidated,
+        // or that the last invalidation was actually made by ourselves so we retain
+        // the previous invalidation timestamp that we had.
+        $current = $cache && $cache->data['head'] == $this->headId ? $cache->data['timestamp'] : 0;
+        $cache = $this->fastBackend->get(self::LAST_WRITE_TIMESTAMP_PREFIX . $this->bin);
+        $this->lastWriteTimestamp = $cache && !empty($cache->data) ? $cache->data : $current;
+      }
     }
     return $this->lastWriteTimestamp;
   }
@@ -307,8 +366,24 @@ protected function markAsOutdated() {
     // costs one additional roundtrip to the persistent cache.
     $now = round(microtime(TRUE) + .001, 3);
     if ($now > $this->getLastWriteTimestamp()) {
-      $this->lastWriteTimestamp = $now;
-      $this->consistentBackend->set(self::LAST_WRITE_TIMESTAMP_PREFIX . $this->bin, $this->lastWriteTimestamp);
+      if ($this->persistOnShutdown) {
+        // Invalidate when the object is destroyed.
+        $this->last_invalidation = $now;
+      }
+      else {
+        $this->fastBackend->set(self::LAST_WRITE_TIMESTAMP_PREFIX . $this->bin, $this->lastWriteTimestamp);
+        $this->consistentBackend->set(self::LAST_WRITE_TIMESTAMP_PREFIX . $this->bin, array('head' => $this->headId, 'timestamp' => $now));
+      }
+    }
+  }
+
+  /**
+   * Shutdown functions.
+   */
+  function __destruct() {
+    if ($this->persistOnShutdown && !empty($this->last_invalidation)) {
+      $this->fastBackend->set(self::LAST_WRITE_TIMESTAMP_PREFIX . $this->bin, $this->lastWriteTimestamp);
+      $this->consistentBackend->set(self::LAST_WRITE_TIMESTAMP_PREFIX . $this->bin, array('head' => $this->headId, 'timestamp' => $this->last_invalidation));
     }
   }
 
diff --git a/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php b/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php
index bba9d94..96c3aca 100644
--- a/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php
+++ b/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php
@@ -57,14 +57,8 @@ public function __construct(Settings $settings = NULL, $consistent_service_name
       $fast_service_name = 'cache.backend.apcu';
     }
 
+    $this->fastServiceName = $fast_service_name;
     $this->consistentServiceName = $consistent_service_name;
-
-    // Do not use the fast chained backend during installation. In those cases,
-    // we expect many cache invalidations and writes, the fast chained cache
-    // backend performs badly in such a scenario.
-    if (!drupal_installation_attempted()) {
-      $this->fastServiceName = $fast_service_name;
-    }
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Cache/ChainedFastRawBackend.php b/core/lib/Drupal/Core/Cache/ChainedFastRawBackend.php
new file mode 100644
index 0000000..0e36189
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/ChainedFastRawBackend.php
@@ -0,0 +1,365 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\ChainedFastRawBackend.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * Defines a backend with a fast and a consistent backend chain.
+ *
+ * In order to mitigate a network roundtrip for each cache get operation, this
+ * cache allows a fast backend to be put in front of a slow(er) backend.
+ * Typically the fast backend will be something like APCu, and be bound to a
+ * single web node, and will not require a network round trip to fetch a cache
+ * item. The fast backend will also typically be inconsistent (will only see
+ * changes from one web node). The slower backend will be something like Mysql,
+ * Memcached or Redis, and will be used by all web nodes, thus making it
+ * consistent, but also require a network round trip for each cache get.
+ *
+ * In addition to being useful for sites running on multiple web nodes, this
+ * backend can also be useful for sites running on a single web node where the
+ * fast backend (e.g., APCu) isn't shareable between the web and CLI processes.
+ * Single-node configurations that don't have that limitation can just use the
+ * fast cache backend directly.
+ *
+ * We always use the fast backend when reading (get()) entries from cache, but
+ * check whether they were created before the last write (set()) to this
+ * (chained) cache backend. Those cache entries that were created before the
+ * last write are discarded, but we use their cache IDs to then read them from
+ * the consistent (slower) cache backend instead; at the same time we update
+ * the fast cache backend so that the next read will hit the faster backend
+ * again. Hence we can guarantee that the cache entries we return are all
+ * up-to-date, and maximally exploit the faster cache backend. This cache
+ * backend uses and maintains a "last write timestamp" to determine which cache
+ * entries should be discarded.
+ *
+ * Because this backend will mark all the cache entries in a bin as out-dated
+ * for each write to a bin, it is best suited to bins with fewer changes.
+ *
+ * Note that this is designed specifically for combining a fast inconsistent
+ * cache backend with a slower consistent cache back-end. To still function
+ * correctly, it needs to do a consistency check (see the "last write timestamp"
+ * logic). This contrasts with \Drupal\Core\Cache\BackendChain, which assumes
+ * both chained cache backends are consistent, thus a consistency check being
+ * pointless.
+ *
+ * @see \Drupal\Core\Cache\BackendChain
+ *
+ * @ingroup cache
+ */
+class ChainedFastRawBackend implements CacheRawBackendInterface {
+
+  /**
+   * Cache key prefix for the bin-specific entry to track the last write.
+   */
+  const WRITE_COUNTER_PREFIX = 'write_counter_';
+
+  /**
+   * @var string
+   */
+  protected $bin;
+
+  /**
+   * Name of the bin assigned to the fastBackend.
+   * 
+   * @var string
+   */
+  protected $fastBin;
+
+  /**
+   * The consistent cache backend.
+   *
+   * @var \Drupal\Core\Cache\CacheRawBackendInterface
+   */
+  protected $consistentBackend;
+
+  /**
+   * The fast cache backend.
+   *
+   * @var \Drupal\Core\Cache\CacheRawBackendInterface
+   */
+  protected $fastBackend;
+
+  /**
+   * The fast cache backend used to store invalidations. It must
+   * have an inmutable binary name.
+   *
+   * @var \Drupal\Core\Cache\CacheRawBackendInterface
+   */
+  protected $fastBackendInvalidations;
+
+  /**
+   * Last time this binary has been marked as outdated.
+   *
+   * @var bool
+   */
+  protected $invalidate_shared = NULL;
+
+  /**
+   * The time at which the last write to this cache bin happened.
+   *
+   * @var int
+   */
+  protected $writeCounter;
+
+  /**
+   * Wether or not invalidations should
+   * be persisted at shutdown.
+   *
+   * @var bool
+   */
+  protected $persistOnShutdown;
+
+  /**
+   * Constructs a ChainedFastBackend object.
+   *
+   * @param \Drupal\Core\Cache\CacheRawBackendInterface $consistent_backend
+   *   The consistent cache backend.
+   * @param \Drupal\Core\Cache\CacheRawBackendInterface $fast_backend
+   *   The fast cache backend.
+   * @param \Drupal\Core\Cache\CacheRawBackendInterface $fast_backend_invalidations
+   *   The fast cache backend used to store invalidations. Must always have the same binary.
+   * @param string $bin
+   *   The cache bin for which the object is created.
+   */
+  public function __construct(CacheRawBackendInterface $consistent_backend, CacheRawBackendInterface $fast_backend, CacheRawBackendInterface $fast_backend_invalidations, $bin, $fast_bin) {
+    $this->consistentBackend = $consistent_backend;
+    $this->fastBackend = $fast_backend;
+    $this->fastBackendInvalidations = $fast_backend_invalidations;
+    $this->bin = $bin;
+    $this->fastBin = $fast_bin;
+    $this->persistOnShutdown = TRUE; //\Drupal\Core\Site\Settings::get('cache_persist_defer', FALSE);
+    $this->writeCounter = NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($cid) {
+    $cids = array($cid);
+    $cache = $this->getMultiple($cids);
+    return reset($cache);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMultiple(&$cids) {
+
+    $this->getWriteCounter();
+
+    $cids_copy = $cids;
+    $cache = array();
+
+    try {
+      $items = $this->fastBackend->getMultiple($cids);
+    }
+    catch (\Exception $e) {
+      $cids = $cids_copy;
+      $items = array();
+    }
+
+    // Even if items were successfully fetched from the fast backend, they
+    // are potentially invalid if older than the last time the bin was
+    // written to in the consistent backend, so only keep ones that aren't.
+    foreach ($items as $key => $data) {
+      $cache[$key] = $data;
+    }
+
+    // If there were any cache entries that were not available in the fast
+    // backend, retrieve them from the consistent backend and store them in the
+    // fast one.
+    if ($cids) {
+      $missing = array();
+      foreach ($this->consistentBackend->getMultiple($cids) as $item) {
+        $cache[$item->cid] = $item;
+        $missing[$item->cid] = (array) $item;
+      }
+      if (!empty($missing)) {
+        $this->fastBackend->setMultiple($missing);
+      }
+    }
+
+    return $cache;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($cid, $data, $expire = Cache::PERMANENT) {
+    $this->consistentBackend->set($cid, $data, $expire);
+    $this->fastBackend->set($cid, $data, $expire);
+    $this->markAsOutdated();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setMultiple(array $items) {
+    $this->consistentBackend->setMultiple($items);
+    $this->fastBackend->setMultiple($items);
+    $this->markAsOutdated();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($cid) {
+    $this->consistentBackend->deleteMultiple(array($cid));
+    $this->fastBackend->deleteMultiple(array($cid));
+    $this->markAsOutdated();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteMultiple(array $cids) {
+    $this->consistentBackend->deleteMultiple($cids);
+    $this->fastBackend->deleteMultiple($cids);
+    $this->markAsOutdated();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteAll() {
+    $this->consistentBackend->deleteAll();
+    $this->fastBackend->deleteAll();
+    $this->markAsOutdated();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function garbageCollection() {
+    $this->consistentBackend->garbageCollection();
+    $this->fastBackend->garbageCollection();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function removeBin() {
+    $this->consistentBackend->removeBin();
+    $this->fastBackend->removeBin();
+  }
+
+  /**
+   * @todo Document in https://www.drupal.org/node/2311945.
+   */
+  public function reset() {
+    $this->lastWriteTimestamp = NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function counter($cid, $increment, $default = 0, $expire = CacheRawBackendInterface::CACHE_PERMANENT) {
+    $this->consistentBackend->counter($cid, $increment, $default, $expire);
+    $this->fastBackend->counter($cid, $increment, $default, $expire);
+    $this->markAsOutdated();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function counterMultiple(array $cids, $increment, $default = 0, $expire = CacheRawBackendInterface::CACHE_PERMANENT) {
+    $this->consistentBackend->counterMultiple($cids, $increment, $default, $expire);
+    $this->fastBackend->counterMultiple($cids, $increment, $default, $expire);
+    $this->markAsOutdated();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function touch($cid, $expire = CacheRawBackendInterface::CACHE_PERMANENT) {
+    $this->consistentBackend->touch($cid, $expire);
+    $this->fastBackend->touch($cid, $expire);
+    $this->markAsOutdated();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function touchMultiple(array $cids, $expire = CacheRawBackendInterface::CACHE_PERMANENT) {
+    $this->consistentBackend->touchMultiple($cids, $expire);
+    $this->fastBackend->touchMultiple($cids, $expire);
+    $this->markAsOutdated();
+  }
+
+  /**
+   * Gets the last write timestamp.
+   */
+  protected function getWriteCounter() {
+    if ($this->writeCounter === NULL) {
+      if ($cache = $this->consistentBackend->get(self::WRITE_COUNTER_PREFIX)) {
+        $this->writeCounter = $cache->data;
+      }
+      else {
+        $this->writeCounter = 0;
+      }
+    }
+    return $this->writeCounter;
+  }
+
+  /**
+   * Marks the fast cache bin as outdated because of a write.
+   */
+  protected function markAsOutdated() {
+    if ($this->persistOnShutdown) {
+      // Invalidate when the object is destroyed.
+      $this->invalidate_shared = TRUE;
+    }
+    else {
+      $this->doMarkAsOutdated();
+    }
+  }
+
+  /**
+   * Shutdown functions.
+   */
+  function __destruct() {
+    if ($this->persistOnShutdown && $this->invalidate_shared == TRUE) {
+      $this->doMarkAsOutdated();
+    }
+  }
+
+  /**
+   * The the real invalidation job.
+   */
+  protected function doMarkAsOutdated() {
+    $writeCounter = $this->getWriteCounter();
+    // Keep a copy of the expected writeCounter and current binary name
+    // so that we do not invalidate ourselves!
+    $this->fastBackendInvalidations->set(self::WRITE_COUNTER_PREFIX . $this->bin, array('bin' => $this->fastBin, 'write_count' => $writeCounter + 1));
+    $this->consistentBackend->counter(self::WRITE_COUNTER_PREFIX, 1, 0);
+  }
+
+  /**
+   * Retrieve the binary name to use for fastStorage.
+   *
+   * @param CacheRawBackendInterface $persistentBackend
+   *   The persistent backend.
+   * @param CacheRawBackendInterface $fastBackend
+   *   The persistent backend.
+   * @param string $bin
+   *   The binary name.
+   */
+  public static function getFastBinNameFromPersistent(CacheRawBackendInterface $persistentBackend, CacheRawBackendInterface $fastBackend, $bin) {
+    $shared = 0;
+    if ($cache = $persistentBackend->get(ChainedFastRawBackend::WRITE_COUNTER_PREFIX)) {
+      $shared = $cache->data;
+    }
+    if ($cache = $fastBackend->get(ChainedFastRawBackend::WRITE_COUNTER_PREFIX . $bin)) {
+      $local = $cache->data;
+      if ($local['write_count'] == $shared) {
+        return $local['bin'];
+      }
+    }
+    return $bin . ':' . $shared;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Cache/DatabaseRawBackend.php b/core/lib/Drupal/Core/Cache/DatabaseRawBackend.php
new file mode 100644
index 0000000..1297d1b
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/DatabaseRawBackend.php
@@ -0,0 +1,512 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\DatabaseRawBackend.
+ */
+
+namespace Drupal\Core\Cache;
+
+use Drupal\Component\Utility\Crypt;
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Database\SchemaObjectExistsException;
+
+/**
+ * Defines a default cache implementation.
+ *
+ * This is Drupal's default cache implementation. It uses the database to store
+ * cached data. Each cache bin corresponds to a database table by the same name.
+ *
+ * @ingroup cache
+ */
+class DatabaseRawBackend implements CacheRawBackendInterface {
+
+  /**
+   * @var string
+   */
+  protected $bin;
+
+
+  /**
+   * The database connection.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
+  protected $connection;
+
+  /**
+   * Constructs a DatabaseBackend object.
+   *
+   * @param \Drupal\Core\Database\Connection $connection
+   *   The database connection.
+   * @param string $bin
+   *   The cache bin for which the object is created.
+   */
+  public function __construct(Connection $connection, $bin) {
+    // All cache tables should be prefixed with 'cache_'.
+    $bin = 'rawcache_' . $bin;
+
+    $this->bin = $bin;
+    $this->connection = $connection;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($cid) {
+    $cids = array($cid);
+    $cache = $this->getMultiple($cids);
+    return reset($cache);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMultiple(&$cids) {
+    $cid_mapping = array();
+    foreach ($cids as $cid) {
+      $cid_mapping[$this->normalizeCid($cid)] = $cid;
+    }
+    // When serving cached pages, the overhead of using ::select() was found
+    // to add around 30% overhead to the request. Since $this->bin is a
+    // variable, this means the call to ::query() here uses a concatenated
+    // string. This is highly discouraged under any other circumstances, and
+    // 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 = array();
+    try {
+      $result = $this->connection->query('SELECT cid, data_serialized, data_string, data_int, data_float, expire, storage FROM {' . $this->connection->escapeTable($this->bin) . '} WHERE cid IN ( :cids[] ) ORDER BY cid', array(':cids[]' => array_keys($cid_mapping)));
+    }
+    catch (\Exception $e) {
+      // Nothing to do.
+    }
+    $cache = array();
+    foreach ($result as $item) {
+      // Map the cache ID back to the original.
+      $item->cid = $cid_mapping[$item->cid];
+      $item = $this->prepareItem($item);
+      if ($item) {
+        $cache[$item->cid] = $item;
+      }
+    }
+    $cids = array_diff($cids, array_keys($cache));
+    return $cache;
+  }
+
+  /**
+   * Prepares a cached item.
+   *
+   * Checks that items are either permanent or did not expire, and unserializes
+   * data as appropriate.
+   *
+   * @param object $cache
+   *   An item loaded from cache_get() or cache_get_multiple().
+   *
+   * @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) {
+
+    // Check expire time.
+    $cache->valid = $cache->expire == Cache::PERMANENT || $cache->expire >= REQUEST_TIME;
+
+    if (!$cache->valid) {
+      return FALSE;
+    }
+
+    // Retrieve the proper data...
+    switch($cache->storage) {
+      case 0:
+        if ($cache->data_serialized === NULL) { return FALSE; }
+        $cache->data = unserialize($cache->data_serialized);
+        break;
+      case 1:
+        if ($cache->data_string === NULL) { return FALSE; }
+        $cache->data = $cache->data_string;
+        break;
+      case 2:
+        if ($cache->data_int === NULL) { return FALSE; }
+        $cache->data = (int) $cache->data_int;
+        break;
+      case 3:
+        if ($cache->data_float === NULL) { return FALSE; }
+        $cache->data = (float) $cache->data_float;
+        break;
+    }
+
+    // Remove storage
+    unset($cache->data_serialized);
+    unset($cache->data_string);
+    unset($cache->data_int);
+    unset($cache->data_float);
+
+    return $cache;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($cid, $data, $expire = CacheRawBackendInterface::CACHE_PERMANENT) {
+    $this->setMultiple([
+      $cid => [
+        'data' => $data,
+        'expire' => $expire,
+      ],
+    ]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setMultiple(array $items) {
+    $try_again = FALSE;
+    try {
+      // The bin might not yet exist.
+      $this->doSetMultiple($items);
+    }
+    catch (\Exception $e) {
+      // If there was an exception, try to create the bins.
+      if (!$try_again = $this->ensureBinExists()) {
+        // If the exception happened for other reason than the missing bin
+        // table, propagate the exception.
+        throw $e;
+      }
+    }
+    // Now that the bin has been created, try again if necessary.
+    if ($try_again) {
+      $this->doSetMultiple($items);
+    }
+  }
+
+  /**
+   * Prepare data to be stored in the database.
+   *
+   * @param string $cid
+   * @param mixed $data
+   * @return array
+   */
+  protected function prepareStorage($cid, $data, $expire) {
+    $fields = array(
+        'cid' => $this->normalizeCid($cid),
+        'expire' => $expire,
+      );
+
+    $fields['data_serialized'] = NULL;
+    $fields['data_string'] = NULL;
+    $fields['data_int'] = NULL;
+    $fields['data_float'] = NULL;
+
+    // We want to store numeric and string in a native way when this is possible.
+
+    if (is_bool($data) || is_int($data)) {
+      $fields['data_int'] = $data;
+      $fields['storage'] = 2;
+    }
+    elseif (is_float($data)) {
+      $fields['data_float'] = $data;
+      $fields['storage'] = 3;
+    }
+    elseif (is_string($data)) {
+      $fields['data_string'] = $data;
+      $fields['storage'] = 1;
+    }
+    else {
+      $fields['data_serialized'] = serialize($data);
+      $fields['storage'] = 0;
+    }
+
+    return $fields;
+  }
+
+  /**
+   * Stores multiple items in the persistent cache.
+   *
+   * @param array $items
+   *   An array of cache items, keyed by cid.
+   *
+   * @see \Drupal\Core\Cache\CacheBackendInterface::setMultiple()
+   */
+  protected function doSetMultiple(array $items) {
+    $values = array();
+
+    foreach ($items as $cid => $item) {
+      $item += array(
+        'expire' => CacheBackendInterface::CACHE_PERMANENT,
+      );
+
+      $values[] = $this->prepareStorage($cid, $item['data'], $item['expire']);
+    }
+
+    // Use an upsert query which is atomic and optimized for multiple-row
+    // merges.
+    $query = $this->connection
+      ->upsert($this->bin)
+      ->key('cid')
+      ->fields(array('cid', 'expire', 'data_serialized', 'data_string', 'data_int', 'data_float', 'storage'));
+    foreach ($values as $fields) {
+      // Only pass the values since the order of $fields matches the order of
+      // the insert fields. This is a performance optimization to avoid
+      // unnecessary loops within the method.
+      $query->values(array_values($fields));
+    }
+
+    $query->execute();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($cid) {
+    $this->deleteMultiple(array($cid));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteMultiple(array $cids) {
+    $cids = array_values(array_map(array($this, 'normalizeCid'), $cids));
+    try {
+      // Delete in chunks when a large array is passed.
+      foreach (array_chunk($cids, 1000) as $cids_chunk) {
+        $this->connection->delete($this->bin)
+          ->condition('cid', $cids_chunk, 'IN')
+          ->execute();
+      }
+    }
+    catch (\Exception $e) {
+      // Create the cache table, which will be empty. This fixes cases during
+      // core install where a cache table is cleared before it is set
+      // with {cache_render} and {cache_data}.
+      if (!$this->ensureBinExists()) {
+        $this->catchException($e);
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteAll() {
+    try {
+      $this->connection->truncate($this->bin)->execute();
+    }
+    catch (\Exception $e) {
+      // Create the cache table, which will be empty. This fixes cases during
+      // core install where a cache table is cleared before it is set
+      // with {cache_render} and {cache_data}.
+      if (!$this->ensureBinExists()) {
+        $this->catchException($e);
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function garbageCollection() {
+    try {
+      $this->connection->delete($this->bin)
+        ->condition('expire', Cache::PERMANENT, '<>')
+        ->condition('expire', REQUEST_TIME, '<')
+        ->execute();
+    }
+    catch (\Exception $e) {
+      // If the table does not exist, it surely does not have garbage in it.
+      // If the table exists, the next garbage collection will clean up.
+      // There is nothing to do.
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function removeBin() {
+    try {
+      $this->connection->schema()->dropTable($this->bin);
+    }
+    catch (\Exception $e) {
+      $this->catchException($e);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function counter($cid, $increment, $default = 0, $expire = CacheRawBackendInterface::CACHE_PERMANENT) {
+    try {
+      $query = $this->connection->update($this->bin);
+      $query ->condition('cid', $cid);
+      $query ->condition('data_int', NULL, 'IS NOT NULL');
+      $query->expression('data_int', "data_int + $increment");
+      $result = $query->execute();
+      if ($result == 0) {
+        throw new \Exception('Item does not exist.');
+      }
+    }
+    catch (\Exception $e) {
+      $this->set($cid, $default, $expire);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function counterMultiple(array $cids, $increment, $default = 0, $expire = CacheRawBackendInterface::CACHE_PERMANENT) {
+    // TODO: This can be implemented in a batched way (with just one query)
+    // and counter() should call counterMultiple()
+    foreach ($cids as $cid) {
+      $this->counter($cid, $increment, $default, $expire);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function touch($cid, $expire = CacheRawBackendInterface::CACHE_PERMANENT) {
+    try {
+      $query = $this->connection->update($this->bin);
+      $query ->condition('cid', $cid);
+      $query->expression('expire', $expire);
+      $query->execute();
+    }
+    catch (\Exception $e) {
+      // No problem if this fails.
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function touchMultiple(array $cids, $expire = CacheRawBackendInterface::CACHE_PERMANENT) {
+    foreach ($cids as $cid) {
+      $this->touch($cid, $expire);
+    }
+  }
+
+  /**
+   * Check if the cache bin exists and create it if not.
+   */
+  protected function ensureBinExists() {
+    try {
+      $database_schema = $this->connection->schema();
+      if (!$database_schema->tableExists($this->bin)) {
+        $schema_definition = $this->schemaDefinition();
+        $database_schema->createTable($this->bin, $schema_definition);
+        return TRUE;
+      }
+    }
+    // If another process has already created the cache table, attempting to
+    // recreate it will throw an exception. In this case just catch the
+    // exception and do nothing.
+    catch (SchemaObjectExistsException $e) {
+      return TRUE;
+    }
+    return FALSE;
+  }
+
+  /**
+   * Act on an exception when cache might be stale.
+   *
+   * If the table does not yet exist, that's fine, but if the table exists and
+   * yet the query failed, then the cache is stale and the exception needs to
+   * propagate.
+   *
+   * @param $e
+   *   The exception.
+   * @param string|null $table_name
+   *   The table name. Defaults to $this->bin.
+   *
+   * @throws \Exception
+   */
+  protected function catchException(\Exception $e, $table_name = NULL) {
+    if ($this->connection->schema()->tableExists($table_name ?: $this->bin)) {
+      throw $e;
+    }
+  }
+
+  /**
+   * Normalizes a cache ID in order to comply with database limitations.
+   *
+   * @param string $cid
+   *   The passed in cache ID.
+   *
+   * @return string
+   *   An ASCII-encoded cache ID that is at most 255 characters long.
+   */
+  protected function normalizeCid($cid) {
+    // Nothing to do if the ID is a US ASCII string of 255 characters or less.
+    $cid_is_ascii = mb_check_encoding($cid, 'ASCII');
+    if (strlen($cid) <= 255 && $cid_is_ascii) {
+      return $cid;
+    }
+    // Return a string that uses as much as possible of the original cache ID
+    // with the hash appended.
+    $hash = Crypt::hashBase64($cid);
+    if (!$cid_is_ascii) {
+      return $hash;
+    }
+    return substr($cid, 0, 255 - strlen($hash)) . $hash;
+  }
+
+  /**
+   * Defines the schema for the {cache_*} bin tables.
+   */
+  public function schemaDefinition() {
+    $schema = array(
+      'description' => 'Storage for the cache API.',
+      'fields' => array(
+        'cid' => array(
+          'description' => 'Primary Key: Unique cache ID.',
+          'type' => 'varchar_ascii',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+          'binary' => TRUE,
+        ),
+        'data_serialized' => array(
+          'description' => 'Cache when data is serialized',
+          'type' => 'blob',
+          'not null' => FALSE,
+          'size' => 'big',
+        ),
+        'data_string' => array(
+          'description' => 'Cache data when string.',
+          'type' => 'text',
+          'not null' => FALSE,
+          'size' => 'big',
+        ),
+        'data_int' => array(
+          'description' => 'Cache data when integer.',
+          'type' => 'int',
+          'not null' => FALSE,
+          'size' => 'big',
+        ),
+        'data_float' => array(
+          'description' => 'Cache data when float',
+          'type' => 'float',
+          'not null' => FALSE,
+        ),
+        'expire' => array(
+          'description' => 'A Unix timestamp indicating when the cache entry should expire, or ' . Cache::PERMANENT . ' for never.',
+          'type' => 'int',
+          'not null' => TRUE,
+          'size' => 'big',
+          'default' => 0,
+        ),
+        'storage' => array(
+          'description' => 'A flag to indicate the storage type: 0 => serialized, 1 => string, 2 => integer, 3 => float',
+          'type' => 'int',
+          'size' => 'small',
+          'not null' => TRUE,
+        ),
+      ),
+      'indexes' => array(
+        'expire' => array('expire'),
+      ),
+      'primary key' => array('cid'),
+    );
+    return $schema;
+  }
+}
diff --git a/core/lib/Drupal/Core/Cache/DummyTagChecksum.php b/core/lib/Drupal/Core/Cache/DummyTagChecksum.php
new file mode 100644
index 0000000..f74e5fd
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/DummyTagChecksum.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\DummyTagChecksum.
+ */
+
+namespace Drupal\Core\Cache;
+
+use Drupal\Core\Cache\CacheTagsChecksumInterface;
+use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
+
+/**
+ * Stub checksum interface, for when you need to use a cache backend
+ * without tag invalidation support.
+ */
+class DummyTagChecksum implements CacheTagsChecksumInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCurrentChecksum(array $tags) {
+    if (!empty($tags)) {
+      throw new \Exception("DummyTagChecksum cannot process tags.");
+    }
+    // Checksum needs to be 0 because the original
+    // database storage for tags was designed not
+    // to accept NULL.
+    return 0;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isValid($checksum, array $tags) { 
+    if (!empty($tags) || !empty($checksum)) {
+      throw new \Exception("DummyTagChecksum cannot process tags and items cannot have a checksum.");
+    }
+    return TRUE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function reset() { return; }
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index 278826e..b10a876 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -78,7 +78,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
         'arguments' => ['@database', '@cache_tags_provider.container', 'container'],
       ],
       'cache_tags_provider.container' => [
-        'class' => 'Drupal\Core\Cache\DatabaseCacheTagsChecksum',
+        'class' => 'Drupal\Core\Cache\CacheCacheTagsChecksum',
         'arguments' => ['@database'],
       ],
     ],
diff --git a/core/tests/Drupal/Tests/Core/Cache/ChainedFastBackendTest.php b/core/tests/Drupal/Tests/Core/Cache/ChainedFastBackendTest.php
index 11e1600..26dd2b3 100644
--- a/core/tests/Drupal/Tests/Core/Cache/ChainedFastBackendTest.php
+++ b/core/tests/Drupal/Tests/Core/Cache/ChainedFastBackendTest.php
@@ -44,8 +44,10 @@ class ChainedFastBackendTest extends UnitTestCase {
   public function testGetDoesntHitConsistentBackend() {
     $consistent_cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
     $timestamp_cid = ChainedFastBackend::LAST_WRITE_TIMESTAMP_PREFIX . 'cache_foo';
-    // Use the request time because that is what we will be comparing against.
-    $timestamp_item = (object) array('cid' => $timestamp_cid, 'data' => (int) $_SERVER['REQUEST_TIME'] - 60);
+    $headid = uniqid(microtime(TRUE), TRUE);
+    // Using a future time to make sure that proper head detection is being enforced. If it is this head
+    // invalidating the binary, the value from the fastCache should be considered instead.
+    $timestamp_item = (object) array('cid' => $timestamp_cid, 'data' => array('timestamp' => (int) $_SERVER['REQUEST_TIME'] + 60, 'head' => $headid));
     $consistent_cache->expects($this->once())
       ->method('get')->with($timestamp_cid)
       ->will($this->returnValue($timestamp_item));
@@ -54,6 +56,8 @@ public function testGetDoesntHitConsistentBackend() {
 
     $fast_cache = new MemoryBackend('foo');
     $fast_cache->set('foo', 'baz');
+    $fast_cache->set($timestamp_cid, (int) $_SERVER['REQUEST_TIME'] - 60);
+    $fast_cache->set('headid', $headid);
 
     $chained_fast_backend = new ChainedFastBackend(
       $consistent_cache,
@@ -67,10 +71,19 @@ public function testGetDoesntHitConsistentBackend() {
    * Tests a fast cache miss gets data from the consistent cache backend.
    */
   public function testFallThroughToConsistentCache() {
+    $headid = uniqid(microtime(TRUE), TRUE);
     $timestamp_item = (object) array(
       'cid' => ChainedFastBackend::LAST_WRITE_TIMESTAMP_PREFIX . 'cache_foo',
-      'data' => time() + 60, // Time travel is easy.
+      'data' => array('timestamp' => time() + 60, 'head' => $headid)
     );
+    $timestamp_item_fast = (object) array(
+      'cid' => ChainedFastBackend::LAST_WRITE_TIMESTAMP_PREFIX . 'cache_foo',
+      'data' => time() + 60,
+    );
+    $head_item = (object) array(
+      'cid' => 'headid',
+      'data' => $headid
+      );
     $cache_item = (object) array(
       'cid' => 'foo',
       'data' => 'baz',
@@ -94,16 +107,24 @@ public function testFallThroughToConsistentCache() {
       ->with(array($cache_item->cid))
       ->will($this->returnValue(array($cache_item->cid => $cache_item)));
 
+    // Cache miss for headid
+    $fast_cache->expects($this->at(0))
+      ->method('get')
+      ->with('headid')
+      ->will($this->returnValue($head_item));
+
+    // Retrieve the timestamp.
+    $fast_cache->expects($this->at(1))
+    ->method('get')
+    ->with($timestamp_item_fast->cid)
+    ->will($this->returnValue($timestamp_item_fast));
+
     // We should get a call for the cache item on the fast backend.
     $fast_cache->expects($this->once())
       ->method('getMultiple')
       ->with(array($cache_item->cid))
       ->will($this->returnValue(array($cache_item->cid => $cache_item)));
 
-    // We should get a call to set the cache item on the fast backend.
-    $fast_cache->expects($this->once())
-      ->method('set')
-      ->with($cache_item->cid, $cache_item->data, $cache_item->expire);
 
     $chained_fast_backend = new ChainedFastBackend(
       $consistent_cache,
@@ -112,5 +133,4 @@ public function testFallThroughToConsistentCache() {
     );
     $this->assertEquals('baz', $chained_fast_backend->get('foo')->data);
   }
-
 }
