Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.841
diff -u -p -r1.841 comment.module
--- modules/comment/comment.module	9 Feb 2010 12:29:39 -0000	1.841
+++ modules/comment/comment.module	12 Feb 2010 13:07:14 -0000
@@ -1241,7 +1241,7 @@ function comment_node_insert($node) {
  */
 function comment_node_delete($node) {
   $cids = db_query('SELECT cid FROM {comment} WHERE nid = :nid', array(':nid' => $node->nid))->fetchCol();
-  comment_delete_multiple($cids);
+  _comment_mass_delete_helper($cids);
   db_delete('node_comment_statistics')
     ->condition('nid', $node->nid)
     ->execute();
@@ -1509,6 +1509,32 @@ function comment_delete($cid) {
  *   The comment to delete.
  */
 function comment_delete_multiple($cids) {
+  // We use batch processing to prevent timeout when deleting a large number
+  // of nodes or comments.
+  if (count($cids) > 10) {
+    $batch = array(
+      'operations' => array(
+        array('_comment_mass_delete_batch_process', array($cids))
+      ),
+      'finished' => '_comment_mass_delete_batch_finished',
+      'title' => t('Processing'),
+      // We use a single multi-pass operation, so the default
+      // 'Remaining x of y operations' message will be confusing here.
+      'progress_message' => '',
+      'error_message' => t('The delete has encountered an error.'),
+    );
+    batch_set($batch);  
+  }
+  else {
+    _comment_mass_delete_helper($cids);
+  }
+}
+
+/**
+ * Comment Mass Delete - helper function.
+ */
+
+function _comment_mass_delete_helper($cids) {
   $comments = comment_load_multiple($cids);
   if ($comments) {
 
@@ -1522,13 +1548,56 @@ function comment_delete_multiple($cids) 
 
       // Delete the comment's replies.
       $child_cids = db_query('SELECT cid FROM {comment} WHERE pid = :cid', array(':cid' => $comment->cid))->fetchCol();
-      comment_delete_multiple($child_cids);
+      _comment_mass_delete_helper($child_cids);
       _comment_update_node_statistics($comment->nid);
     }
   }
 }
 
 /**
+ * Node Mass Delete Batch operation
+ */
+function _comment_mass_delete_batch_process($cids, &$context) {
+  if (!isset($context['sandbox']['progress'])) {
+    $context['sandbox']['progress'] = 0;
+    $context['sandbox']['max'] = count($cids);
+    $context['sandbox']['cids'] = $cids;
+  }
+
+  // Process comments by groups of 5.
+  $count = min(5, count($context['sandbox']['cids']));
+  for ($i = 1; $i <= $count; $i++) {
+    // For each cid, load the comment, reset the values, and save it.
+    $cid = array_shift($context['sandbox']['cids']);
+    $comment = comment_load($cid);
+    _comment_mass_delete_helper(array($cid));
+    // Store result for post-processing in the finished callback.
+    $context['results'][] = $comment->title;
+
+    // Update our progress information.
+    $context['sandbox']['progress']++;
+  }
+
+  // Inform the batch engine that we are not finished,
+  // and provide an estimation of the completion level we reached.
+  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
+    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
+  }
+}
+
+/**
+ * Comment Mass Update Batch 'finished' callback.
+ */
+function _comment_mass_delete_batch_finished($success, $results, $operations) {
+  if (!$success) {
+    drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
+    $message = format_plural(count($results), '1 item successfully processed:', '@count items successfully processed:');
+    $message .= theme('item_list', array('items' => $results));
+    drupal_set_message($message);
+  }
+}
+
+/**
  * Comment operations. Offer different update operations depending on
  * which comment administration page is being viewed.
  *
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1227
diff -u -p -r1.1227 node.module
--- modules/node/node.module	7 Feb 2010 17:29:09 -0000	1.1227
+++ modules/node/node.module	12 Feb 2010 13:07:29 -0000
@@ -1101,40 +1101,107 @@ function node_delete($nid) {
  *   An array of node IDs.
  */
 function node_delete_multiple($nids) {
-  if (!empty($nids)) {
-    $nodes = node_load_multiple($nids, array());
+  // We use batch processing to prevent timeout when deleting a large number
+  // of nodes.
+  if (count($nids) > 10) {
+    $batch = array(
+      'operations' => array(
+        array('_node_mass_delete_batch_process', array($nids))
+      ),
+      'finished' => '_node_mass_delete_batch_finished',
+      'title' => t('Processing'),
+      // We use a single multi-pass operation, so the default
+      // 'Remaining x of y operations' message will be confusing here.
+      'progress_message' => '',
+      'error_message' => t('The delete has encountered an error.'),
+    );
+    batch_set($batch);
+  }
+  else {
+    foreach ($nids as $nid) {
+      _node_mass_delete_helper($nid);
+    }
+    drupal_set_message(t('The delete has been performed.'));  
+  }
+}
 
-    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();
+/**
+ * Node Mass Delete - helper function.
+ */
+function _node_mass_delete_helper($nid) {
+  $node = node_load($nid, NULL, TRUE);
+  // Call the node-specific callback (if any):
+  node_invoke($node, 'delete');
+  module_invoke_all('node_delete', $node);
+  field_attach_delete('node', $node);
 
-    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');
-      }
-    }
+  // 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');
+  }
+  db_delete('node')
+    ->condition('nid', $nid, '=')
+    ->execute();
+  db_delete('node_revision')
+    ->condition('nid', $nid, '=')
+    ->execute();
+  db_delete('history')
+    ->condition('nid', $nid, '=')
+    ->execute();
+ 
+  // Clear the page and block and node_load_multiple caches.
+  cache_clear_all();
+  entity_get_controller('node')->resetCache();
+  return $node;
+}
 
-    // Clear the page and block and node_load_multiple caches.
-    cache_clear_all();
-    entity_get_controller('node')->resetCache();
+/**
+ * Node Mass Delete Batch operation
+ */
+function _node_mass_delete_batch_process($nids, &$context) {
+  if (!isset($context['sandbox']['progress'])) {
+    $context['sandbox']['progress'] = 0;
+    $context['sandbox']['max'] = count($nids);
+    $context['sandbox']['nids'] = $nids;
+  }
+
+  // Process nodes by groups of 5.
+  $count = min(5, count($context['sandbox']['nids']));
+  for ($i = 1; $i <= $count; $i++) {
+    // For each nid, load the node, reset the values, and save it.
+    $nid = array_shift($context['sandbox']['nids']);
+    $node = _node_mass_delete_helper($nid);
+
+    // Store result for post-processing in the finished callback.
+    $context['results'][] = l($node->title, 'node/' . $node->nid);
+
+    // Update our progress information.
+    $context['sandbox']['progress']++;
+  }
+
+  // Inform the batch engine that we are not finished,
+  // and provide an estimation of the completion level we reached.
+  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
+    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
+  }
+}
+
+/**
+ * Node Mass Update Batch 'finished' callback.
+ */
+function _node_mass_delete_batch_finished($success, $results, $operations) {
+  if (!$success) {
+    drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
+    $message = format_plural(count($results), '1 item successfully processed:', '@count items successfully processed:');
+    $message .= theme('item_list', array('items' => $results));
+    drupal_set_message($message);
   }
 }
 
+
 /**
  * Delete a node revision.
  *
