Index: includes/cache.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/cache.inc,v
retrieving revision 1.31
diff -u -p -r1.31 cache.inc
--- includes/cache.inc	4 May 2009 10:40:10 -0000	1.31
+++ includes/cache.inc	7 May 2009 22:40:24 -0000
@@ -9,12 +9,52 @@
  * @param $cid
  *   The cache ID of the data to retrieve.
  * @param $table
- *   The table $table to store the data in. Valid core values are
- *   'cache_filter', 'cache_menu', 'cache_page', or 'cache' for
- *   the default cache.
- * @return The cache or FALSE on failure.
+ *   The cache table where the data is stored.
+ * @return
+ *   The cache or FALSE on failure.
  */
 function cache_get($cid, $table = 'cache') {
+  // Garbage collection necessary when enforcing a minimum cache lifetime.
+  _cache_garbage_collection($table);
+  $cache = db_query("SELECT data, created, headers, expire, serialized FROM {" . $table . "} WHERE cid = :cid", array(':cid' => $cid))->fetchObject();
+
+  return _cache_prepare_item($cache);
+}
+
+/**
+ * Return data from the persistent cache when given an array of cache IDs.
+ *
+ * @param $cids
+ *   An array of cache IDs for the data to retrieve. This is passed by
+ *   reference, and will have the IDs successfully returned from cache removed.
+ * @param $table
+ *   The cache table where the data is stored.
+ * @return
+ *   An array of items indexed by cid.
+ */
+function cache_get_multiple(array &$cids, $table = 'cache') {
+  // Garbage collection necessary when enforcing a minimum cache lifetime.
+  _cache_garbage_collection($table);
+  $query = db_select($table);
+  $query->fields($table, array('cid', 'data', 'created', 'headers', 'expire', 'serialized'));
+  $query->condition($table . '.cid', $cids, 'IN');
+  $result = $query->execute();
+  $cache = array();
+  foreach ($result as $item) {
+    $item = _cache_prepare_item($item);
+    $cache[$item->cid] = $item;
+  }
+  $cids = array_keys(array_diff_key(array_flip($cids), $cache));
+  return $cache;
+}
+
+/**
+ * Garbage collection for cache_get() and cache_get_multiple().
+ *
+ * @param $table
+ *   The table being requested.
+ */
+function _cache_garbage_collection($table) {
   global $user;
 
   // Garbage collection necessary when enforcing a minimum cache lifetime
@@ -28,13 +68,31 @@ function cache_get($cid, $table = 'cache
       ->condition('expire', $cache_flush, '<=')
       ->execute();
   }
+}
 
