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)
