=== modified file 'includes/cache.inc'
--- includes/cache.inc	2009-05-21 10:17:37 +0000
+++ includes/cache.inc	2009-06-05 04:23:56 +0000
@@ -1,6 +1,17 @@
 <?php
 // $Id: cache.inc,v 1.33 2009/05/21 10:17:37 dries Exp $
 
+function _get_cache_object($table) {
+  // We do not use drupal_static here because we do not want to change the
+  // storage of cache table mid-request.
+  static $cache_objects;
+  if (!isset($cache_objects[$table])) {
+    $class = variable_get($table, 'Drupal') . 'Cache';
+    $cache_objects[$table] = new $class($table);
+  }
+  return $cache_objects[$table];
+}
+
 /**
  * Return data from the persistent cache. Data may be stored as either plain
  * text or as serialized data. cache_get will automatically return
@@ -15,45 +26,7 @@
  * @return The cache or FALSE on failure.
  */
 function cache_get($cid, $table = 'cache') {
-  global $user;
-
-  // Garbage collection necessary when enforcing a minimum cache lifetime
-  $cache_flush = variable_get('cache_flush_' . $table, 0);
-  if ($cache_flush && ($cache_flush + variable_get('cache_lifetime', 0) <= REQUEST_TIME)) {
-    // Reset the variable immediately to prevent a meltdown in heavy load situations.
-    variable_set('cache_flush_' . $table, 0);
-    // Time to flush old cache data
-    db_delete($table)
-      ->condition('expire', CACHE_PERMANENT, '<>')
-      ->condition('expire', $cache_flush, '<=')
-      ->execute();
-  }
-
-  $cache = db_query("SELECT data, created, headers, expire, serialized FROM {" . $table . "} WHERE cid = :cid", array(':cid' => $cid))->fetchObject();
-
-  if (!isset($cache->data)) {
-    return FALSE;
-  }
-
-  // If enforcing a minimum cache lifetime, validate that the data is
-  // currently valid for this user before we return it by making sure the cache
-  // entry was created before the timestamp in the current session's cache
-  // timer. The cache variable is loaded into the $user object by _sess_read()
-  // in session.inc. If the data is permanent or we're not enforcing a minimum
-  // cache lifetime always return the cached data.
-  if ($cache->expire != CACHE_PERMANENT && variable_get('cache_lifetime', 0) && $user->cache > $cache->created) {
-    // This cache data is too old and thus not valid for us, ignore it.
-    return FALSE;
-  }
-
-  if ($cache->serialized) {
-    $cache->data = unserialize($cache->data);
-  }
-  if (isset($cache->headers)) {
-    $cache->headers = unserialize($cache->headers);
-  }
-
-  return $cache;
+  return _get_cache_object($table)->get($cid);
 }
 
 /**
@@ -102,31 +75,14 @@ function cache_get($cid, $table = 'cache
  *   A string containing HTTP header information for cached pages.
  */
 function cache_set($cid, $data, $table = 'cache', $expire = CACHE_PERMANENT, array $headers = NULL) {
-  $fields = array(
-    'serialized' => 0,
-    'created' => REQUEST_TIME,
-    'expire' => $expire,
-    'headers' => isset($headers) ? serialize($headers) : NULL,
-  );
-  if (!is_string($data)) {
-    $fields['data'] = serialize($data);
-    $fields['serialized'] = 1;
-  }
-  else {
-    $fields['data'] = $data;
-    $fields['serialized'] = 0;
-  }
-
-  db_merge($table)
-    ->key(array('cid' => $cid))
-    ->fields($fields)
-    ->execute();
+  return _get_cache_object($table)->set($cid, $data, $expire, $headers);
 }
 
 /**
+ * Expire data from the cache.
  *
- * Expire data from the cache. If called without arguments, expirable
- * entries will be cleared from the cache_page and cache_block tables.
+ * If called without arguments, expirable entries will be cleared from the
+ * cache_page and cache_block tables.
  *
  * @param $cid
  *   If set, the cache ID to delete. Otherwise, all cache entries that can
@@ -142,8 +98,6 @@ function cache_set($cid, $data, $table =
  *   match. If '*' is given as $cid, the table $table will be emptied.
  */
 function cache_clear_all($cid = NULL, $table = NULL, $wildcard = FALSE) {
-  global $user;
-
   if (!isset($cid) && !isset($table)) {
     // Clear the block cache first, so stale data will
     // not end up in the page cache.
@@ -153,53 +107,222 @@ function cache_clear_all($cid = NULL, $t
     cache_clear_all(NULL, 'cache_page');
     return;
   }
+  return _get_cache_object($table)->clear_all($cid, $wildcard);
+}
 
-  if (empty($cid)) {
-    if (variable_get('cache_lifetime', 0)) {
-      // We store the time in the current user's $user->cache variable which
-      // will be saved into the sessions table by _sess_write(). We then
-      // simulate that the cache was flushed for this user by not returning
-      // cached data that was cached before the timestamp.
-      $user->cache = REQUEST_TIME;
-
-      $cache_flush = variable_get('cache_flush_' . $table, 0);
-      if ($cache_flush == 0) {
-        // This is the first request to clear the cache, start a timer.
-        variable_set('cache_flush_' . $table, REQUEST_TIME);
+interface DrupalCacheInterface {
+  function __construct($table);
+
+  /**
+   * Return 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
+   *   The cache ID of the data to retrieve.
+   * @return The cache or FALSE on failure.
+   */
+  function get($cid);
+
+  /**
+   * Store data in the persistent cache.
+   *
+   * The persistent cache is split up into four database
+   * tables. Contributed modules can add additional tables.
+   *
+   * 'cache_page': This table stores generated pages for anonymous
+   * users. This is the only table affected by the page cache setting on
+   * the administrator panel.
+   *
+   * 'cache_menu': Stores the cacheable part of the users' menus.
+   *
+   * 'cache_filter': Stores filtered pieces of content. This table is
+   * periodically cleared of stale entries by cron.
+   *
+   * 'cache': Generic cache storage table.
+   *
+   * The reasons for having several tables are as follows:
+   *
+   * - smaller tables allow for faster selects and inserts
+   * - we try to put fast changing cache items and rather static
+   *   ones into different tables. The effect is that only the fast
+   *   changing tables will need a lot of writes to disk. The more
+   *   static tables will also be better cacheable with MySQL's query cache
+   *
+   * @param $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
+   *   One of the following values:
+   *   - CACHE_PERMANENT: Indicates that the item should never be removed unless
+   *     explicitly told to using cache_clear_all() with a cache ID.
+   *   - CACHE_TEMPORARY: Indicates that the item should be removed at the next
+   *     general cache wipe.
+   *   - A Unix timestamp: Indicates that the item should be kept at least until
+   *     the given time, after which it behaves like CACHE_TEMPORARY.
+   * @param $headers
+   *   A string containing HTTP header information for cached pages.
+   */
+  function set($cid, $data, $expire = CACHE_PERMANENT, array $headers = NULL);
+
+  /**
+   *
+   * Expire data from the cache. If called without arguments, expirable
+   * entries will be cleared from the cache_page and cache_block tables.
+   *
+   * @param $cid
+   *   If set, the cache ID to delete. Otherwise, all cache entries that can
+   *   expire are deleted.
+   * @param $wildcard
+   *   If set to TRUE, the $cid is treated as a substring
+   *   to match rather than a complete ID. The match is a right hand
+   *   match. If '*' is given as $cid, the table $table will be emptied.
+   */
+  function clear_all($cid = NULL, $wildcard = FALSE);
+}
+
+class DrupalCache implements DrupalCacheInterface {
+  protected $table;
+
+  function __construct($table) {
+    $this->table = $table;
+  }
+  
+  function get($cid) {
+    global $user;
+  
+    // Garbage collection necessary when enforcing a minimum cache lifetime
+    $cache_flush = variable_get('cache_flush_' . $this->table, 0);
+    if ($cache_flush && ($cache_flush + variable_get('cache_lifetime', 0) <= REQUEST_TIME)) {
+      // Reset the variable immediately to prevent a meltdown in heavy load situations.
+      variable_set('cache_flush_' . $this->table, 0);
+      // Time to flush old cache data
+      db_delete($this->table)
+        ->condition('expire', CACHE_PERMANENT, '<>')
+        ->condition('expire', $cache_flush, '<=')
+        ->execute();
+    }
+  
+    $cache = db_query("SELECT data, created, headers, expire, serialized FROM {" . $this->table . "} WHERE cid = :cid", array(':cid' => $cid))->fetchObject();
+  
+    if (!isset($cache->data)) {
+      return FALSE;
+    }
+  
+    // If enforcing a minimum cache lifetime, validate that the data is
+    // currently valid for this user before we return it by making sure the cache
+    // entry was created before the timestamp in the current session's cache
+    // timer. The cache variable is loaded into the $user object by _sess_read()
+    // in session.inc. If the data is permanent or we're not enforcing a minimum
+    // cache lifetime always return the cached data.
+    if ($cache->expire != CACHE_PERMANENT && variable_get('cache_lifetime', 0) && $user->cache > $cache->created) {
+      // This cache data is too old and thus not valid for us, ignore it.
+      return FALSE;
+    }
+  
+    if ($cache->serialized) {
+      $cache->data = unserialize($cache->data);
+    }
+    if (isset($cache->headers)) {
+      $cache->headers = unserialize($cache->headers);
+    }
+  
+    return $cache;
+  }
+  
+  function set($cid, $data, $expire = CACHE_PERMANENT, array $headers = NULL) {
+    $fields = array(
+      'serialized' => 0,
+      'created' => REQUEST_TIME,
+      'expire' => $expire,
+      'headers' => isset($headers) ? serialize($headers) : NULL,
+    );
+    if (!is_string($data)) {
+      $fields['data'] = serialize($data);
+      $fields['serialized'] = 1;
+    }
+    else {
+      $fields['data'] = $data;
+      $fields['serialized'] = 0;
+    }
+  
+    db_merge($this->table)
+      ->key(array('cid' => $cid))
+      ->fields($fields)
+      ->execute();
+  }
+  
+  /**
+   *
+   * Expire data from the cache. If called without arguments, expirable
+   * entries will be cleared from the cache_page and cache_block tables.
+   *
+   * @param $cid
+   *   If set, the cache ID to delete. Otherwise, all cache entries that can
+   *   expire are deleted.
+   *
+   * @param $this->table
+   *   If set, the table $this->table to delete from. Mandatory
+   *   argument if $cid is set.
+   *
+   * @param $wildcard
+   *   If set to TRUE, the $cid is treated as a substring
+   *   to match rather than a complete ID. The match is a right hand
+   *   match. If '*' is given as $cid, the table $this->table will be emptied.
+   */
+  function clear_all($cid = NULL, $wildcard = FALSE) {
+    global $user;
+    
+    if (empty($cid)) {
+      if (variable_get('cache_lifetime', 0)) {
+        // We store the time in the current user's $user->cache variable which
+        // will be saved into the sessions table by _sess_write(). We then
+        // simulate that the cache was flushed for this user by not returning
+        // cached data that was cached before the timestamp.
+        $user->cache = REQUEST_TIME;
+  
+        $cache_flush = variable_get('cache_flush_' . $this->table, 0);
+        if ($cache_flush == 0) {
+          // This is the first request to clear the cache, start a timer.
+          variable_set('cache_flush_' . $this->table, REQUEST_TIME);
+        }
+        elseif (REQUEST_TIME > ($cache_flush + variable_get('cache_lifetime', 0))) {
+          // Clear the cache for everyone, cache_lifetime seconds have
+          // passed since the first request to clear the cache.
+          db_delete($this->table)
+            ->condition('expire', CACHE_PERMANENT, '<>')
+            ->condition('expire', REQUEST_TIME, '<')
+            ->execute();
+          variable_set('cache_flush_' . $this->table, 0);
+        }
       }
-      elseif (REQUEST_TIME > ($cache_flush + variable_get('cache_lifetime', 0))) {
-        // Clear the cache for everyone, cache_lifetime seconds have
-        // passed since the first request to clear the cache.
-        db_delete($table)
+      else {
+        // No minimum cache lifetime, flush all temporary cache entries now.
+        db_delete($this->table)
           ->condition('expire', CACHE_PERMANENT, '<>')
           ->condition('expire', REQUEST_TIME, '<')
           ->execute();
-        variable_set('cache_flush_' . $table, 0);
       }
     }
     else {
-      // No minimum cache lifetime, flush all temporary cache entries now.
-      db_delete($table)
-        ->condition('expire', CACHE_PERMANENT, '<>')
-        ->condition('expire', REQUEST_TIME, '<')
-        ->execute();
-    }
-  }
-  else {
-    if ($wildcard) {
-      if ($cid == '*') {
-        db_truncate($table)->execute();
+      if ($wildcard) {
+        if ($cid == '*') {
+          db_truncate($this->table)->execute();
+        }
+        else {
+          db_delete($this->table)
+            ->condition('cid', $cid . '%', 'LIKE')
+            ->execute();
+        }
       }
       else {
-        db_delete($table)
-          ->condition('cid', $cid . '%', 'LIKE')
+        db_delete($this->table)
+          ->condition('cid', $cid)
           ->execute();
       }
     }
-    else {
-      db_delete($table)
-        ->condition('cid', $cid)
-        ->execute();
-    }
   }
-}
+}
\ No newline at end of file

