Commit 61f4dfc9 authored by Dries's avatar Dries

- Patch #456824 by catch: add better caching to drupal_lookup_path().

parent 196da1b8
......@@ -43,6 +43,8 @@ Drupal 7.0, xxxx-xx-xx (development version)
- Performance:
* Improved performance on uncached page views by loading multiple core
objects in a single database query.
* Improved performance for logged-in users by reducing queries for path
alias lookups.
* Improved support for HTTP proxies (including reverse proxies), allowing
anonymous pageviews to be served entirely from the proxy.
- Documentation:
......
......@@ -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();
}
/**
......
......@@ -49,6 +49,9 @@ function drupal_lookup_path($action, $path = '', $path_language = '') {
$map = &drupal_static(__FUNCTION__, array());
$no_src = &drupal_static(__FUNCTION__ . ':no_src', array());
$count = &drupal_static(__FUNCTION__ . ':count');
$system_paths = &drupal_static(__FUNCTION__ . ':system_paths');
$no_aliases = &drupal_static(__FUNCTION__ . ':no_alias', array());
$first_call = &drupal_static(__FUNCTION__ . ':first_call', TRUE);
$path_language = $path_language ? $path_language : $language->language;
......@@ -61,19 +64,45 @@ function drupal_lookup_path($action, $path = '', $path_language = '') {
$map = array();
$no_src = array();
$count = NULL;
$system_paths = array();
$no_aliases = array();
}
elseif ($count > 0 && $path != '') {
if ($action == 'alias') {
// During the first call to drupal_lookup_path() per language, load the
// expected system paths for the page from cache.
if ($first_call) {
$first_call = FALSE;
$map[$path_language] = array();
// Load system paths from cache.
$cid = current_path();
if ($cache = cache_get($cid, 'cache_path')) {
$system_paths = $cache->data;
// Now fetch the aliases corresponding to these system paths.
// We order by ASC and overwrite array keys to ensure the correct
// alias is used when there are multiple aliases per path.
$map[$path_language] = db_query("SELECT src, dst FROM {url_alias} WHERE src IN(:system) AND language IN(:language, '') ORDER BY language ASC", array(
':system' => $system_paths,
':language' => $path_language
))->fetchAllKeyed();
// Keep a record of paths with no alias to avoid querying twice.
$no_aliases[$path_language] = array_flip(array_diff_key($system_paths, array_keys($map[$path_language])));
}
}
// If the alias has already been loaded, 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();
$map[$path_language][$path] = $alias;
return $alias;
// For system paths which were not cached, query aliases individually.
else if (!isset($no_aliases[$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();
$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
......@@ -102,6 +131,33 @@ function drupal_lookup_path($action, $path = '', $path_language = '') {
return FALSE;
}
/**
* Cache system paths for a page.
*
* Cache an array of the system paths available on each page. We assume
* that aiases will be needed for the majority of these paths during
* subsequent requests, and load them in a single query during
* drupal_lookup_path().
*/
function drupal_cache_system_paths() {
// Check if the system paths for this page were loaded from cache in this
// request to avoid writing to cache on every request.
$system_paths = &drupal_static('drupal_lookup_path:system_paths', array());
if (!$system_paths) {
// The static $map array used by drupal_lookup_path() includes all
// system paths for the page request.
$map = &drupal_static('drupal_lookup_path', array());
// Generate a cache ID (cid) specifically for this page.
$cid = current_path();
if ($paths = current($map)) {
$data = array_keys($paths);
$expire = REQUEST_TIME + (60 * 60 * 24);
cache_set($cid, $data, 'cache_path', $expire);
}
}
}
/**
* Given an internal Drupal path, return the alias set by the administrator.
*
......
......@@ -26,6 +26,31 @@ class PathTestCase extends DrupalWebTestCase {
$this->drupalLogin($web_user);
}
/**
* Test the path cache.
*/
function testPathCache() {
// Create test node.
$node1 = $this->drupalCreateNode();
// Create alias.
$edit = array();
$edit['src'] = 'node/' . $node1->nid;
$edit['dst'] = $this->randomName(8);
$this->drupalPost('admin/build/path/add', $edit, t('Create new alias'));
// Visit the system path for the node and confirm a cache entry is
// created.
cache_clear_all('*', 'cache_path', TRUE);
$this->drupalGet($edit['src']);
$this->assertTrue(cache_get($edit['src'], 'cache_path'), t('Cache entry was created.'));
// Visit the alias for the node and confirm a cache entry is created.
cache_clear_all('*', 'cache_path', TRUE);
$this->drupalGet($edit['dst']);
$this->assertTrue(cache_get($edit['src'], 'cache_path'), t('Cache entry was created.'));
}
/**
* Test alias functionality through the admin interfaces.
*/
......
......@@ -611,6 +611,8 @@ 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 alias lookup.';
$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.';
......@@ -3495,6 +3497,17 @@ function system_update_7023() {
return $ret;
}
/**
* 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 for path alias lookups.');
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.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment