Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.1068 diff -u -p -r1.1068 common.inc --- includes/common.inc 22 Dec 2009 14:47:14 -0000 1.1068 +++ includes/common.inc 23 Dec 2009 17:59:32 -0000 @@ -6297,10 +6297,11 @@ function entity_get_info($entity_type = 'fieldable' => FALSE, 'controller class' => 'DrupalDefaultEntityController', 'static cache' => TRUE, + 'entity cache' => FALSE, 'load hook' => $name . '_load', 'bundles' => array(), 'object keys' => array(), - 'cacheable' => TRUE, + 'field cache' => TRUE, 'translation' => array(), ); $entity_info[$name]['object keys'] += array( @@ -6354,8 +6355,8 @@ function entity_extract_ids($entity_type // If no bundle key provided, then we assume a single bundle, named after the // entity type. $bundle = $info['object keys']['bundle'] ? $entity->{$info['object keys']['bundle']} : $entity_type; - $cacheable = $info['cacheable']; - return array($id, $vid, $bundle, $cacheable); + $field_cache = $info['field cache']; + return array($id, $vid, $bundle, $field_cache); } /** @@ -6420,7 +6421,7 @@ function entity_create_stub_entity($enti */ function entity_load($entity_type, $ids = array(), $conditions = array(), $reset = FALSE) { if ($reset) { - entity_get_controller($entity_type)->resetCache(); + entity_get_controller($entity_type)->resetCache($ids); } return entity_get_controller($entity_type)->load($ids, $conditions); } Index: includes/entity.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/entity.inc,v retrieving revision 1.4 diff -u -p -r1.4 entity.inc --- includes/entity.inc 8 Dec 2009 06:33:11 -0000 1.4 +++ includes/entity.inc 23 Dec 2009 17:59:32 -0000 @@ -24,7 +24,17 @@ interface DrupalEntityControllerInterfac /** * Reset the internal, static entity cache. */ - public function resetCache(); + public function resetStaticCache(); + + /** + * Clear the persistent cache for an entity. + * + * @param $ids + * A single entity ID or array of IDs, if present clear the entity cache for + * these specific entities. If no argument is given, the entire bin + * specified in hook_entity_info() will be flushed. + */ + public function resetCache($id = NULL); /** * Load one or more entities. @@ -48,7 +58,8 @@ interface DrupalEntityControllerInterfac */ class DrupalDefaultEntityController implements DrupalEntityControllerInterface { - protected $entityCache; + protected $entityStaticCache; + protected $entityPersistentCache; protected $entityType; protected $entityInfo; protected $hookLoadArguments; @@ -63,7 +74,7 @@ class DrupalDefaultEntityController impl public function __construct($entityType) { $this->entityType = $entityType; $this->entityInfo = entity_get_info($entityType); - $this->entityCache = array(); + $this->entityStaticCache = array(); $this->hookLoadArguments = array(); $this->idKey = $this->entityInfo['object keys']['id']; @@ -77,11 +88,38 @@ class DrupalDefaultEntityController impl } // Check if the entity type supports static caching of loaded entities. - $this->cache = !empty($this->entityInfo['static cache']); + $this->staticCache = !empty($this->entityInfo['static cache']); + // Check if the entity type supports persistent caching if loaded entities. + $this->persistentCache = !empty($this->entityInfo['entity cache']); } - public function resetCache() { - $this->entityCache = array(); + public function resetStaticCache() { + $this->staticCache = array(); + } + + public function resetCache($ids = NULL) { + // Only attempt to clear the persistent cache if this entity type uses it. + if ($this->persistentCache) { + // For consistency with cache_clear_all(), we allow either a single ID + // or an array of IDS. + if (isset($ids)) { + $ids = is_numeric($ids) ? array($ids) : $ids; + foreach ($ids as $id) { + $cids[] = $this->entityType . ':' . $id; + $wildcard = FALSE; + } + } + // If no IDs are given, do a full cache bin flush. + else { + $cids = '*'; + $wildcard = TRUE; + } + $bin = $this->entityInfo['entity cache bin']; + + cache_clear_all($cids, $bin, $wildcard); + } + // Clear the static cache whenever this is called. + $this->resetStaticCache(); } public function load($ids = array(), $conditions = array()) { @@ -108,17 +146,35 @@ class DrupalDefaultEntityController impl $passed_ids = !empty($this->ids) ? array_flip($this->ids) : FALSE; // Try to load entities from the static cache, if the entity type supports // static caching. - if ($this->cache) { - $entities += $this->cacheGet($this->ids, $this->conditions); + if ($this->staticCache) { + $entities += $this->staticCacheGet($this->ids, $this->conditions); // If any entities were loaded, remove them from the ids still to load. if ($passed_ids) { $this->ids = array_keys(array_diff_key($passed_ids, $entities)); } } + // Attempt to load any remaining entities from the persistent cache. + $cached_entities = array(); + + $cid_prefix = $this->entityType . ':'; + if ($this->persistentCache && $this->ids && !$this->conditions && !$this->revisionId) { + foreach ($this->ids as $id) { + $cids[] = $cid_prefix . $id; + } + if ($cached = cache_get_multiple($cids, $this->entityInfo['entity cache bin'])) { + foreach ($cached as $item) { + $id = str_replace($cid_prefix, '', $item->cid); + $cached_entities[$id] = $item->data; + } + $this->ids = array_diff($this->ids, array_keys($cached_entities)); + } + } + // Load any remaining entities from the database. This is the case if $ids // is set to FALSE (so we load all entities), if there are any ids left to // load, if loading a revision, or if $conditions was passed without $ids. + $queried_entities = array(); if ($this->ids === FALSE || $this->ids || $this->revisionId || ($this->conditions && !$passed_ids)) { // Build the query. $this->buildQuery(); @@ -132,15 +188,32 @@ class DrupalDefaultEntityController impl // entity type specific load callback, for example hook_node_load(). if (!empty($queried_entities)) { $this->attachLoad($queried_entities); - $entities += $queried_entities; + // If these entities can be persistently cached, do so now. + if ($this->persistentCache && !$this->revisionId) { + foreach ($queried_entities as $item) { + cache_set($cid_prefix . $item->{$this->idKey}, $item, $this->entityInfo['entity cache bin']); + } + } } - if ($this->cache) { - // Add entities to the cache if we are not loading a revision. - if (!empty($queried_entities) && !$this->revisionId) { - $this->cacheSet($queried_entities); + // Now that attachLoad() has been run, merge in entities loaded from cache + // and those from the database into a single variable. + $new_entities = $queried_entities + $cached_entities; + + // Allow modules to act on entities without the result being persistently + // cached. + if (!empty($new_entities)) { + $this->attachAfterLoad($new_entities); + if ($this->staticCache) { + // Add entities to the cache if we are not loading a revision. + if (!empty($new_entities) && !$this->revisionId) { + $this->staticCacheSet($new_entities); + } } } + // Merge all entities to be returned from this call into the same array + // now that all hooks have run. + $entities += $new_entities; // Ensure that the returned array is ordered the same as the original // $ids array if this was passed in and remove any invalid ids. @@ -257,6 +330,27 @@ class DrupalDefaultEntityController impl } /** + * Attach data to entities after loading. + * + * Invokes hook_TYPE_load_uncached() to allow modules to interact with + * entity objects without the result being persistently cached. + * + * If your hook_TYPE_load() expects special parameters apart from the + * queried entities, you can set $this->hookLoadArguments prior to + * calling the method. See NodeController::attachLoad() for an example. + */ + protected function attachAfterLoad(&$entities) { + // Call hook_TYPE_load(). The first argument for hook_TYPE_load() are + // always the queried entities, followed by additional arguments set in + // $this->hookLoadArguments. + $args = array_merge(array($entities), $this->hookLoadArguments); + foreach (module_implements($this->entityInfo['load hook'] . '_uncached') as $module) { + call_user_func_array($module . '_' . $this->entityInfo['load hook'] . '_uncached', $args); + } + } + + + /** * Get entities from the static cache. * * @param $ids @@ -264,17 +358,17 @@ class DrupalDefaultEntityController impl * @param $conditions * If set, return entities that match all of these conditions. */ - protected function cacheGet($ids, $conditions = array()) { + protected function staticCacheGet($ids, $conditions = array()) { $entities = array(); // Load any available entities from the internal cache. - if (!empty($this->entityCache) && !$this->revisionId) { + if (!empty($this->entityStaticCache) && !$this->revisionId) { if ($ids) { - $entities += array_intersect_key($this->entityCache, array_flip($ids)); + $entities += array_intersect_key($this->entityStaticCache, array_flip($ids)); } // If loading entities only by conditions, fetch all available entities // from the cache. Entities which don't match are removed later. elseif ($conditions) { - $entities = $this->entityCache; + $entities = $this->entityStaticCache; } } @@ -294,7 +388,7 @@ class DrupalDefaultEntityController impl /** * Store entities in the static entity cache. */ - protected function cacheSet($entities) { - $this->entityCache += $entities; + protected function staticCacheSet($entities) { + $this->entityStaticCache += $entities; } } Index: includes/file.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/file.inc,v retrieving revision 1.199 diff -u -p -r1.199 file.inc --- includes/file.inc 5 Nov 2009 03:37:08 -0000 1.199 +++ includes/file.inc 23 Dec 2009 17:59:33 -0000 @@ -490,6 +490,7 @@ function file_save(stdClass $file) { drupal_write_record('file', $file, 'fid'); // Inform modules that the file has been updated. module_invoke_all('file_update', $file); + entity_get_controller('file')->resetCache($file->fid); } return $file; @@ -937,6 +938,7 @@ function file_delete(stdClass $file, $fo // Let other modules clean up any references to the deleted file. module_invoke_all('file_delete', $file); + entity_get_controller('file')->resetCache($file->fid); // Make sure the file is deleted before removing its row from the // database, so UIs can still find the file in the database. Index: modules/book/book.module =================================================================== RCS file: /cvs/drupal/drupal/modules/book/book.module,v retrieving revision 1.531 diff -u -p -r1.531 book.module --- modules/book/book.module 21 Dec 2009 13:47:31 -0000 1.531 +++ modules/book/book.module 23 Dec 2009 17:59:33 -0000 @@ -744,9 +744,9 @@ function book_menu_name($bid) { } /** - * Implements hook_node_load(). + * Implements hook_node_load_uncached(). */ -function book_node_load($nodes, $types) { +function book_node_load_uncached($nodes, $types) { $result = db_query("SELECT * FROM {book} b INNER JOIN {menu_links} ml ON b.mlid = ml.mlid WHERE b.nid IN (:nids)", array(':nids' => array_keys($nodes)), array('fetch' => PDO::FETCH_ASSOC)); foreach ($result as $record) { $nodes[$record['nid']]->book = $record; Index: modules/comment/comment.install =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment.install,v retrieving revision 1.55 diff -u -p -r1.55 comment.install --- modules/comment/comment.install 8 Dec 2009 06:52:38 -0000 1.55 +++ modules/comment/comment.install 23 Dec 2009 17:59:33 -0000 @@ -215,6 +215,15 @@ function comment_update_7011() { } /** + * Add the {cache_comment} table. + */ +function comment_update_7012() { + $schema['cache_comment'] = drupal_get_schema_unprocessed('system', 'cache'); + $schema['cache_comment']['description'] = 'Cache table used for taxonomy terms and vocabularies.'; + db_create_table('cache_comment', $schema['cache_comment']); +} + +/** * @} End of "defgroup updates-6.x-to-7.x" * The next series of updates should start at 8000. */ @@ -395,5 +404,8 @@ function comment_schema() { ), ); + $schema['cache_comment'] = drupal_get_schema_unprocessed('system', 'cache'); + $schema['cache_comment']['description'] = 'Cache table used for comments.'; + return $schema; } Index: modules/comment/comment.module =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v retrieving revision 1.820 diff -u -p -r1.820 comment.module --- modules/comment/comment.module 22 Dec 2009 20:38:23 -0000 1.820 +++ modules/comment/comment.module 23 Dec 2009 17:59:34 -0000 @@ -108,6 +108,9 @@ function comment_entity_info() { ), 'bundles' => array(), 'static cache' => FALSE, + 'field cache' => FALSE, + 'entity cache' => TRUE, + 'entity cache bin' => 'cache_comment', ), ); @@ -1311,6 +1314,7 @@ function comment_save($comment) { module_invoke_all('comment_update', $comment); // Add an entry to the watchdog log. watchdog('content', 'Comment: updated %subject.', array('%subject' => $comment->subject), WATCHDOG_NOTICE, l(t('view'), 'comment/' . $comment->cid, array('fragment' => 'comment-' . $comment->cid))); + entity_get_controller('comment')->resetCache($comment->cid); } else { // Add the comment to database. This next section builds the thread field. @@ -1443,6 +1447,7 @@ function comment_delete_multiple($cids) $child_cids = db_query('SELECT cid FROM {comment} WHERE pid = :cid', array(':cid' => $comment->cid))->fetchCol(); comment_delete_multiple($child_cids); _comment_update_node_statistics($comment->nid); + entity_get_controller('comment')->resetCache($comment->cid); } } } @@ -2255,6 +2260,8 @@ function _comment_update_node_statistics ->condition('nid', $nid) ->execute(); } + // Clear the cache for this node. + entity_get_controller('node')->resetCache($nid); } /** Index: modules/field/field.attach.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/field/field.attach.inc,v retrieving revision 1.66 diff -u -p -r1.66 field.attach.inc --- modules/field/field.attach.inc 21 Dec 2009 13:47:32 -0000 1.66 +++ modules/field/field.attach.inc 23 Dec 2009 17:59:34 -0000 @@ -540,7 +540,7 @@ function field_attach_load($obj_type, $o $info = entity_get_info($obj_type); // Only the most current revision of non-deleted fields for // cacheable fieldable types can be cached. - $cache_read = $load_current && $info['cacheable'] && empty($options['deleted']); + $cache_read = $load_current && $info['field cache'] && empty($options['deleted']); // In addition, do not write to the cache when loading a single field. $cache_write = $cache_read && !isset($options['field_id']); @@ -821,7 +821,7 @@ function field_attach_insert($obj_type, _field_invoke_default('insert', $obj_type, $object); _field_invoke('insert', $obj_type, $object); - list($id, $vid, $bundle, $cacheable) = entity_extract_ids($obj_type, $object); + list($id, $vid, $bundle, $field_cache) = entity_extract_ids($obj_type, $object); // Let any module insert field data before the storage engine, accumulating // saved fields along the way. @@ -854,7 +854,7 @@ function field_attach_insert($obj_type, // Let other modules act on inserting the object. module_invoke_all('field_attach_insert', $obj_type, $object); - if ($cacheable) { + if ($field_cache) { cache_clear_all("field:$obj_type:$id", 'cache_field'); } } @@ -870,7 +870,7 @@ function field_attach_insert($obj_type, function field_attach_update($obj_type, $object) { _field_invoke('update', $obj_type, $object); - list($id, $vid, $bundle, $cacheable) = entity_extract_ids($obj_type, $object); + list($id, $vid, $bundle, $field_cache) = entity_extract_ids($obj_type, $object); // Let any module update field data before the storage engine, accumulating // saved fields along the way. @@ -907,7 +907,7 @@ function field_attach_update($obj_type, // Let other modules act on updating the object. module_invoke_all('field_attach_update', $obj_type, $object); - if ($cacheable) { + if ($field_cache) { cache_clear_all("field:$obj_type:$id", 'cache_field'); } } Index: modules/field/tests/field_test.entity.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/field/tests/field_test.entity.inc,v retrieving revision 1.1 diff -u -p -r1.1 field_test.entity.inc --- modules/field/tests/field_test.entity.inc 20 Nov 2009 23:29:28 -0000 1.1 +++ modules/field/tests/field_test.entity.inc 23 Dec 2009 17:59:34 -0000 @@ -19,7 +19,7 @@ function field_test_entity_info() { 'revision' => 'ftvid', 'bundle' => 'fttype', ), - 'cacheable' => FALSE, + 'field cache' => FALSE, 'bundles' => $bundles, 'fieldable' => TRUE, ), @@ -32,7 +32,7 @@ function field_test_entity_info() { 'bundle' => 'fttype', ), 'fieldable' => TRUE, - 'cacheable' => TRUE, + 'field cache' => TRUE, 'bundles' => $bundles, ), ); Index: modules/locale/locale.module =================================================================== RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v retrieving revision 1.275 diff -u -p -r1.275 locale.module --- modules/locale/locale.module 7 Dec 2009 05:02:37 -0000 1.275 +++ modules/locale/locale.module 23 Dec 2009 17:59:35 -0000 @@ -380,7 +380,7 @@ function locale_form_path_admin_form_alt * Implements hook_form_FORM_ID_alter(). */ function locale_form_node_type_form_alter(&$form, &$form_state) { - if (isset($form['identity']['type'])) { + if (isset($form['type'])) { $form['workflow']['language_content_type'] = array( '#type' => 'radios', '#title' => t('Multilingual support'), Index: modules/node/node.install =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.install,v retrieving revision 1.37 diff -u -p -r1.37 node.install --- modules/node/node.install 4 Dec 2009 16:49:46 -0000 1.37 +++ modules/node/node.install 23 Dec 2009 17:59:35 -0000 @@ -353,6 +353,9 @@ function node_schema() { 'primary key' => array('type'), ); + $schema['cache_node'] = drupal_get_schema_unprocessed('system', 'cache'); + $schema['cache_node']['description'] = 'Cache table used for nodes.'; + return $schema; } @@ -576,6 +579,16 @@ function node_update_7009() { } /** + * Add the {cache_node} table. + */ +function node_update_7010() { + // Add the cache_path table. + $schema['cache_node'] = drupal_get_schema_unprocessed('system', 'cache'); + $schema['cache_node']['description'] = 'Cache table used for nodes.'; + db_create_table('cache_node', $schema['cache_node']); +} + +/** * @} End of "defgroup updates-6.x-to-7.x" * The next series of updates should start at 8000. */ Index: modules/node/node.module =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.module,v retrieving revision 1.1188 diff -u -p -r1.1188 node.module --- modules/node/node.module 22 Dec 2009 20:38:23 -0000 1.1188 +++ modules/node/node.module 23 Dec 2009 17:59:37 -0000 @@ -192,6 +192,9 @@ function node_entity_info() { 'controller class' => 'NodeController', 'base table' => 'node', 'revision table' => 'node_revision', + 'entity cache bin' => 'cache_node', + 'entity cache' => TRUE, + 'field cache' => FALSE, 'fieldable' => TRUE, 'object keys' => array( 'id' => 'nid', @@ -1053,6 +1056,11 @@ function node_save($node) { // Update the node access table for this node. node_access_acquire_grants($node); + // Clear the entity cache. + if (!$node->is_new) { + entity_get_controller('node')->resetCache($node->nid); + } + // Clear internal properties. unset($node->is_new); @@ -1132,8 +1140,7 @@ function node_delete_multiple($nids) { } // Clear the page and block and node_load_multiple caches. - cache_clear_all(); - entity_get_controller('node')->resetCache(); + entity_get_controller('node')->resetCache($nids); } } @@ -3290,4 +3297,15 @@ class NodeController extends DrupalDefau $this->hookLoadArguments[] = array_keys($typed_nodes); parent::attachLoad($nodes); } + + protected function attachAfterLoad(&$nodes) { + // Create an array of content types and pass this to the + // object type specific callback. + $types = array(); + foreach ($nodes as $object) { + $types[$object->type] = $object->type; + } + $this->hookLoadArguments[] = $types; + parent::attachAfterLoad($nodes); + } } Index: modules/poll/poll.module =================================================================== RCS file: /cvs/drupal/drupal/modules/poll/poll.module,v retrieving revision 1.329 diff -u -p -r1.329 poll.module --- modules/poll/poll.module 14 Dec 2009 20:38:15 -0000 1.329 +++ modules/poll/poll.module 23 Dec 2009 17:59:37 -0000 @@ -433,7 +433,6 @@ function poll_node_prepare_translation($ * Implements hook_load(). */ function poll_load($nodes) { - global $user; foreach ($nodes as $node) { $poll = db_query("SELECT runtime, active FROM {poll} WHERE nid = :nid", array(':nid' => $node->nid))->fetchObject(); @@ -445,23 +444,6 @@ function poll_load($nodes) { ->orderBy('weight') ->execute()->fetchAllAssoc('chid', PDO::FETCH_ASSOC); - // Determine whether or not this user is allowed to vote. - $poll->allowvotes = FALSE; - if (user_access('vote on polls') && $poll->active) { - if ($user->uid) { - $result = db_query('SELECT chid FROM {poll_vote} WHERE nid = :nid AND uid = :uid', array(':nid' => $node->nid, ':uid' => $user->uid))->fetchObject(); - } - else { - $result = db_query("SELECT chid FROM {poll_vote} WHERE nid = :nid AND hostname = :hostname", array(':nid' => $node->nid, ':hostname' => ip_address()))->fetchObject(); - } - if ($result) { - $poll->vote = $result->chid; - } - else { - $poll->vote = -1; - $poll->allowvotes = TRUE; - } - } foreach ($poll as $key => $value) { $nodes[$node->nid]->$key = $value; } @@ -469,6 +451,39 @@ function poll_load($nodes) { } /** + * Implements hook_node_load_uncached(). + * + * Loads user-specific information into the node object for the duration + * of the page request only. + */ +function poll_node_load_uncached($nodes, $types) { + global $user; + + foreach ($nodes as $node) { + if ($node->type == 'poll') { + // Determine whether or not this user is allowed to vote. + $node->allowvotes = FALSE; + if (user_access('vote on polls') && $node->active) { + if ($user->uid) { + $result = db_query('SELECT chid FROM {poll_vote} WHERE nid = :nid AND uid = :uid', array(':nid' => $node->nid, ':uid' => $user->uid))->fetchObject(); + } + else { + $result = db_query("SELECT chid FROM {poll_vote} WHERE nid = :nid AND hostname = :hostname", array(':nid' => $node->nid, ':hostname' => ip_address()))->fetchObject(); + } + if ($result) { + $node->vote = $result->chid; + } + else { + $node->vote = -1; + $node->allowvotes = TRUE; + } + } + } + } +} + + +/** * Implements hook_insert(). */ function poll_insert($node) { @@ -699,6 +714,7 @@ function poll_vote($form, &$form_state) ->condition('chid', $choice) ->execute(); + entity_get_controller('node')->resetCache($node->nid); cache_clear_all(); drupal_set_message(t('Your vote was recorded.')); Index: modules/system/system.install =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.install,v retrieving revision 1.430 diff -u -p -r1.430 system.install --- modules/system/system.install 14 Dec 2009 10:36:26 -0000 1.430 +++ modules/system/system.install 23 Dec 2009 17:59:37 -0000 @@ -604,6 +604,8 @@ function system_schema() { $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_file'] = $schema['cache']; + $schema['cache_file']['description'] = 'Cache table for file objects.'; $schema['date_format_type'] = array( 'description' => 'Stores configured date format types.', @@ -2716,6 +2718,16 @@ function system_update_7048() { } /** + * Add the {cache_file} table. + */ +function system_update_7049() { + // Add the cache_path table. + $schema['cache_file'] = drupal_get_schema_unprocessed('system', 'cache'); + $schema['cache_file']['description'] = 'Cache table used for files.'; + db_create_table('cache_file', $schema['cache_file']); +} + +/** * @} End of "defgroup updates-6.x-to-7.x" * The next series of updates should start at 8000. */ Index: modules/system/system.module =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.module,v retrieving revision 1.862 diff -u -p -r1.862 system.module --- modules/system/system.module 15 Dec 2009 08:45:32 -0000 1.862 +++ modules/system/system.module 23 Dec 2009 17:59:38 -0000 @@ -282,6 +282,9 @@ function system_entity_info() { 'id' => 'fid', ), 'static cache' => FALSE, + 'field cache' => FALSE, + 'entity cache' => TRUE, + 'entity cache bin' => 'cache_file', ), ); } Index: modules/taxonomy/taxonomy.install =================================================================== RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.install,v retrieving revision 1.30 diff -u -p -r1.30 taxonomy.install --- modules/taxonomy/taxonomy.install 9 Dec 2009 15:52:25 -0000 1.30 +++ modules/taxonomy/taxonomy.install 23 Dec 2009 17:59:38 -0000 @@ -211,6 +211,9 @@ function taxonomy_schema() { ), ); + $schema['cache_taxonomy'] = drupal_get_schema_unprocessed('system', 'cache'); + $schema['cache_taxonomy']['description'] = 'Cache table used for taxonomy terms and vocabularies.'; + return $schema; } @@ -429,3 +432,11 @@ function taxonomy_update_7006() { )); } +/** + * Add the {cache_taxonomy} table. + */ +function taxonomy_update_7007() { + $schema['cache_taxonomy'] = drupal_get_schema_unprocessed('system', 'cache'); + $schema['cache_taxonomy']['description'] = 'Cache table used for taxonomy terms and vocabularies.'; + db_create_table('cache_taxonomy', $schema['cache_taxonomy']); +} Index: modules/taxonomy/taxonomy.module =================================================================== RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.module,v retrieving revision 1.552 diff -u -p -r1.552 taxonomy.module --- modules/taxonomy/taxonomy.module 21 Dec 2009 13:47:32 -0000 1.552 +++ modules/taxonomy/taxonomy.module 23 Dec 2009 17:59:39 -0000 @@ -90,6 +90,9 @@ function taxonomy_entity_info() { 'controller class' => 'TaxonomyTermController', 'base table' => 'taxonomy_term_data', 'fieldable' => TRUE, + 'entity cache' => TRUE, + 'entity cache bin' => 'cache_taxonomy', + 'field cache' => FALSE, 'object keys' => array( 'id' => 'tid', 'bundle' => 'vocabulary_machine_name', @@ -115,6 +118,8 @@ function taxonomy_entity_info() { 'label' => t('Taxonomy vocabulary'), 'controller class' => 'TaxonomyVocabularyController', 'base table' => 'taxonomy_vocabulary', + 'entity cache' => TRUE, + 'entity cache bin' => 'cache_taxonomy', 'object keys' => array( 'id' => 'vid', ), @@ -341,6 +346,7 @@ function taxonomy_vocabulary_save($vocab if (!empty($vocabulary->vid) && !empty($vocabulary->name)) { $status = drupal_write_record('taxonomy_vocabulary', $vocabulary, 'vid'); module_invoke_all('taxonomy_vocabulary_update', $vocabulary); + entity_get_controller('taxonomy_vocabulary')->resetCache($vocabulary->vid); } elseif (empty($vocabulary->vid)) { $status = drupal_write_record('taxonomy_vocabulary', $vocabulary); @@ -350,7 +356,6 @@ function taxonomy_vocabulary_save($vocab } cache_clear_all(); - entity_get_controller('taxonomy_vocabulary')->resetCache(); return $status; } @@ -473,10 +478,11 @@ function taxonomy_term_save($term) { $status = drupal_write_record('taxonomy_term_data', $term, 'tid'); field_attach_update('taxonomy_term', $term); module_invoke_all('taxonomy_term_update', $term); + entity_get_controller('taxonomy_term')->resetCache($term->tid); + taxonomy_terms_static_reset(); } else { $status = drupal_write_record('taxonomy_term_data', $term); - _taxonomy_clean_field_cache($term); field_attach_insert('taxonomy_term', $term); module_invoke_all('taxonomy_term_insert', $term); } @@ -514,7 +520,6 @@ function taxonomy_term_save($term) { $query->execute(); cache_clear_all(); - taxonomy_terms_static_reset(); return $status; } @@ -553,15 +558,15 @@ function taxonomy_term_delete($tid) { ->execute(); field_attach_delete('taxonomy_term', $term); - _taxonomy_clean_field_cache($term); module_invoke_all('taxonomy_term_delete', $term); } $tids = $orphans; } - cache_clear_all(); + entity_get_controller('taxonomy_term')->resetCache($term->tid); taxonomy_terms_static_reset(); + cache_clear_all(); return SAVED_DELETED; } @@ -572,7 +577,6 @@ function taxonomy_term_delete($tid) { function taxonomy_terms_static_reset() { drupal_static_reset('taxonomy_term_count_nodes'); drupal_static_reset('taxonomy_get_tree'); - entity_get_controller('taxonomy_term')->resetCache(); } /** @@ -1174,48 +1178,6 @@ function taxonomy_field_formatter_prepar } /** - * Helper function that clears field cache when terms are updated or deleted - */ -function _taxonomy_clean_field_cache($term) { - $cids = array(); - - // Determine object types that are not cacheable. - $obj_types = array(); - foreach (entity_get_info() as $obj_type => $info) { - if (isset($info['cacheable']) && !$info['cacheable']) { - $obj_types[] = $obj_type; - } - } - - // Load info for all taxonomy term fields. - $fields = field_read_fields(array('type' => 'taxonomy_term')); - foreach ($fields as $field_name => $field) { - - // Assemble an array of vocabulary IDs that are used in this field. - foreach ($field['settings']['allowed_values'] as $tree) { - $vids[$tree['vid']] = $tree['vid']; - } - - // Check this term's vocabulary against those used for the field's options. - if (in_array($term->vid, $vids)) { - $conditions = array(array('tid', $term->tid)); - if ($obj_types) { - $conditions[] = array('type', $obj_types, 'NOT IN'); - } - $results = field_attach_query($field['id'], $conditions, array('limit' => FIELD_QUERY_NO_LIMIT)); - foreach ($results as $obj_type => $objects) { - foreach (array_keys($objects) as $id) { - $cids[] = "field:$obj_type:$id"; - } - } - } - } - if ($cids) { - cache_clear_all($cids, 'cache_field'); - } -} - -/** * Title callback for term pages. * * @param $term Index: modules/taxonomy/taxonomy.test =================================================================== RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.test,v retrieving revision 1.64 diff -u -p -r1.64 taxonomy.test --- modules/taxonomy/taxonomy.test 10 Dec 2009 15:39:43 -0000 1.64 +++ modules/taxonomy/taxonomy.test 23 Dec 2009 17:59:39 -0000 @@ -683,6 +683,7 @@ class TaxonomyHooksTestCase extends Taxo 'antonym' => 'Short', ); $this->drupalPost('taxonomy/term/' . $term->tid . '/edit', $edit, t('Save')); + entity_get_controller('taxonomy_term')->resetCache($term->tid); taxonomy_terms_static_reset(); $term = taxonomy_term_load($term->tid); $this->assertEqual($edit['antonym'], $term->antonym, t('Antonym was successfully edited')); Index: modules/translation/translation.module =================================================================== RCS file: /cvs/drupal/drupal/modules/translation/translation.module,v retrieving revision 1.68 diff -u -p -r1.68 translation.module --- modules/translation/translation.module 6 Dec 2009 17:56:05 -0000 1.68 +++ modules/translation/translation.module 23 Dec 2009 17:59:39 -0000 @@ -225,14 +225,14 @@ function translation_node_insert($node) if (!empty($node->translation_source)) { if ($node->translation_source->tnid) { // Add node to existing translation set. - $tnid = $node->translation_source->tnid; + $node->tnid = $node->translation_source->tnid; } else { // Create new translation set, using nid from the source node. - $tnid = $node->translation_source->nid; + $node->tnid = $node->translation_source->nid; db_update('node') ->fields(array( - 'tnid' => $tnid, + 'tnid' => $node->tnid, 'translate' => 0, )) ->condition('nid', $node->translation_source->nid) @@ -240,11 +240,12 @@ function translation_node_insert($node) } db_update('node') ->fields(array( - 'tnid' => $tnid, + 'tnid' => $node->tnid, 'translate' => 0, )) ->condition('nid', $node->nid) ->execute(); + translation_clear_node_cache($node); } } } @@ -273,6 +274,7 @@ function translation_node_update($node) ->execute(); } } + translation_clear_node_cache($node); } } @@ -334,6 +336,7 @@ function translation_remove_from_set($no ->execute(); } } + translation_clear_node_cache($node); } } @@ -420,3 +423,24 @@ function translation_language_switch_lin } } } + +/** + * Clear the node_load() cache for all nodes in the translation set. + * + * This ensures we have the proper translation set information in every node. + * + * @param $tnid + * The translation source nid of the translation set, the identifier + * of the node used to derive all translations in the set. + */ +function translation_clear_node_cache($node) { + drupal_static_reset('translation_node_get_translations'); + $nids = array(); + if ($translations = translation_node_get_translations($node->tnid)) { + foreach ($translations as $translation) { + $nids[] = $translation->nid; + } + entity_get_controller('node')->resetCache($nids); + } +} +