diff --git a/core/includes/module.inc b/core/includes/module.inc
index f964af8..70492e1 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -710,6 +710,13 @@ function module_uninstall($module_list = array(), $uninstall_dependents = TRUE)
       config($config_name)->delete();
     }
 
+    // Remove any cache bins defined by the module.
+    if ($bins = module_invoke($module, 'cache_bin_info')) {
+      foreach ($bins as $bin) {
+        cache($bin)->removeBin();
+      }
+    }
+
     watchdog('system', '%module module uninstalled.', array('%module' => $module), WATCHDOG_INFO);
     $schema_store->delete($module);
     $disabled_config->clear($module);
diff --git a/core/lib/Drupal/Core/Cache/BackendChain.php b/core/lib/Drupal/Core/Cache/BackendChain.php
index 4918767..6d9d7ad 100644
--- a/core/lib/Drupal/Core/Cache/BackendChain.php
+++ b/core/lib/Drupal/Core/Cache/BackendChain.php
@@ -192,4 +192,13 @@ public function isEmpty() {
 
     return TRUE;
   }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::removeBin().
+   */
+  public function removeBin() {
+    foreach ($this->backends as $backend) {
+      $this->removeBin();
+    }
+  }
 }
diff --git a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php
index ee1df76..fa9319e 100644
--- a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php
+++ b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php
@@ -148,6 +148,11 @@ public function invalidateTags(array $tags);
   public function garbageCollection();
 
   /**
+   * Remove a cache bin.
+   */
+  public function removeBin();
+
+  /**
    * Checks if a cache bin is empty.
    *
    * A cache bin is considered empty if it does not contain any valid data for
diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
index a12ed13..1fe7647 100644
--- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php
+++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
@@ -56,6 +56,7 @@ public function get($cid) {
    * Implements Drupal\Core\Cache\CacheBackendInterface::getMultiple().
    */
   public function getMultiple(&$cids) {
+    $cache = array();
     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
@@ -65,7 +66,6 @@ public function getMultiple(&$cids) {
       // 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));
-      $cache = array();
       foreach ($result as $item) {
         $item = $this->prepareItem($item);
         if ($item) {
@@ -73,13 +73,12 @@ public function getMultiple(&$cids) {
         }
       }
       $cids = array_diff($cids, array_keys($cache));
-      return $cache;
     }
     catch (Exception $e) {
-      // If the database is never going to be available, cache requests should
-      // return FALSE in order to allow exception handling to occur.
-      return array();
+      // Try to create the cache bin if it doesn't exist.
+      $this->ensureBinExists();
     }
+    return $cache;
   }
 
   /**
@@ -143,7 +142,8 @@ public function set($cid, $data, $expire = CacheBackendInterface::CACHE_PERMANEN
         ->execute();
     }
     catch (Exception $e) {
-      // The database may not be available, so we'll ignore cache_set requests.
+      // Try to create the cache bin if it doesn't exist.
+      $this->ensureBinExists();
     }
   }
 
@@ -280,7 +280,8 @@ protected function checksumTags($tags) {
         }
       }
       catch (Exception $e) {
-        // The database may not be available, so we'll ignore cache_set requests.
+        // The database table may not exist yet, create it if it doesn't.
+        $this->ensureBinExists();
       }
     }
     return $checksum;
@@ -298,4 +299,108 @@ public function isEmpty() {
       ->fetchField();
     return empty($result);
   }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::removeBin().
+   */
+  public function removeBin() {
+    Database::getConnection()->schema()->dropTable($this->bin);
+  }
+
+  /**
+   * Check if the cache bin exists and create it if not.
+   */
+  protected function ensureBinExists() {
+    try {
+      if (!Database::getConnection()->schema()->tableExists($this->bin)) {
+        $schema = $this->schemaDefinition();
+        Database::getConnection()->schema()->createTable($this->bin, $schema['bin']);
+        // If the bin doesn't exist, the cache tags table may also not exist.
+        if (!Database::getConnection()->schema()->tableExists('cache_tags')) {
+          Database::getConnection()->schema()->createTable($this->bin, $schema['cache_tags']);
+        }
+      }
+    }
+    catch (Exception $e) {
+    }
+  }
+
+  /**
+   * Defines the schema for the cache bin and cache_tags table.
+   */
+  protected function schemaDefinition() {
+    $schema['bin'] = array(
+      'description' => 'Storage for the cache API.',
+      'fields' => array(
+        'cid' => array(
+          'description' => 'Primary Key: Unique cache ID.',
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+        ),
+        'data' => array(
+          'description' => 'A collection of data to cache.',
+          'type' => 'blob',
+          'not null' => FALSE,
+          'size' => 'big',
+        ), 
+        'expire' => array(
+          'description' => 'A Unix timestamp indicating when the cache entry should expire, or 0 for never.',
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+        ),
+        'created' => array(
+          'description' => 'A Unix timestamp indicating when the cache entry was created.',
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+        ),
+        'serialized' => array(
+          'description' => 'A flag to indicate whether content is serialized (1) or not (0).',
+          'type' => 'int',
+          'size' => 'small',
+          'not null' => TRUE,
+          'default' => 0,
+        ),
+        'tags' => array(
+          'description' => 'Space-separated list of cache tags for this entry.',
+          'type' => 'text',
+          'size' => 'big',
+          'not null' => FALSE,
+        ),
+        'checksum' => array(
+          'description' => 'The tag invalidation sum when this entry was saved.',
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+        ),
+      ),
+      'indexes' => array(
+        'expire' => array('expire'),
+      ),
+      'primary key' => array('cid'),
+    );
+    $schema['cache_tags'] = array(
+      'description' => 'Cache table for tracking cache tags related to the cache bin.',
+      'fields' => array(
+        'tag' => array(
+          'description' => 'Namespace-prefixed tag string.',
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+        ),
+        'invalidations' => array(
+          'description' => 'Number incremented when the tag is invalidated.',
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+        ),
+      ),
+      'primary key' => array('tag'),
+    );
+    return $schema;
+  }
 }
