diff --git a/core/modules/views/lib/Drupal/views/ViewsDataCache.php b/core/modules/views/lib/Drupal/views/ViewsDataCache.php
new file mode 100644
index 0000000..c2ddbd8
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/ViewsDataCache.php
@@ -0,0 +1,195 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\ViewsDataCache.
+ */
+
+namespace Drupal\views;
+
+/**
+ * @todo.
+ */
+class ViewsDataCache {
+
+  /**
+   * The base cache ID to use.
+   *
+   * @var string
+   */
+  protected $baseCid = 'views_data';
+
+  /**
+   * This views cache bin to use.
+   *
+   * @var string
+   */
+  protected $bin = 'views_info';
+
+  /**
+   * Storage for the data itself.
+   *
+   * @var array
+   */
+  protected $storage = array();
+
+  /**
+   * @todo.
+   *
+   * @var bool
+   */
+  protected $fullyLoaded = FALSE;
+
+  /**
+   * @todo.
+   *
+   * @var bool
+   */
+  protected $useLanguage;
+
+  /**
+   * @todo
+   *
+   * @var bool
+   */
+  protected $skipCache;
+
+  /**
+   * @todo
+   *
+   * @var bool
+   */
+  protected $rebuildCache;
+
+  public function __construct($use_language = FALSE, $skip_cache = FALSE) {
+    $this->useLanguage = $use_language;
+    // @todo Use this from the paramter instead.
+    $this->skipCache = config('views.settings')->get('skip_cache');
+  }
+
+  /**
+   * @todo.
+   */
+  public function get($key) {
+    if ($key) {
+      if (!isset($this->storage[$key])) {
+        $cid = $this->baseCid . ':' . $key;
+        $data = $this->cacheGet($cid);
+        if (!empty($data->data)) {
+          $this->storage[$key] = $data->data;
+        }
+        else {
+          // No cache entry, rebuild.
+          $this->storage = $this->getData();
+          $this->fullyLoaded = TRUE;
+        }
+      }
+      if (isset($this->storage[$key])) {
+        return $this->storage[$key];
+      }
+    }
+    else {
+      if (!$this->fullyLoaded) {
+        $data = $this->cacheGet($this->baseCid);
+        if (!empty($data->data)) {
+          $this->storage = $data->data;
+        }
+        else {
+          $this->storage = $this->getData();
+        }
+        $fully_loaded = TRUE;
+      }
+    }
+
+    // Return an empty array if there is no match.
+    return $this->storage;
+  }
+
+  /**
+   * @todo.
+   */
+  public function set($key, $value) {
+    if ($this->skipCache) {
+      return FALSE;
+    }
+    if ($this->useLanguage) {
+      $cid .= ':' . language(LANGUAGE_TYPE_INTERFACE)->langcode;
+    }
+
+    cache($this->bin)->set($cid, $value);
+  }
+
+  /**
+   * [cacheGet description]
+   *
+   * @param  [type] $cid [description]
+   *
+   * @return mixed
+   */
+  protected function cacheGet($cid) {
+    if ($this->skipCache) {
+      return FALSE;
+    }
+    if ($this->useLanguage) {
+      $cid .= ':' . language(LANGUAGE_TYPE_INTERFACE)->langcode;
+    }
+
+    return cache($this->bin)->get($cid);
+  }
+
+  /**
+   * @todo.
+   */
+  protected function getData() {
+    $data = module_invoke_all('views_data');
+
+    foreach (module_implements('views_data_alter') as $module) {
+      $function = $module . '_views_data_alter';
+      $function($data);
+    }
+
+    $this->processEntityTypes($data);
+
+    $this->rebuildCache = TRUE;
+
+    return $data;
+  }
+
+  /**
+   * [processEntityTypes description]
+   * @param  array  $data [description]
+   */
+  protected function processEntityTypes(array &$data) {
+    foreach ($data as $table_name => $table_info) {
+      // Add in a join from the entity-table if an entity-type is given.
+      if (!empty($table_info['table']['entity type'])) {
+        $entity_table = 'views_entity_' . $table_info['table']['entity type'];
+
+        $data[$entity_table]['table']['join'][$table_name] = array(
+          'left_table' => $table_name,
+        );
+        $data[$entity_table]['table']['entity type'] = $table_info['table']['entity type'];
+        // Copy over the default table group if we have none yet.
+        if (!empty($table_info['table']['group']) && empty($data[$entity_table]['table']['group'])) {
+          $data[$entity_table]['table']['group'] = $table_info['table']['group'];
+        }
+      }
+    }
+  }
+
+  /**
+   * Destructs the ViewData object.
+   */
+  public function __destruct() {
+    if ($this->rebuildCache && !empty($this->storage)) {
+      // Keep a record with all data.
+      $this->set($this->baseCid, $this->storage);
+      // Save data in seperate cache entries.
+      foreach ($$this->storage as $table => $data) {
+        $cid = $this->baseCid . ':' . $table;
+        $this->set($cid, $data);
+      }
+    }
+  }
+
+}
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 514a78a..22f2931 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -13,6 +13,7 @@
 use Drupal\views\ViewExecutable;
 use Drupal\Component\Plugin\Exception\PluginException;
 use Drupal\views\Plugin\Core\Entity\View;
+use Drupal\views\ViewsDataCache;
 
 /**
  * Views API version string.
@@ -1210,8 +1211,11 @@ function views_get_handler($table, $field, $type, $override = NULL) {
  * @see hook_views_data()
  */
 function views_fetch_data($table = NULL, $reset = FALSE) {
-  views_include('cache');
-  return _views_fetch_data($table, $reset);
+  static $viewsDataCache;
+  if (!isset($viewsDataCache)) {
+    $viewsDataCache = new viewsDataCache();
+  }
+  return $viewsDataCache->get($table);
 }
 
 /**
