? batch_memory_improvements_1.patch
Index: views_bulk_operations.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views_bulk_operations/Attic/views_bulk_operations.install,v
retrieving revision 1.1.2.6
diff -u -p -r1.1.2.6 views_bulk_operations.install
--- views_bulk_operations.install	23 Mar 2010 00:07:29 -0000	1.1.2.6
+++ views_bulk_operations.install	1 Sep 2010 16:39:58 -0000
@@ -7,6 +7,58 @@
  */
 
 /**
+ * Implementation of hook_schema().
+ */
+function views_bulk_operations_schema() {
+  $schema['vbo_batch'] = array(
+    'description' => t('Store vbo batches for processing.'),
+    'fields' => array(
+  	  'vbo_id' => array(
+        'description' => t('Primary ID'),
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+  	  'unique_batch_id' => array(
+        'description' => t('Unique batch ID'),
+        'type' => 'varchar',
+        'length' => 255,
+        'default' => '',
+      ),
+      'oid' => array(
+        'description' => t('Operation ID'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+	  'data' => array(
+        'type' => 'text',
+        'default' => '',
+        'description' => t('The serialized data for the operation.'),
+      ),
+    ),
+    'indexes' => array('batch' => array('unique_batch_id')),
+    'primary key' => array('vbo_id'),
+  );
+  return $schema;
+}
+
+/**
+ * Implementation of hook_install().
+ */
+function views_bulk_operations_install() {
+  drupal_install_schema('views_bulk_operations');
+}
+
+/**
+ * Implementation of hook_uninstall().
+ */
+function views_bulk_operations_uninstall() {
+  drupal_uninstall_schema('views_bulk_operations');
+}
+
+/**
  * Implementation of hook_update_N().
  *
  * Replace MD5 hashes with meaningful strings in selected operations arrays.
@@ -60,3 +112,13 @@ function views_bulk_operations_update_60
   return array();
 }
 
+/*
+ * Implementation of hook_N().
+ */
+function views_bulk_operations_update_6001() {
+  $ret = array();
+  $ret[] = update_sql("DROP TABLE IF EXISTS {vbo_batch}");
+  $table = views_bulk_operations_schema();
+  db_create_table($ret, 'vbo_batch', $table['vbo_batch']);
+  return $ret;
+}
\ No newline at end of file
Index: views_bulk_operations.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views_bulk_operations/views_bulk_operations.module,v
retrieving revision 1.29.2.9.2.149
diff -u -p -r1.29.2.9.2.149 views_bulk_operations.module
--- views_bulk_operations.module	30 Aug 2010 00:11:06 -0000	1.29.2.9.2.149
+++ views_bulk_operations.module	1 Sep 2010 16:39:58 -0000
@@ -435,6 +435,9 @@ function views_bulk_operations_form_vali
  */ 
 function _views_bulk_operations_adjust_selection(&$selection, $select_all, $exposed_input, $arguments, $plugin) {
   if ($select_all) {
+    // Setup a unique batch id here for storage.
+    $unique_batch_id = uniqid();
+    $_SESSION['vbo_options']['unique_batch_id'] = $unique_batch_id;
     // Adjust selection to select all nodes across pages.
     $view = views_get_view($plugin->view->vid ? $plugin->view->vid : $plugin->view->name);
     $view->set_items_per_page(0);
@@ -444,10 +447,18 @@ function _views_bulk_operations_adjust_s
     // HACK for date_api_filter_handler: set $_GET with the exposed_input.
     $_GET += $exposed_input;
 
+    // @TODO: we need to process the view in a controlled way as this still renders all rows to the $view object.
     $view->execute($plugin->view->current_display);
     $selection = array();
     foreach ($view->result as $num => $result) {
-      $selection[$num + 1] = $result;
+      $oid = $result->{$view->base_field};
+      $data = serialize($result);
+      // Lets insert these rows into the batch table to process one at a time instead of saving to memory.
+      db_query("INSERT INTO {vbo_batch} (unique_batch_id, oid, data) VALUES ('%s', %d, '%s')", $unique_batch_id, $oid, $data);
+      // Save the first 20 for the confirmation view?
+      // @TODO: Need to show total count in confirmation view.
+      // @TODO: Need to remove all these rows from database if users chooses cancel.
+      if($num < 20) $selection[$num + 1] = $result;
     }
   }
   else {
@@ -583,12 +594,7 @@ function _views_bulk_operations_execute(
     variable_set('actions_max_stack', 10000000);
   }
   if ($operation['aggregate'] != VBO_AGGREGATE_FORCED && $options['execution_type'] == VBO_EXECUTION_BATCH) {
-    $operations = array();
-    foreach ($objects as $num => $row) {
-      $oid = $row->{$view->base_field};
-      $operations[] = array('_views_bulk_operations_batch_process', array($oid, $row));
-    }
-
+    $operations = array(array('_views_bulk_operations_batch_process', array()));
     // Save the options in the session because Batch API doesn't give a way to 
     // send a parameter to the finished callback.
     $_SESSION['vbo_options']['display_result'] = $options['display_result'];
@@ -668,39 +674,63 @@ function _views_bulk_operations_queue_pr
 /**
  * Helper function to handle Batch API operations.
  */
-function _views_bulk_operations_batch_process($oid, $row, &$context) {
+function _views_bulk_operations_batch_process(&$context) {
   module_load_include('inc', 'node', 'node.admin');
 
   $operation = $_SESSION['vbo_options']['operation'];
   $params = $_SESSION['vbo_options']['params'];
   $object_info = $_SESSION['vbo_options']['object_info'];
+  $unique_batch_id = $_SESSION['vbo_options']['unique_batch_id'];
+  
+  // Add our total and initialiation here.
+  if (!isset($context['sandbox']['progress'])) {
+    $context['sandbox']['progress'] = 0;
+    $context['sandbox']['current_oid'] = 0;
+    $max = db_fetch_object(db_query("SELECT COUNT(*) AS total FROM {vbo_batch} WHERE unique_batch_id='%s'", $unique_batch_id));
+    $context['sandbox']['max'] = $max->total;
+  }
 
+  // Set our limit here
+  // @TODO: maybe make this a configuration option?
+  $limit = (int)100;
+  
   if (!isset($context['results']['time'])) {
     $context['results']['time'] = microtime(TRUE);
   }
+  
+  $result = db_query_range("SELECT * FROM {vbo_batch} WHERE unique_batch_id='%s' AND oid>%d ORDER BY oid", $unique_batch_id, $context['sandbox']['current_oid'], 0, $limit);
+  while($row = db_fetch_object($result)) {
+    $context['sandbox']['progress']++;
+    $context['sandbox']['current_oid'] = $row->oid;
+    // Extract our object data
+    $data = unserialize($row->data);
 
-  $object = call_user_func($object_info['load'], $oid);
-  if (!_views_bulk_operations_object_permission($operation, $object, $object_info)) {
-    $context['results']['log'][] = t('Skipped %action on @type %title due to insufficient permissions.', array(
+    $object = call_user_func($object_info['load'], $row->oid);
+    if (!_views_bulk_operations_object_permission($operation, $object, $object_info)) {
+      $context['results']['log'][] = t('Skipped %action on @type %title due to insufficient permissions.', array(
+        '%action' => $operation['label'], 
+        '@type' => t($object_info['type']),
+        '%title' => $object->{$object_info['title']},
+      ));
+      continue;
+    }
+    
+    _views_bulk_operations_action_do($operation, $row->oid, $object, $data, $params, $object_info);
+    
+    $context['results']['log'][] = t('Performed %action on @type %title.', array(
       '%action' => $operation['label'], 
       '@type' => t($object_info['type']),
       '%title' => $object->{$object_info['title']},
     ));
-    return;
-  }
-
-  _views_bulk_operations_action_do($operation, $oid, $object, $row, $params, $object_info);
-
-  $context['results']['log'][] = t('Performed %action on @type %title.', array(
-    '%action' => $operation['label'], 
-    '@type' => t($object_info['type']),
-    '%title' => $object->{$object_info['title']},
-  ));
-  if (isset($context['results']['rows'])) {
-    $context['results']['rows'] += 1;
+    if (isset($context['results']['rows'])) {
+      $context['results']['rows'] += 1;
+    }
+    else {
+      $context['results']['rows'] = 1;
+    }
   }
-  else {
-    $context['results']['rows'] = 1;
+  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
+    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
   }
 }
 
@@ -731,6 +761,10 @@ function _views_bulk_operations_batch_fi
   if ($display_result || @$_SESSION['vbo_options']['display_result']) {
     _views_bulk_operations_log($message);
   }
+  // Truncate our batch table.
+  if (isset($_SESSION['vbo_options']['unique_batch_id'])) {
+    db_query("TRUNCATE {vbo_batch} WHERE unique_batch_id='%s'", $_SESSION['vbo_options']['unique_batch_id']);
+  }
   unset($_SESSION['vbo_options']); // unset the options which were used for just one invocation
 }
 
