=== modified file 'includes/common.inc'
--- includes/common.inc	2008-10-29 10:06:06 +0000
+++ includes/common.inc	2008-10-30 00:42:08 +0000
@@ -1610,6 +1610,7 @@ function drupal_page_footer() {
 
   registry_cache_hook_implementations(FALSE, TRUE);
   registry_cache_path_files();
+  drupal_lookup_path('footer');
 }
 
 /**

=== modified file 'includes/path.inc'
--- includes/path.inc	2008-10-14 11:01:08 +0000
+++ includes/path.inc	2008-10-30 00:44:51 +0000
@@ -11,14 +11,29 @@
  */
 
 /**
+ * Do not cache anything.
+ */
+define('PATH_CACHE_NONE', 0);
+
+/**
+ * Cache everything.
+ */
+define('PATH_CACHE_ALL', 1);
+
+/**
+ * Cache the aliases on page that seem unchanging.
+ */
+define('PATH_CACHE_ADAPTIVE', 2);
+
+/**
  * Initialize the $_GET['q'] variable to the proper normal path.
  */
 function drupal_init_path() {
   if (!empty($_GET['q'])) {
-    $_GET['q'] = drupal_get_normal_path(trim($_GET['q'], '/'));
+    $_GET['q'] = drupal_get_normal_path(trim($_GET['q'], '/'), '', TRUE);
   }
   else {
-    $_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));
+    $_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'), '', TRUE);
   }
 }
 