diff --git a/core/lib/Drupal/Core/Cache/MemoryBackend.php b/core/lib/Drupal/Core/Cache/MemoryBackend.php
index 837df0e..b9efeba 100644
--- a/core/lib/Drupal/Core/Cache/MemoryBackend.php
+++ b/core/lib/Drupal/Core/Cache/MemoryBackend.php
@@ -226,4 +226,9 @@ public function isEmpty() {
    */
   public function garbageCollection() {
   }
+
+ /** 
+  * Implements Drupal\Core\CacheBackendInterface::removeBin(). 
+  */ 
+  public function removeBin() {} 
 }
diff --git a/core/lib/Drupal/Core/Cache/NullBackend.php b/core/lib/Drupal/Core/Cache/NullBackend.php
index 66a9938..4c1a117 100644
--- a/core/lib/Drupal/Core/Cache/NullBackend.php
+++ b/core/lib/Drupal/Core/Cache/NullBackend.php
@@ -83,4 +83,9 @@ public function invalidateTags(array $tags) {}
   public function isEmpty() {
     return TRUE;
   }
+
+  /**
+   * Implements Drupal\Core\CacheBackendInterface::removeBin().
+   */
+  public function removeBin() {}
 }
diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
index d88633f..5a50d10 100644
--- a/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
@@ -480,7 +480,7 @@ public function prepareComment($comment, $length = NULL) {
     // Truncate comment to maximum comment length.
     if (isset($length)) {
       // Add table prefixes before truncating.
-      $comment = truncate_utf8($this->connection->prefixTables($comment), $length, TRUE, TRUE);
+      $comment = substr($this->connection->prefixTables($comment), 0, $length);
     }
 
     return $this->connection->quote($comment);
diff --git a/core/modules/block/block.install b/core/modules/block/block.install
index 56b91c3..20fba82 100644
--- a/core/modules/block/block.install
+++ b/core/modules/block/block.install
@@ -203,13 +203,17 @@ function block_schema() {
     'primary key' => array('module', 'delta', 'type', 'langcode'),
   );
 
-  $schema['cache_block'] = drupal_get_schema_unprocessed('system', 'cache');
-  $schema['cache_block']['description'] = 'Cache table for the Block module to store already built blocks, identified by module, delta, and various contexts which may change the block, such as theme, locale, and caching mode defined for the block.';
-
   return $schema;
 }
 
 /**
+ * Implements hook_cache_bin_info().
+ */
+function block_cache_bin_info() {
+  return array('block');
+}
+
+/**
  * Implements hook_install().
  */
 function block_install() {
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index 2978146..1d827e1 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -948,13 +948,6 @@ function _block_get_renderable_block($element) {
 }
 
 /**
- * Implements hook_cache_flush().
- */
-function block_cache_flush() {
-  return array('block');
-}
-
-/**
  * Implements hook_rebuild().
  */
 function block_rebuild() {
diff --git a/core/modules/field/field.install b/core/modules/field/field.install
index bc566d6..cef699c 100644
--- a/core/modules/field/field.install
+++ b/core/modules/field/field.install
@@ -161,13 +161,17 @@ function field_schema() {
       'deleted' => array('deleted'),
     ),
   );
-  $schema['cache_field'] = drupal_get_schema_unprocessed('system', 'cache');
-  $schema['cache_field']['description'] = 'Cache table for the Field module to store already built field informations.';
-
   return $schema;
 }
 
 /**
+ * Implements hook_cache_bin_info().
+ */
+function field_cache_bin_info() {
+  return array('field');
+}
+
+/**
  * Creates a field by writing directly to the database.
  *
  * @ingroup update_api
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index ac0d1b4..c020a7e 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -467,14 +467,6 @@ function field_language_fallback(&$field_langcodes, $entity, $langcode) {
 }
 
 /**
- * Implements hook_cache_flush().
- */
-function field_cache_flush() {
-  // Request a flush of our cache table.
-  return array('field');
-}
-
-/**
  * Implements hook_rebuild().
  */
 function field_rebuild() {
diff --git a/core/modules/filter/filter.install b/core/modules/filter/filter.install
index 9237ad1..21297e1 100644
--- a/core/modules/filter/filter.install
+++ b/core/modules/filter/filter.install
@@ -105,13 +105,17 @@ function filter_schema() {
     ),
   );
 
