From 9f33a091958d60f47ffd3ee3d9ca1691f547da19 Mon Sep 17 00:00:00 2001 From: Gordon Heydon Date: Fri, 7 Aug 2009 23:20:14 +1000 Subject: [PATCH] Restrict caching of Nodes to reduce memory #375494 - Increase limit to 30 to be inline with max number of nodes on a standard node page - Remove use of array_chunk() and array_slice() - Write tests to check the node cashe is acting as expected. - Fix up issue with single node_load() not moving the node to the head of the cache - Remove the defined variable NODE_LOAD_MAX_CACHE to a variable_get() --- modules/node/node.module | 21 +++++++++++--- modules/node/node.test | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 5 deletions(-) diff --git modules/node/node.module modules/node/node.module index c1f6ee0..a941b6e 100644 --- modules/node/node.module +++ modules/node/node.module @@ -809,11 +809,11 @@ function node_load_multiple($nids = array(), $conditions = array(), $reset = FAL $function = $module . '_node_load'; $function($queried_nodes, array_keys($typed_nodes)); } + + // Add the current nodes that came from the cache to the end of the + // nodes so they will get purged after the newly loaded nodes. + // This will give a sort of least recently used method for purging nodes. $nodes += $queried_nodes; - // Add nodes to the cache if we're not loading a revision. - if (!$vid) { - $node_cache += $queried_nodes; - } } // Ensure that the returned array is ordered the same as the original $nids @@ -826,7 +826,18 @@ function node_load_multiple($nids = array(), $conditions = array(), $reset = FAL } $nodes = $passed_nids; } - + + // Add nodes to the cache if we're not loading a revision. + if (!$vid) { + $node_cache = $nodes + $node_cache; + + // check if the cache is greater than the max cache size and purge + // the nodes at the bottom of the array as they are the least used. + if (count($node_cache) > variable_get('node_load_max_cache', 30)) { + $node_cache = array_slice($node_cache, 0, variable_get('node_load_max_cache', 30), TRUE); + } + } + return $nodes; } diff --git modules/node/node.test modules/node/node.test index 315d7c1..6c72b8e 100644 --- modules/node/node.test +++ modules/node/node.test @@ -840,3 +840,69 @@ class NodeAccessRebuildTestCase extends DrupalWebTestCase { $this->assertText(t('Content permissions have been rebuilt.')); } } + +/** + * Test restriction of the number of nodes to be held in the static cache. + */ +class NodeLoadRestrictionTestCase extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => 'Node restriction', + 'description' => 'Check cache size restriction of node_load() to only retain only NODE_LOAD_MAX_CACHE.', + 'group' => 'Node', + ); + } + + function testNodeRestrictions() { + for ($i = 0; $i < variable_get('node_load_max_cache', 30) + 10; $i ++) { + $node = $this->drupalCreateNode(array('type' => 'article')); + $node_keys[] = $node->nid; + } + + $node_cache = &drupal_static('node_load_multiple', array(), TRUE); + + // Over fill the node cache. + foreach ($node_keys as $nid) { + node_load($nid); + } + + // Check if the cache has too many nodes in it. + $this->assertTrue(count($node_cache) <= variable_get('node_load_max_cache', 30), t('The static node cache is less than or equal to the Maximum cache size')); + } +} + +/** + * Test restriction of the number of nodes to make sure the most used is at + * the beginning of the node cache and less likey to be removed. + */ +class NodeLoadPurgeOrderTestCase extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => 'Node restriction purge order', + 'description' => 'Check cashe size restriction of node_load() is moving the most recently loaded nodes to the beginning.', + 'group' => 'Node', + ); + } + + function testNodeRestrictionsPurgeOrder() { + for ($i = 0; $i < variable_get('node_load_max_cache', 30) + 10; $i ++) { + $node = $this->drupalCreateNode(array('type' => 'article')); + $node_keys[] = $node->nid; + } + + $popular_nid = array_shift($node_keys); + + drupal_static('node_load_multiple', array(), TRUE); + $node_cache = &drupal_static('node_load_multiple', array()); + + // Over fill the node cache. + foreach ($node_keys as $nid) { + node_load($nid); + node_load($popular_nid); + } + + $popular_node = reset($node_cache); + // Check if the cache has too many nodes in it. + $this->assertEqual($popular_node->nid, $popular_nid, t('The node at the top of the cache is the popular node')); + } +} -- 1.6.4.rc0.17.gd9eb0