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 21:21:01 -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 the items successfully returned from cache 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 21:21:03 -0000 @@ -1873,6 +1873,7 @@ function drupal_page_footer() { module_implements(MODULE_IMPLEMENTS_WRITE_CACHE); _registry_check_code(REGISTRY_WRITE_LOOKUP_CACHE); + drupal_cache_path_map(); } /** 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 21:21:03 -0000 @@ -1,5 +1,5 @@ language; @@ -64,14 +65,43 @@ function drupal_lookup_path($action, $pa } 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'); + } + $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(); + if ($alias) { + cache_set($cid, $alias, 'cache_path'); + } + } $map[$path_language][$path] = $alias; return $alias; } @@ -103,11 +133,25 @@ function drupal_lookup_path($action, $pa } /** + * Cache path mappings for a page. + */ +function drupal_cache_path_map() { + $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 ($map = current($map)) { + $data = array_keys($map); + 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/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 21:21:06 -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. */