-  $schema['cache_filter'] = drupal_get_schema_unprocessed('system', 'cache');
-  $schema['cache_filter']['description'] = 'Cache table for the Filter module to store already filtered pieces of text, identified by text format and hash of the text.';
-
   return $schema;
 }
 
 /**
+ * Implements hook_cache_bin_info().
+ */
+function filter_cache_bin_info() {
+  return array('filter');
+}
+
+/**
  * Implements hook_install().
  */
 function filter_install() {
diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index b55066f..f9940e8 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -29,13 +29,6 @@
 const FILTER_TYPE_TRANSFORM_IRREVERSIBLE = 3;
 
 /**
- * Implements hook_cache_flush().
- */
-function filter_cache_flush() {
-  return array('filter');
-}
-
-/**
  * Implements hook_help().
  */
 function filter_help($path, $arg) {
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 2d09534..278906b 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -2125,12 +2125,12 @@ function hook_mail($key, &$message, $params) {
 /**
  * Flush all persistent and static caches.
  *
- * This hook asks your module to clear all of its persistent (database) and
- * static caches, in order to ensure a clean environment for subsequently
+ * This hook asks your module to clear all of its static caches,
+ * in order to ensure a clean environment for subsequently
  * invoked data rebuilds.
  *
  * Do NOT use this hook for rebuilding information. Only use it to flush custom
- * caches and return the names of additional cache bins to flush.
+ * caches.
  *
  * Static caches using drupal_static() do not need to be reset manually.
  * However, all other static variables that do not use drupal_static() must be
@@ -2139,14 +2139,11 @@ function hook_mail($key, &$message, $params) {
  * This hook is invoked by drupal_flush_all_caches(). It runs before module data
  * is updated and before hook_rebuild().
  *
- * @return array
- *   An array of cache bins to be flushed.
- *
  * @see drupal_flush_all_caches()
  * @see hook_rebuild()
  */
 function hook_cache_flush() {
-  return array('example');
+  my_custom_static_cache_reset();
 }
 
 /**
@@ -2567,6 +2564,19 @@ function hook_requirements($phase) {
 }
 
 /**
+ * Defines the cache bins used by your module.
+ *
+ * This hook is used during module uninstallation to remove unused cache bins
+ * so must be defined in the .install file.
+ *
+ * @return
+ *   An array of cache bin names. 
+ */
+function hook_cache_bin_info() {
+  return array('my_bin');
+}
+
+/**
  * Define the current version of the database schema.
  *
  * A Drupal schema definition is an array structure representing one or
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 25c7adb..6f18dada 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -582,92 +582,6 @@ function system_schema() {
     ),
   );
 
-  $schema['cache_tags'] = array(
-    'description' => 'Cache table for tracking cache tags related to the cache bin.',
-    'fields' => array(
-      'tag' => array(
-        'description' => 'Namespace-prefixed tag string.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'invalidations' => array(
-        'description' => 'Number incremented when the tag is invalidated.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-    ),
-    'primary key' => array('tag'),
-  );
-
-  $schema['cache'] = array(
-    'description' => 'Generic cache table for caching things not separated out into their own tables. Contributed modules may also use this to store cached items.',
-    'fields' => array(
-      'cid' => array(
-        'description' => 'Primary Key: Unique cache ID.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'data' => array(
-        'description' => 'A collection of data to cache.',
-        'type' => 'blob',
-        'not null' => FALSE,
-        'size' => 'big',
-      ),
-      'expire' => array(
-        'description' => 'A Unix timestamp indicating when the cache entry should expire, or 0 for never.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'created' => array(
-        'description' => 'A Unix timestamp indicating when the cache entry was created.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'serialized' => array(
-        'description' => 'A flag to indicate whether content is serialized (1) or not (0).',
-        'type' => 'int',
-        'size' => 'small',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'tags' => array(
-        'description' => 'Space-separated list of cache tags for this entry.',
-        'type' => 'text',
-        'size' => 'big',
-        'not null' => FALSE,
-      ),
-      'checksum' => array(
-        'description' => 'The tag invalidation sum when this entry was saved.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-    ),
-    'indexes' => array(
-      'expire' => array('expire'),
-    ),
-    'primary key' => array('cid'),
-  );
-  $schema['cache_bootstrap'] = $schema['cache'];
-  $schema['cache_bootstrap']['description'] = 'Cache table for data required to bootstrap Drupal, may be routed to a shared memory cache.';
-  $schema['cache_config'] = $schema['cache'];
-  $schema['cache_config']['description'] = 'Cache table for configuration data.';
-  $schema['cache_form'] = $schema['cache'];
-  $schema['cache_form']['description'] = 'Cache table for the form system to store recently built forms and their storage data, to be used in subsequent page requests.';
-  $schema['cache_page'] = $schema['cache'];
-  $schema['cache_page']['description'] = 'Cache table used to store compressed pages for anonymous users, if page caching is enabled.';
-  $schema['cache_menu'] = $schema['cache'];
-  $schema['cache_menu']['description'] = 'Cache table for the menu system to store router information as well as generated link trees for various menu/page/user combinations.';
-  $schema['cache_path'] = $schema['cache'];
-  $schema['cache_path']['description'] = 'Cache table for path alias lookup.';
-
   $schema['date_format_type'] = array(
     'description' => 'Stores configured date format types.',
     'fields' => array(
@@ -1521,6 +1435,13 @@ function system_schema_cache_8007() {
   );
 }
 
+/**
+ * Implements hook_cache_bin_info().
+ */
+function system_cache_bin_info() {
+  return array('cache', 'bootstrap', 'config', 'form', 'page', 'menu', 'path');
+}
+
 // Updates for core.
 
 function system_update_last_removed() {
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 4475104..accc31f 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -3496,7 +3496,9 @@ function system_cron() {
     ->condition('expiration', REQUEST_TIME, '<')
     ->execute();
 
-  $cache_bins = array_merge(module_invoke_all('cache_flush'), array('form', 'menu'));
+  // hook_cache_bin_info() lives in .install files, so load them.
+  module_load_all_includes('install');
+  $cache_bins = module_invoke_all('cache_bin_info');
   foreach ($cache_bins as $bin) {
     cache($bin)->expire();
   }
@@ -3522,14 +3524,6 @@ function system_cron() {
 }
 
 /**
- * Implements hook_cache_flush().
- */
-function system_cache_flush() {
-  // Do NOT flush the 'form' cache bin to retain in-progress form submissions.
-  return array('bootstrap', 'config', 'cache', 'page', 'path');
-}
-
-/**
  * Implements hook_rebuild().
  */
 function system_rebuild() {
diff --git a/core/modules/update/update.install b/core/modules/update/update.install
index d6c32d6..fdd264f 100644
--- a/core/modules/update/update.install
+++ b/core/modules/update/update.install
@@ -57,12 +57,10 @@ function update_requirements($phase) {
 }
 
 /**
- * Implements hook_schema().
+ * Implements hook_cache_bin_info().
  */
-function update_schema() {
-  $schema['cache_update'] = drupal_get_schema_unprocessed('system', 'cache');
-  $schema['cache_update']['description'] = 'Cache table for the Update module to store information about available releases, fetched from central server.';
-  return $schema;
+function update_cache_bin_info() {
+  return array('update');
 }
 
 /**
diff --git a/core/modules/views/views.install b/core/modules/views/views.install
index 5d63efa..8f9ee48 100644
--- a/core/modules/views/views.install
+++ b/core/modules/views/views.install
@@ -15,16 +15,10 @@ function views_install() {
 }
 
 /**
- * Implements hook_schema().
+ * Implements hook_cache_bin_info().
  */
-function views_schema() {
-  $schema['cache_views_info'] = drupal_get_schema_unprocessed('system', 'cache');
-
-  $schema['cache_views_results'] = drupal_get_schema_unprocessed('system', 'cache');
-  $schema['cache_views_results']['description'] = 'Cache table for views to store pre-rendered queries, results, and display output.';
-  $schema['cache_views_results']['fields']['serialized']['default'] = 1;
-
-  return $schema;
+function views_cache_bin_info() {
+  return array('views_info', 'views_results');
 }
 
 /**
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 6608d47..081f0d4 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -915,13 +915,6 @@ function views_language_list($field = 'name', $all = FALSE) {
 }
 
 /**
- * Implements hook_cache_flush().
- */
-function views_cache_flush() {
-  return array('views_info', 'views_results');
-}
-
-/**
  * Implements hook_field_create_instance.
  */
 function views_field_create_instance($instance) {
