? w21.patch Index: modules/comment/comment.module =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v retrieving revision 1.844 diff -u -p -r1.844 comment.module --- modules/comment/comment.module 12 Feb 2010 14:35:36 -0000 1.844 +++ modules/comment/comment.module 16 Feb 2010 11:02:44 -0000 @@ -1512,6 +1512,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) { @@ -1525,13 +1551,52 @@ 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; + } + + // 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->subject; + // 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.1232 diff -u -p -r1.1232 node.module --- modules/node/node.module 15 Feb 2010 19:00:30 -0000 1.1232 +++ modules/node/node.module 16 Feb 2010 11:02:55 -0000 @@ -1103,37 +1103,99 @@ 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; + } + + // 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); } }