batch_7.inc

Drupal 7 engine for the Batch API

Functions

Namesort descending Description
_drush_backend_batch_process Main loop for the Drush batch API.
_drush_batch_command Initialize the batch command and call the worker function.
_drush_batch_finished End the batch processing: Call the 'finished' callbacks to allow custom handling of results, and resolve page redirection.
_drush_batch_shutdown Shutdown function: store the batch data for next request, or clear the table if the batch is finished.
_drush_batch_worker Process batch operations

File

commands/core/drupal/batch_7.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * Drupal 7 engine for the Batch API
  5. */
  6. /**
  7. * Main loop for the Drush batch API.
  8. *
  9. * Saves a record of the batch into the database, and progressively call $command to
  10. * process the operations.
  11. *
  12. * @param command
  13. * The command to call to process the batch.
  14. *
  15. */
  16. function _drush_backend_batch_process($command = 'batch-process') {
  17. $batch =& batch_get();
  18. if (isset($batch)) {
  19. $process_info = array(
  20. 'current_set' => 0,
  21. );
  22. $batch += $process_info;
  23. // The batch is now completely built. Allow other modules to make changes
  24. // to the batch so that it is easier to reuse batch processes in other
  25. // enviroments.
  26. drupal_alter('batch', $batch);
  27. // Assign an arbitrary id: don't rely on a serial column in the 'batch'
  28. // table, since non-progressive batches skip database storage completely.
  29. $batch['id'] = db_next_id();
  30. $batch['progressive'] = TRUE;
  31. // Move operations to a job queue. Non-progressive batches will use a
  32. // memory-based queue.
  33. foreach ($batch['sets'] as $key => $batch_set) {
  34. _batch_populate_queue($batch, $key);
  35. }
  36. // Store the batch.
  37. db_insert('batch')
  38. ->fields(array(
  39. 'bid' => $batch['id'],
  40. 'timestamp' => REQUEST_TIME,
  41. 'token' => drupal_get_token($batch['id']),
  42. 'batch' => serialize($batch),
  43. ))
  44. ->execute();
  45. $finished = FALSE;
  46. while (!$finished) {
  47. $data = drush_backend_invoke($command, array($batch['id']));
  48. $finished = drush_get_error() || !$data || ($data['context']['drush_batch_process_finished'] == TRUE);
  49. }
  50. }
  51. }
  52. /**
  53. * Initialize the batch command and call the worker function.
  54. *
  55. * Loads the batch record from the database and sets up the requirements
  56. * for the worker, such as registering the shutdown function.
  57. *
  58. * @param id
  59. * The batch id of the batch being processed.
  60. */
  61. function _drush_batch_command($id) {
  62. $batch =& batch_get();
  63. $data = db_query("SELECT batch FROM {batch} WHERE bid = :bid", array(
  64. ':bid' => $id))->fetchField();
  65. if ($data) {
  66. $batch = unserialize($data);
  67. }
  68. else {
  69. return FALSE;
  70. }
  71. if (!isset($batch['running'])) {
  72. $batch['running'] = TRUE;
  73. }
  74. // Register database update for end of processing.
  75. register_shutdown_function('_drush_batch_shutdown');
  76. if (_drush_batch_worker()) {
  77. _drush_batch_finished();
  78. }
  79. }
  80. /**
  81. * Process batch operations
  82. *
  83. * Using the current $batch process each of the operations until the batch
  84. * has been completed or half of the available memory for the process has been
  85. * reached.
  86. */
  87. function _drush_batch_worker() {
  88. $batch =& batch_get();
  89. $current_set =& _batch_current_set();
  90. $set_changed = TRUE;
  91. timer_start('batch_processing');
  92. if (empty($current_set['start'])) {
  93. $current_set['start'] = microtime(TRUE);
  94. }
  95. $queue = _batch_queue($current_set);
  96. while (!$current_set['success']) {
  97. // If this is the first time we iterate this batch set in the current
  98. // request, we check if it requires an additional file for functions
  99. // definitions.
  100. if ($set_changed && isset($current_set['file']) && is_file($current_set['file'])) {
  101. include_once DRUPAL_ROOT . '/' . $current_set['file'];
  102. }
  103. $task_message = '';
  104. // Assume a single pass operation and set the completion level to 1 by
  105. // default.
  106. $finished = 1;
  107. if ($item = $queue->claimItem()) {
  108. list($function, $args) = $item->data;
  109. // Build the 'context' array and execute the function call.
  110. $batch_context = array(
  111. 'sandbox' => &$current_set['sandbox'],
  112. 'results' => &$current_set['results'],
  113. 'finished' => &$finished,
  114. 'message' => &$task_message,
  115. );
  116. call_user_func_array($function, array_merge($args, array(&$batch_context)));
  117. if ($finished == 1) {
  118. // Make sure this step is not counted twice when computing $current.
  119. $finished = 0;
  120. // Remove the processed operation and clear the sandbox.
  121. $queue->deleteItem($item);
  122. $current_set['count']--;
  123. $current_set['sandbox'] = array();
  124. }
  125. }
  126. // When all operations in the current batch set are completed, browse
  127. // through the remaining sets, marking them 'successfully processed'
  128. // along the way, until we find a set that contains operations.
  129. // _batch_next_set() executes form submit handlers stored in 'control'
  130. // sets (see form_execute_handlers()), which can in turn add new sets to
  131. // the batch.
  132. $set_changed = FALSE;
  133. $old_set = $current_set;
  134. while (empty($current_set['count']) && ($current_set['success'] = TRUE) && _batch_next_set()) {
  135. $current_set = &_batch_current_set();
  136. $current_set['start'] = microtime(TRUE);
  137. $set_changed = TRUE;
  138. }
  139. // At this point, either $current_set contains operations that need to be
  140. // processed or all sets have been completed.
  141. $queue = _batch_queue($current_set);
  142. // If we are in progressive mode, break processing after 1 second.
  143. if ((memory_get_usage() * 2) >= drush_memory_limit()) {
  144. drush_log(dt("Batch process has consumed in excess of 50% of available memory. Starting new thread"), "batch");
  145. // Record elapsed wall clock time.
  146. $current_set['elapsed'] = round((microtime(TRUE) - $current_set['start']) * 1000, 2);
  147. break;
  148. }
  149. }
  150. // Reporting 100% progress will cause the whole batch to be considered
  151. // processed. If processing was paused right after moving to a new set,
  152. // we have to use the info from the new (unprocessed) set.
  153. if ($set_changed && isset($current_set['queue'])) {
  154. // Processing will continue with a fresh batch set.
  155. $remaining = $current_set['count'];
  156. $total = $current_set['total'];
  157. $progress_message = $current_set['init_message'];
  158. $task_message = '';
  159. }
  160. else {
  161. // Processing will continue with the current batch set.
  162. $remaining = $old_set['count'];
  163. $total = $old_set['total'];
  164. $progress_message = $old_set['progress_message'];
  165. }
  166. $current = $total - $remaining + $finished;
  167. $percentage = _batch_api_percentage($total, $current);
  168. return ($percentage == 100);
  169. }
  170. /**
  171. * End the batch processing:
  172. * Call the 'finished' callbacks to allow custom handling of results,
  173. * and resolve page redirection.
  174. */
  175. function _drush_batch_finished() {
  176. $batch = &batch_get();
  177. // Execute the 'finished' callbacks for each batch set, if defined.
  178. foreach ($batch['sets'] as $batch_set) {
  179. if (isset($batch_set['finished'])) {
  180. // Check if the set requires an additional file for function definitions.
  181. if (isset($batch_set['file']) && is_file($batch_set['file'])) {
  182. include_once DRUPAL_ROOT . '/' . $batch_set['file'];
  183. }
  184. if (function_exists($batch_set['finished'])) {
  185. $queue = _batch_queue($batch_set);
  186. $operations = $queue->getAllItems();
  187. $batch_set['finished']($batch_set['success'], $batch_set['results'], $operations, format_interval($batch_set['elapsed'] / 1000));
  188. }
  189. }
  190. }
  191. // Clean up the batch table and unset the static $batch variable.
  192. db_delete('batch')
  193. ->condition('bid', $batch['id'])
  194. ->execute();
  195. foreach ($batch['sets'] as $batch_set) {
  196. if ($queue = _batch_queue($batch_set)) {
  197. $queue->deleteQueue();
  198. }
  199. }
  200. $_batch = $batch;
  201. $batch = NULL;
  202. drush_set_option('drush_batch_process_finished', TRUE);
  203. }
  204. /**
  205. * Shutdown function: store the batch data for next request,
  206. * or clear the table if the batch is finished.
  207. */
  208. function _drush_batch_shutdown() {
  209. if ($batch = batch_get()) {
  210. db_update('batch')
  211. ->fields(array('batch' => serialize($batch)))
  212. ->condition('bid', $batch['id'])
  213. ->execute();
  214. }
  215. }