-  $cache = db_query("SELECT data, created, headers, expire, serialized FROM {" . $table . "} WHERE cid = :cid", array(':cid' => $cid))->fetchObject();
-
+/**
+ * Prepare a cached item.
+ *
+ * Checks that items are either permanent or did not expire, and unserializes
+ * data as appropriate.
+ *
+ * @param $cache
+ *   An item loaded from cache_get() or cache_get_multiple().
+ * @return
+ *   The item with data unserialized as appropriate or FALSE if there is no
+ *   valid item to load.
+ */
+function _cache_prepare_item($cache) {
   if (!isset($cache->data)) {
     return FALSE;
   }
-
+  // If the data is permanent or we are not enforcing a minimum cache lifetime
+  // always return the cached data.
+  if ($cache->expire == CACHE_PERMANENT || !variable_get('cache_lifetime', 0)) {
+    if ($cache->serialized) {
+      $cache->data = unserialize($cache->data);
+    }
+  }
   // 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
@@ -46,9 +104,6 @@ function cache_get($cid, $table = 'cache
     return FALSE;
   }
 
-  if ($cache->serialized) {
-    $cache->data = unserialize($cache->data);
-  }
   if (isset($cache->headers)) {
     $cache->headers = unserialize($cache->headers);
   }
@@ -129,8 +184,8 @@ function cache_set($cid, $data, $table =
  * 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.
+ *   If set, the cache ID to delete, or an array of cache IDs to delete.
+ *   Otherwise, all cache entries that can expire are deleted.
  *
  * @param $table
  *   If set, the table $table to delete from. Mandatory
@@ -196,6 +251,15 @@ function cache_clear_all($cid = NULL, $t
           ->execute();
       }
     }
+    elseif (is_array($cid)) {
+      // Delete in chunks when a large array is passed.
+      do {
+        db_delete($table)
+          ->condition('cid', array_splice($cid, 0, 1000), 'IN')
+          ->execute();
+      }
+      while (count($cid));
+    }
     else {
       db_delete($table)
         ->condition('cid', $cid)
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.893
diff -u -p -r1.893 common.inc
--- includes/common.inc	7 May 2009 15:29:07 -0000	1.893
+++ includes/common.inc	7 May 2009 22:40:30 -0000
@@ -165,8 +165,8 @@ function drupal_get_html_head() {
 /**
  * Reset the static variable which holds the aliases mapped for this request.
  */
-function drupal_clear_path_cache() {
-  drupal_lookup_path('wipe');
+function drupal_clear_path_cache($path = '*') {
+  drupal_lookup_path('wipe', $path);
 }
 
 /**
@@ -1873,6 +1873,7 @@ function drupal_page_footer() {
 
   module_implements(MODULE_IMPLEMENTS_WRITE_CACHE);
   _registry_check_code(REGISTRY_WRITE_LOOKUP_CACHE);
+  drupal_cache_system_paths();
 }
 
 /**
Index: includes/path.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/path.inc,v
retrieving revision 1.35
diff -u -p -r1.35 path.inc
--- includes/path.inc	7 May 2009 15:49:57 -0000	1.35
+++ includes/path.inc	7 May 2009 22:40:31 -0000
@@ -1,5 +1,5 @@
 <?php
-// $Id: path.inc,v 1.35 2009/05/07 15:49:57 webchick Exp $
+// $Id: path.inc,v 1.33 2009/04/03 17:41:32 dries Exp $
 
 /**
  * @file
@@ -49,6 +49,7 @@ function drupal_lookup_path($action, $pa
   $map = &drupal_static(__FUNCTION__, array());
   $no_src = &drupal_static(__FUNCTION__ . ':no_src', array());
   $count = &drupal_static(__FUNCTION__ . ':count');
+  $map_cache = &drupal_static(__FUNCTION__ . ':map_cache', array());
 
   $path_language = $path_language ? $path_language : $language->language;
 
@@ -61,17 +62,53 @@ function drupal_lookup_path($action, $pa
     $map = array();
     $no_src = array();
     $count = NULL;
+    $map_cache = array();
+    cache_clear_all($path, 'cache_path', TRUE);
+    cache_clear_all('path:system:', 'cache_path', TRUE);
   }
   elseif ($count > 0 && $path != '') {
     if ($action == 'alias') {
+      // If the path is in memory, return it.
       if (isset($map[$path_language][$path])) {
         return $map[$path_language][$path];
       }
-      // Get the most fitting result falling back with alias without language
-      $alias = db_query("SELECT dst FROM {url_alias} WHERE src = :src AND language IN(:language, '') ORDER BY language DESC", array(
-        ':src' => $path,
-        ':language' => $path_language))
-        ->fetchField();
+
+      // During the first call to drupal_lookup_path() fetch as many paths
+      // as possible from cache.
+      if (empty($map_cache) && $map_cache !== FALSE) {
+        // First get the cache of system paths set for the current menu item.
+        $cid = 'path:system:' . current_path();
+        $cids = array();
+        if ($cache = cache_get($cid, 'cache_path')) {
+          $system_paths = $cache->data;
+          $cids = array();
+          foreach ($system_paths as $system_path) {
+            $cids[] = 'path:' . $path_language . ':' . $system_path;
+          }
+          // Now fetch all cached paths.
+          $map_cache = cache_get_multiple($cids, 'cache_path');
+        }
+        // If no paths were returned from cache, set $map_cache explicitly to
+        // FALSE.
+        $map_cache = $map_cache ? $map_cache : FALSE;
+      }
+
+      $cid = 'path:' . $path_language . ':' . $path;
+      if (isset($map_cache[$cid])) {
+        $alias = $map_cache[$cid]->data ? $map_cache[$cid]->data : FALSE;
+      }
+      else {
+        // Get the most fitting result falling back with alias without language
+        $alias = db_query("SELECT dst FROM {url_alias} WHERE src = :src AND language IN(:language, '') ORDER BY language DESC", array(
+          ':src' => $path,
+          ':language' => $path_language))
+          ->fetchField();
+        // Only cache path aliases if we attempted to fetch some from cache
+        // during this request.
+        if ($alias && $map_cache !== FALSE) {
+          cache_set($cid, $alias, 'cache_path');
+        }
+      }
       $map[$path_language][$path] = $alias;
       return $alias;
     }
@@ -103,11 +140,25 @@ function drupal_lookup_path($action, $pa
 }
 
 /**
+ * Cache system paths for a page.
+ */
+function drupal_cache_system_paths() {
+  $map = &drupal_static('drupal_lookup_path', array());
+  $map_cache = &drupal_static('drupal_lookup_path:map_cache', array());
+  if (!$map_cache && $item = menu_get_item()) {
+     // Generate a cache ID (cid) specific for this page.
+     $cid = 'path:system:' . current_path();
+     // Only store the system paths for this request.
+     if ($paths = current($map)) {
+       $data = array_keys($paths);
+       cache_set($cid, $data, 'cache_path');
+     }
+   }
+}
+
+/**
  * Given an internal Drupal path, return the alias set by the administrator.
  *
- * If no path is provided, the function will return the alias of the current
- * page.
- *
  * @param $path
  *   An internal Drupal path.
  * @param $path_language
Index: modules/path/path.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/path/path.module,v
retrieving revision 1.156
diff -u -p -r1.156 path.module
--- modules/path/path.module	22 Apr 2009 15:53:00 -0000	1.156
+++ modules/path/path.module	7 May 2009 22:40:33 -0000
@@ -114,7 +114,7 @@ function path_set_alias($path = NULL, $a
       db_query("DELETE FROM {url_alias} WHERE src = '%s'", $path);
     }
   }
-  drupal_clear_path_cache();
+  drupal_clear_path_cache($path);
 }
 
 /**
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.321
diff -u -p -r1.321 system.install
--- modules/system/system.install	7 May 2009 15:29:08 -0000	1.321
+++ modules/system/system.install	7 May 2009 22:40:38 -0000
@@ -606,6 +606,9 @@ function system_schema() {
   $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 aliases.';
+
   $schema['cache_registry'] = $schema['cache'];
   $schema['cache_registry']['description'] = 'Cache table for the code registry system to remember what code files need to be loaded on any given page.';
 
@@ -3439,6 +3442,21 @@ function system_update_7023() {
 }
 
 /**
+ * Create the cache_path table.
+ */
+function system_update_7024() {
+  $ret = array();
+  $schema['cache_path'] = drupal_get_schema_unprocessed('system', 'cache');
+  $schema['cache_path']['description'] = t('Cache table used to store path aliases.');
+  db_create_table($ret, 'cache_path', $schema['cache_path']);
+  return $ret;
+}
+
+
+
+
+
+/**
  * @} End of "defgroup updates-6.x-to-7.x"
  * The next series of updates should start at 8000.
  */
