From 2a70b70c441aa9693370fba0194afc75c26e46e6 Mon Sep 17 00:00:00 2001 From: sam marshall Date: Mon, 9 Sep 2013 16:17:44 +0100 Subject: [PATCH] MDL-41087 Backup: add progress tracking in slow steps Adds calls to the new backup progress tracking API within various steps of the backup system - previously it only tracked progress between steps, but some steps can themselves be slow. This ensures the system displays progress (either by moving the progress bar if possible, or by making the wibbler below it pulsate) during nearly all of the backup process. --- backup/moodle2/backup_stepslib.php | 46 +++++++++++++++++-- .../dbops/backup_structure_dbops.class.php | 10 +++- .../util/plan/backup_structure_step.class.php | 5 +- .../backup_structure_processor.class.php | 22 ++++++++- 4 files changed, 76 insertions(+), 7 deletions(-) diff --git a/backup/moodle2/backup_stepslib.php b/backup/moodle2/backup_stepslib.php index e2f47f6498c..9437714206f 100644 --- a/backup/moodle2/backup_stepslib.php +++ b/backup/moodle2/backup_stepslib.php @@ -1499,10 +1499,16 @@ class move_inforef_annotations_to_final extends backup_execution_step { // Items we want to include in the inforef file $items = backup_helper::get_inforef_itemnames(); + $progress = $this->task->get_progress(); + $progress->start_progress($this->get_name(), count($items)); + $done = 1; foreach ($items as $itemname) { // Delegate to dbops - backup_structure_dbops::move_annotations_to_final($this->get_backupid(), $itemname); + backup_structure_dbops::move_annotations_to_final($this->get_backupid(), + $itemname, $progress); + $progress->progress($done++); } + $progress->end_progress(); } } @@ -1667,7 +1673,11 @@ class backup_main_structure_step extends backup_structure_step { /** * Execution step that will generate the final zip (.mbz) file with all the contents */ -class backup_zip_contents extends backup_execution_step { +class backup_zip_contents extends backup_execution_step implements file_progress { + /** + * @var bool True if we have started tracking progress + */ + protected $startedprogress; protected function define_execution() { @@ -1694,8 +1704,34 @@ class backup_zip_contents extends backup_execution_step { $zippacker = get_file_packer('application/zip'); // Zip files - $zippacker->archive_to_pathname($files, $zipfile); + $zippacker->archive_to_pathname($files, $zipfile, true, $this); + + // If any progress happened, end it. + if ($this->startedprogress) { + $this->task->get_progress()->end_progress(); + } } + + /** + * Implementation for file_progress interface to display unzip progress. + * + * @param int $progress Current progress + * @param int $max Max value + */ + public function progress($progress = file_progress::INDETERMINATE, $max = file_progress::INDETERMINATE) { + $reporter = $this->task->get_progress(); + + // Start tracking progress if necessary. + if (!$this->startedprogress) { + $reporter->start_progress('extract_file_to_dir', ($max == file_progress::INDETERMINATE) + ? core_backup_progress::INDETERMINATE : $max); + $this->startedprogress = true; + } + + // Pass progress through to whatever handles it. + $reporter->progress(($progress == file_progress::INDETERMINATE) + ? core_backup_progress::INDETERMINATE : $progress); + } } /** @@ -1955,6 +1991,8 @@ class backup_annotate_all_user_files extends backup_execution_step { // Fetch all annotated (final) users $rs = $DB->get_recordset('backup_ids_temp', array( 'backupid' => $this->get_backupid(), 'itemname' => 'userfinal')); + $progress = $this->task->get_progress(); + $progress->start_progress($this->get_name()); foreach ($rs as $record) { $userid = $record->itemid; $userctx = context_user::instance($userid, IGNORE_MISSING); @@ -1966,8 +2004,10 @@ class backup_annotate_all_user_files extends backup_execution_step { // We don't need to specify itemid ($userid - 5th param) as far as by // context we can get all the associated files. See MDL-22092 backup_structure_dbops::annotate_files($this->get_backupid(), $userctx->id, 'user', $filearea, null); + $progress->progress(); } } + $progress->end_progress(); $rs->close(); } } diff --git a/backup/util/dbops/backup_structure_dbops.class.php b/backup/util/dbops/backup_structure_dbops.class.php index 29529f0b6b6..61a903a9919 100644 --- a/backup/util/dbops/backup_structure_dbops.class.php +++ b/backup/util/dbops/backup_structure_dbops.class.php @@ -130,10 +130,16 @@ abstract class backup_structure_dbops extends backup_dbops { /** * Moves all the existing 'item' annotations to their final 'itemfinal' ones * for a given backup. + * + * @param string $backupid Backup ID + * @param string $itemname Item name + * @param core_backup_progress $progress Progress tracker */ - public static function move_annotations_to_final($backupid, $itemname) { + public static function move_annotations_to_final($backupid, $itemname, core_backup_progress $progress) { global $DB; + $progress->start_progress('move_annotations_to_final'); $rs = $DB->get_recordset('backup_ids_temp', array('backupid' => $backupid, 'itemname' => $itemname)); + $progress->progress(); foreach($rs as $annotation) { // If corresponding 'itemfinal' annotation does not exist, update 'item' to 'itemfinal' if (! $DB->record_exists('backup_ids_temp', array('backupid' => $backupid, @@ -141,10 +147,12 @@ abstract class backup_structure_dbops extends backup_dbops { 'itemid' => $annotation->itemid))) { $DB->set_field('backup_ids_temp', 'itemname', $itemname . 'final', array('id' => $annotation->id)); } + $progress->progress(); } $rs->close(); // All the remaining $itemname annotations can be safely deleted $DB->delete_records('backup_ids_temp', array('backupid' => $backupid, 'itemname' => $itemname)); + $progress->end_progress(); } /** diff --git a/backup/util/plan/backup_structure_step.class.php b/backup/util/plan/backup_structure_step.class.php index 9c3d0e719fe..5ff5d086637 100644 --- a/backup/util/plan/backup_structure_step.class.php +++ b/backup/util/plan/backup_structure_step.class.php @@ -73,7 +73,9 @@ abstract class backup_structure_step extends backup_step { // from xml_writer (blame serialized data!) } $xw = new xml_writer($xo, $xt); - $pr = new backup_structure_processor($xw); + $progress = $this->task->get_progress(); + $progress->start_progress($this->get_name()); + $pr = new backup_structure_processor($xw, $progress); // Set processor variables from settings foreach ($this->get_settings() as $setting) { @@ -105,6 +107,7 @@ abstract class backup_structure_step extends backup_step { // Close everything $xw->stop(); + $progress->end_progress(); // Destroy the structure. It helps PHP 5.2 memory a lot! $structure->destroy(); diff --git a/backup/util/structure/backup_structure_processor.class.php b/backup/util/structure/backup_structure_processor.class.php index 3c648545dd9..88cfeca3cee 100644 --- a/backup/util/structure/backup_structure_processor.class.php +++ b/backup/util/structure/backup_structure_processor.class.php @@ -37,9 +37,21 @@ class backup_structure_processor extends base_processor { protected $writer; // xml_writer where the processor is going to output data protected $vars; // array of backup::VAR_XXX => helper value pairs to be used by source specifications - public function __construct(xml_writer $writer) { + /** + * @var core_backup_progress Progress tracker (null if none) + */ + protected $progress; + + /** + * Constructor. + * + * @param xml_writer $writer XML writer to save data + * @param core_backup_progress $progress Progress tracker (optional) + */ + public function __construct(xml_writer $writer, core_backup_progress $progress = null) { $this->writer = $writer; - $this->vars = array(); + $this->progress = $progress; + $this->vars = array(); } public function set_var($key, $value) { @@ -83,6 +95,9 @@ class backup_structure_processor extends base_processor { public function post_process_nested_element(base_nested_element $nested) { // Send close tag to xml_writer $this->writer->end_tag($nested->get_name()); + if ($this->progress) { + $this->progress->progress(); + } } public function process_final_element(base_final_element $final) { @@ -93,6 +108,9 @@ class backup_structure_processor extends base_processor { $attrarr[$attribute->get_name()] = $attribute->get_value(); } $this->writer->full_tag($final->get_name(), $final->get_value(), $attrarr); + if ($this->progress) { + $this->progress->progress(); + } // Annotate current value if configured to do so $final->annotate($this->get_var(backup::VAR_BACKUPID)); }