@@ -38,12 +53,14 @@ function drupal_init_path() {
  *   Optional language code to search the path with. Defaults to the page language.
  *   If there's no path defined for that language it will search paths without
  *   language.
+ * @param $first_call
+ *   TRUE to postpone adaptive cache initialization. Internal use only.
  *
  * @return
  *   Either a Drupal system path, an aliased path, or FALSE if no path was
  *   found.
  */
-function drupal_lookup_path($action, $path = '', $path_language = '') {
+function drupal_lookup_path($action, $path = '', $path_language = '', $first_call = FALSE) {
   global $language;
   // $map is an array with language keys, holding arrays of Drupal paths to alias relations
   static $map = array(), $no_src = array(), $count;
@@ -55,45 +72,122 @@ function drupal_lookup_path($action, $pa
     $count = db_result(db_query('SELECT COUNT(pid) FROM {url_alias}'));
   }
 
+  if (!$count) {
+    return FALSE;
+  }
+
+  $path_language = $path_language ? $path_language : $language->language;
+  $strategy = variable_get('path_strategy', PATH_CACHE_NONE);
+
+  if ($action == 'footer' && $strategy == PATH_CACHE_ADAPTIVE) {
+    $insert = db_insert('path_alias_statistics_map')->fields(array('page_path', 'language', 'src', 'dst'))->delayed();
+    foreach ($map as $path_language => $entry) {
+      foreach ($entry as $src => $dst) {
+        $insert->values(array('page_path' => $_GET['q'], 'language' => $path_language, 'src' => $src, 'dst' => $dst));
+      }
+    }
+    $insert->execute();
+    return;
+  }
+
+  if ($strategy == PATH_CACHE_ALL) {
+    return drupal_lookup_path_cached($action, $path, $path_language);
+  }
+  if (!$map && !$first_call && $strategy == PATH_CACHE_ADAPTIVE) {
+    $cache = cache_get($_GET['q'] .':'. $path_language, 'cache_path');
+    if ($cache) {
+      $map[$path_language] = $cache->data;
+    }
+    else {
+      $map[$path_language] = array();
+      $result = db_query("SELECT src, dst FROM {path_alias_map} WHERE page_path = '%s' AND language = '%s'", $_GET['q'], $path_language);
+      while ($pair = db_fetch_array($result)) {
+        $map[$path_language][$pair['src']] = $pair['dst'];
+      }
+      cache_set($_GET['q'] .':'. $path_language, $map[$path_language], 'cache_path');
+    }
+  }
   if ($action == 'wipe') {
     $map = array();
     $no_src = array();
-    $count = NULL;
-  }
-  elseif ($count > 0 && $path != '') {
-    if ($action == 'alias') {
-      if (isset($map[$path_language][$path])) {
-        return $map[$path_language][$path];
-      }
-      // Get the most fitting result falling back with alias without language
-      $alias = db_result(db_query("SELECT dst FROM {url_alias} WHERE src = '%s' AND language IN('%s', '') ORDER BY language DESC", $path, $path_language));
-      $map[$path_language][$path] = $alias;
-      return $alias;
-    }
-    // Check $no_src for this $path in case we've already determined that there
-    // isn't a path that has this alias
-    elseif ($action == 'source' && !isset($no_src[$path_language][$path])) {
-      // Look for the value $path within the cached $map
-      $src = '';
-      if (!isset($map[$path_language]) || !($src = array_search($path, $map[$path_language]))) {
-        // Get the most fitting result falling back with alias without language
-        if ($src = db_result(db_query("SELECT src FROM {url_alias} WHERE dst = '%s' AND language IN('%s', '') ORDER BY language DESC", $path, $path_language))) {
-          $map[$path_language][$src] = $path;
+    // @TODO: This is less than optimal: the path cache needs only be wiped
+    // if an alias changed (and then only for a specific language), but not
+    // upon creation or deletion.
+    cache_clear_all('*', 'cache_path', TRUE);
+    db_query('DELETE FROM {path_alias_map}');
+    db_query('DELETE FROM {path_alias_statistics_map}');
+    return FALSE;
+  }
+  elseif ($path != '') {
+    switch ($action) {
+      case 'alias':
+        if (isset($map[$path_language][$path])) {
+          return $map[$path_language][$path];
         }
-        else {
-          // We can't record anything into $map because we do not have a valid
-          // index and there is no need because we have not learned anything
-          // about any Drupal path. Thus cache to $no_src.
-          $no_src[$path_language][$path] = TRUE;
+        // Get the most fitting result falling back with alias without language
+        $alias = db_result(db_query("SELECT dst FROM {url_alias} WHERE src = '%s' AND language IN ('%s', '') ORDER BY language DESC", $path, $path_language));
+        $map[$path_language][$path] = $alias;
+        return $alias;
+      case 'source':
+        // Check $no_src for this $path in case we've already determined that there
+        // isn't a path that has this alias
+        if (!isset($no_src[$path_language][$path])) {
+          // Look for the value $path within the cached $map
+          $src = '';
+          if (!isset($map[$path_language]) || !($src = array_search($path, $map[$path_language]))) {
+            // Get the most fitting result falling back with alias without language
+            if ($src = db_result(db_query("SELECT src FROM {url_alias} WHERE dst = '%s' AND language IN ('%s', '') ORDER BY language DESC", $path, $path_language))) {
+              $map[$path_language][$src] = $path;
+            }
+            else {
+              // We can't record anything into $map because we do not have a valid
+              // index and there is no need because we have not learned anything
+              // about any Drupal path. Thus cache to $no_src.
+              $no_src[$path_language][$path] = TRUE;
+            }
+          }
+          return $src;
         }
+        break;
+    }
+  }
+  return FALSE;
+}
+
+function drupal_lookup_path_cached($action, $path, $path_language) {
+  static $map = array();
+  if ($action == 'wipe') {
+    // @TODO: see drupal_lookup_path wipe.
+    $map = array();
+    cache_clear_all('*', 'cache_path', TRUE);
+    return FALSE;
+  }
+  if (empty($map)) {
+    $cache = cache_get('path', 'cache_path');
+    if ($cache) {
+      $map = $cache->data;
+    }
+    else {
+      $map = array();
+      $result = db_query("SELECT src, dst, language FROM {url_alias}");
+      while ($url_alias = db_fetch_object($result)) {
+        $map[$url_alias->language][$url_alias->src] = $url_alias->dst;
       }
+      cache_set('path', $map, 'cache_path');
+    }
+  }
+  foreach (array($path_language, '') as $language) {
+    if ($action == 'alias' && isset($map[$language][$path])) {
+      return $map[$language][$path];
+    }
+    if ($action == 'source' && isset($map[$language]) && ($src = array_search($path, $map[$language]))) {
       return $src;
     }
   }
-
   return FALSE;
 }
 
+
 /**
  * Given an internal Drupal path, return the alias set by the administrator.
  *
@@ -121,14 +215,16 @@ function drupal_get_path_alias($path, $p
  *   A Drupal path alias.
  * @param $path_language
  *   An optional language code to look up the path in.
+ * @param $first_call
+ *   TRUE to postpone adaptive cache initialization. Internal use only.
  *
  * @return
  *   The internal path represented by the alias, or the original alias if no
  *   internal path was found.
  */
-function drupal_get_normal_path($path, $path_language = '') {
+function drupal_get_normal_path($path, $path_language = '', $first_call = FALSE) {
   $result = $path;
-  if ($src = drupal_lookup_path('source', $path, $path_language)) {
+  if ($src = drupal_lookup_path('source', $path, $path_language, $first_call)) {
     $result = $src;
   }
   if (function_exists('custom_url_rewrite_inbound')) {

=== modified file 'modules/path/path.admin.inc'
--- modules/path/path.admin.inc	2008-10-13 00:33:01 +0000
+++ modules/path/path.admin.inc	2008-10-30 00:42:08 +0000
@@ -238,3 +238,25 @@ function path_admin_filter_get_keys() {
   $path = explode('/', $_GET['q'], 5);
   return count($path) == 5 ? $path[4] : '';
 }
+
+function path_form_system_performance_settings_alter(&$form) {
+  $options = array(
+    PATH_CACHE_NONE => t('Disabled'),
+    PATH_CACHE_ALL => t('Cache all aliases on each page (not recommended for sites with a large number of aliases).'),
+    PATH_CACHE_ADAPTIVE => t('Cache aliases that appear to change infrequently.'),
+  );
+
+  $form['path_cache'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Path alias cache'),
+    '#description' => t('Path alias caching can significantly reduce the number of database queries on each page load. If the page cache is also enabled, performance increases from enabling the path alias cache will mainly benefit authenticated users.'),
+    '#weight' => -35,
+  );
+
+  $form['path_cache']['path_cache'] = array(
+    '#type' => 'radios',
+    '#title' => 'Caching',
+    '#options' => $options,
+    '#default_value' => variable_get('path_strategy', PATH_CACHE_NONE),
+  );
+}

=== modified file 'modules/path/path.module'
--- modules/path/path.module	2008-10-12 04:30:05 +0000
+++ modules/path/path.module	2008-10-30 00:42:08 +0000
@@ -234,3 +234,11 @@ function path_perm() {
 function path_load($pid) {
   return db_fetch_array(db_query('SELECT * FROM {url_alias} WHERE pid = %d', $pid));
 }
+
+function path_cron() {
+  db_query_temporary('SELECT page_path, language, :path_cutoff * MAX(c) AS cutoff FROM (SELECT page_path, language, COUNT(*) AS c FROM {path_alias_statistics_map} GROUP BY page_path, language, src, dst) AS x GROUP BY page_path, language', array('path_cutoff' => variable_get('path_cutoff', .6)), 'page_cutoff');
+  db_query("ALTER TABLE page_cutoff ADD KEY path_language (page_path, language)");
+  db_query('DELETE FROM {path_alias_map}');
+  db_query('INSERT INTO {path_alias_map} (page_path, language, src, dst) SELECT page_path, language, src, dst FROM {path_alias_statistics_map} p GROUP BY page_path, language, src, dst HAVING COUNT(*) > (SELECT cutoff FROM page_cutoff pc WHERE pc.page_path = p.page_path AND pc.language = p.language)');
+  db_query('DELETE FROM {path_alias_statistics_map}');
+}

=== modified file 'modules/path/path.test'
--- modules/path/path.test	2008-10-13 20:57:19 +0000
+++ modules/path/path.test	2008-10-30 00:42:08 +0000
@@ -2,14 +2,6 @@
 // $Id: path.test,v 1.4 2008/10/13 20:57:19 dries Exp $
 
 class PathTestCase extends DrupalWebTestCase {
-  function getInfo() {
-    return array(
-      'name' => t('Path alias functionality'),
-      'description' => t('Add, edit, delete, and change alias and verify its consistency in the database.'),
-      'group' => t('Path'),
-    );
-  }
-
   /**
    * Create user, setup permissions, log user in, and create a node.
    */
@@ -21,9 +13,9 @@ class PathTestCase extends DrupalWebTest
   }
 
   /**
-   * Test alias functionality through the admin interfaces.
+   * Test alias functionality through the admin interfaces for a path caching type.
    */
-  function testAdminAlias() {
+  function checkAdminAlias($type) {
     // create test node
     $node1 = $this->createNode();
 
@@ -35,7 +27,7 @@ class PathTestCase extends DrupalWebTest
 
     // Confirm that the alias works.
     $this->drupalGet($edit['dst']);
-    $this->assertText($node1->title, 'Alias works.');
+    $this->assertText($node1->title, t('@type: Alias works.', array('@type' => $type)));
 
     // Change alias.
     $pid = $this->getPID($edit['dst']);
@@ -46,11 +38,11 @@ class PathTestCase extends DrupalWebTest
 
     // Confirm that the alias works.
     $this->drupalGet($edit['dst']);
-    $this->assertText($node1->title, 'Changed alias works.');
+    $this->assertText($node1->title, t('@type: Changed alias works.', array('@type' => $type)));
 
     // Confirm that previous alias no longer works.
     $this->drupalGet($previous);
-    $this->assertNoText($node1->title, 'Previous alias no longer works.');
+    $this->assertNoText($node1->title, t('@type: Previous alias no longer works.', array('@type' => $type)));
     $this->assertResponse(404);
 
     // Create second test node.
@@ -69,13 +61,13 @@ class PathTestCase extends DrupalWebTest
 
     // Confirm that the alias no longer works.
     $this->drupalGet($edit['dst']);
-    $this->assertNoText($node1->title, 'Alias was successfully deleted.');
+    $this->assertNoText($node1->title, t('@type: Alias was successfully deleted.', array('@type' => $type)));
   }
 
   /**
    * Test alias functionality through the node interfaces.
    */
-  function testNodeAlias() {
+  function checkNodeAlias($type) {
     // Create test node.
     $node1 = $this->createNode();
 
@@ -86,7 +78,7 @@ class PathTestCase extends DrupalWebTest
 
     // Confirm that the alias works.
     $this->drupalGet($edit['path']);
-    $this->assertText($node1->title, 'Alias works.');
+    $this->assertText($node1->title, t('@type: Alias works.', array('@type' => $type)));
 
     // Change alias.
     $previous = $edit['path'];
@@ -95,11 +87,11 @@ class PathTestCase extends DrupalWebTest
 
     // Confirm that the alias works.
     $this->drupalGet($edit['path']);
-    $this->assertText($node1->title, 'Changed alias works.');
+    $this->assertText($node1->title, t('@type: Changed alias works.', array('@type' => $type)));
 
     // Make sure that previous alias no longer works.
     $this->drupalGet($previous);
-    $this->assertNoText($node1->title, 'Previous alias no longer works.');
+    $this->assertNoText($node1->title, t('@type: Previous alias no longer works.', array('@type' => $type)));
     $this->assertResponse(404);
 
     // Create second test node.
@@ -110,14 +102,14 @@ class PathTestCase extends DrupalWebTest
     $this->drupalPost('node/' . $node2->nid . '/edit', $edit, t('Save'));
 
     // Confirm that the alias didn't make a duplicate.
-    $this->assertText(t('The path is already in use.'), 'Attempt to moved alias was rejected.');
+    $this->assertText(t('The path is already in use.'), t('@type: Attempt to moved alias was rejected.', array('@type' => $type)));
 
     // Delete alias.
     $this->drupalPost('node/' . $node1->nid . '/edit', array('path' => ''), t('Save'));
 
     // Confirm that the alias no longer works.
     $this->drupalGet($edit['path']);
-    $this->assertNoText($node1->title, 'Alias was successfully deleted.');
+    $this->assertNoText($node1->title, t('@type: Alias was successfully deleted.', array('@type' => $type)));
   }
 
   function getPID($dst) {

=== modified file 'modules/system/system.admin.inc'
--- modules/system/system.admin.inc	2008-10-16 20:23:08 +0000
+++ modules/system/system.admin.inc	2008-10-30 00:42:08 +0000
@@ -1337,6 +1337,7 @@ function system_performance_settings() {
     '#type' => 'fieldset',
     '#title' => t('Page cache'),
     '#description' => t('Enabling the page cache will offer a significant performance boost. Drupal can store and send compressed cached pages requested by <em>anonymous</em> users. By caching a web page, Drupal does not have to construct the page each time it is viewed.'),
+    '#weight' => -50,
   );
 
   $form['page_cache']['cache'] = array(
@@ -1368,6 +1369,7 @@ function system_performance_settings() {
     '#type' => 'fieldset',
     '#title' => t('Block cache'),
     '#description' => t('Enabling the block cache can offer a performance increase for all users by preventing blocks from being reconstructed on each page load. If the page cache is also enabled, performance increases from enabling the block cache will mainly benefit authenticated users.'),
+    '#weight' => -40
   );
 
   $form['block_cache']['block_cache'] = array(
@@ -1382,7 +1384,8 @@ function system_performance_settings() {
   $form['bandwidth_optimizations'] = array(
     '#type' => 'fieldset',
     '#title' => t('Bandwidth optimizations'),
-    '#description' => '<p>' . t('Drupal can automatically optimize external resources like CSS and JavaScript, which can reduce both the size and number of requests made to your website. CSS files can be aggregated and compressed into a single file, while JavaScript files are aggregated (but not compressed). These optional optimizations may reduce server load, bandwidth requirements, and page loading times.') . '</p><p>' . t('These options are disabled if you have not set up your files directory, or if your download method is set to private.') . '</p>'
+    '#description' => '<p>' . t('Drupal can automatically optimize external resources like CSS and JavaScript, which can reduce both the size and number of requests made to your website. CSS files can be aggregated and compressed into a single file, while JavaScript files are aggregated (but not compressed). These optional optimizations may reduce server load, bandwidth requirements, and page loading times.') . '</p><p>' . t('These options are disabled if you have not set up your files directory, or if your download method is set to private.') . '</p>',
+    '#weight' => -30,
   );
 
   $directory = file_directory_path();
@@ -1408,6 +1411,7 @@ function system_performance_settings() {
     '#type' => 'fieldset',
     '#title' => t('Clear cached data'),
     '#description' => t('Caching data improves performance, but may cause problems while troubleshooting new modules, themes, or translations, if outdated information has been cached. To refresh all cached data on your site, click the button below. <em>Warning: high-traffic sites will experience performance slowdowns while cached data is rebuilt.</em>'),
+    '#weight' => -20,
   );
 
   $form['clear_cache']['clear'] = array(

=== modified file 'modules/system/system.install'
--- modules/system/system.install	2008-10-13 20:29:42 +0000
+++ modules/system/system.install	2008-10-30 00:42:08 +0000
@@ -619,10 +619,10 @@ function system_schema() {
 
   $schema['cache_form'] = $schema['cache'];
   $schema['cache_form']['description'] = t('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'] = t('Cache table used to store compressed pages for anonymous users, if page caching is enabled.');
   $schema['cache_menu'] = $schema['cache'];
   $schema['cache_menu']['description'] = t('Cache table for the menu system to store router information as well as generated link trees for various menu/page/user combinations.');
+  $schema['cache_page'] = $schema['cache'];
+  $schema['cache_page']['description'] = t('Cache table used to store compressed pages for anonymous users, if page caching is enabled.');
   $schema['cache_registry'] = $schema['cache'];
   $schema['cache_registry']['description'] = t('Cache table for the code registry system to remember what code files need to be loaded on any given page.');
 
@@ -3072,6 +3072,28 @@ function system_update_7011() {
 }
 
 /**
+ * Create the cache_path table.
+ */
+function system_update_7012() {
+  $ret = array();
+  $schema['cache_path'] = array(
+    'fields' => array(
+      'cid'        => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'data'       => array('type' => 'blob', 'not null' => FALSE, 'size' => 'big'),
+      'expire'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+      'created'    => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+      'headers'    => array('type' => 'text', 'not null' => FALSE),
+      'serialized' => array('type' => 'int', 'size' => 'small', 'not null' => TRUE, 'default' => 0)
+    ),
+    'indexes' => array('expire' => array('expire')),
+    'primary key' => array('cid'),
+  );
+  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.
  */

