Index: modules/node/node.module =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.module,v retrieving revision 1.1264 diff -u -r1.1264 node.module --- modules/node/node.module 22 Apr 2010 09:12:35 -0000 1.1264 +++ modules/node/node.module 29 Apr 2010 06:24:22 -0000 @@ -445,7 +445,7 @@ * * All new module-defined node types are saved to the database via a call to * node_type_save(), and obsolete ones are deleted via a call to - * node_type_delete(). See _node_types_build() for an explanation of the new + * node_type_delete(). See _node_types_build() for an explanation of the new * and obsolete types. */ function node_types_rebuild() { @@ -1117,54 +1117,112 @@ } /** - * Delete a node. + * Deletes a node. * * @param $nid * A node ID. + * + * @see node_delete_multiple() + * @see node_delete_batch() */ function node_delete($nid) { node_delete_multiple(array($nid)); } /** - * Delete multiple nodes. + * Queues multiple nodes for deletion. + * + * If the number of nodes to delete exceeds the value defined in the + * node_delete_batch_size variable, then the array containing the $nids to be + * deleted will be split up into smaller chunks with each having at most + * node_delete_batch_size items. The first of these chunks will be processed + * immediately, while subsequent chunks are handled during cron. * * @param $nids * An array of node IDs. - */ -function node_delete_multiple($nids) { + * + * @return + * The number of nodes left in the queue for deletion at a later stage. Note + * that this number can be higher than the number of items in $nids, as nodes + * submitted for deletion during ealier calls to node_delete_multiple() might + * still be in the queue. + * + * @see node_delete() + * @see node_delete_multiple() + */ +function node_delete_batch($nids) { + $queue = DrupalQueue::get('node_deletes'); + $queue->createQueue(); + if (!empty($nids)) { - $nodes = node_load_multiple($nids, array()); + while ($nids) { + $nids_chunks[] = array_splice($nids, 0, variable_get('node_delete_batch_size', 50)); + } - db_delete('node') - ->condition('nid', $nids, 'IN') - ->execute(); - db_delete('node_revision') - ->condition('nid', $nids, 'IN') - ->execute(); - db_delete('history') - ->condition('nid', $nids, 'IN') - ->execute(); + // Since we are processing one of the chunks immediately, don't queue it. + $first_chunk = array_shift($nids_chunks); - foreach ($nodes as $nid => $node) { - // Call the node-specific callback (if any): - node_invoke($node, 'delete'); - module_invoke_all('node_delete', $node); - field_attach_delete('node', $node); - - // Remove this node from the search index if needed. - // This code is implemented in node module rather than in search module, - // because node module is implementing search module's API, not the other - // way around. - if (module_exists('search')) { - search_reindex($nid, 'node'); - } + // Queue the remaining chunks. + foreach ($nids_chunks as $chunk) { + $queue->createItem($chunk); } - // Clear the page and block and node_load_multiple caches. - cache_clear_all(); - entity_get_controller('node')->resetCache(); + node_delete_multiple($first_chunk); } + + return $queue->numberOfItems(); +} + +/** + * Helper function to delete multiple nodes. + * + * @param $nids + * An array of nids representing the nodes to be deleted. + * + * @see node_delete() + * @see node_delete_multiple() + */ +function node_delete_multiple($nids) { + $nodes = node_load_multiple($nids, array()); + db_delete('node') + ->condition('nid', $nids, 'IN') + ->execute(); + db_delete('node_revision') + ->condition('nid', $nids, 'IN') + ->execute(); + db_delete('history') + ->condition('nid', $nids, 'IN') + ->execute(); + + foreach ($nodes as $nid => $node) { + // Call the node-specific callback (if any): + node_invoke($node, 'delete'); + module_invoke_all('node_delete', $node); + field_attach_delete('node', $node); + + // Remove this node from the search index if needed. + // This code is implemented in node module rather than in search module, + // because node module is implementing search module's API, not the other + // way around. + if (module_exists('search')) { + search_reindex($nid, 'node'); + } + } + + // Clear the page and block and node_load_multiple caches. + cache_clear_all(); + entity_get_controller('node')->resetCache(); +} + +/** + * Implements hook_cron_queue_info(). + */ +function node_cron_queue_info() { + return array( + 'node_deletes' => array( + 'worker callback' => 'node_delete_multiple', + ), + ); } /** @@ -1677,18 +1735,19 @@ */ function node_user_delete($account) { // Delete nodes (current revisions). - // @todo Introduce node_mass_delete() or make node_mass_update() more flexible. $nodes = db_select('node', 'n') ->fields('n', array('nid')) ->condition('uid', $account->uid) ->execute() ->fetchCol(); - node_delete_multiple($nodes); + node_delete_batch($nodes); + // Delete old revisions. $revisions = db_query('SELECT vid FROM {node_revision} WHERE uid = :uid', array(':uid' => $account->uid))->fetchCol(); foreach ($revisions as $revision) { node_revision_delete($revision); } + // Clean history. db_delete('history') ->condition('uid', $account->uid)