Skip to content
Browse files

MDL-26405 restore - dispatch able to skip branches

after this change any restore_structure_step processor
method is able to instruct the dispatcher about to skip
any path below it. Until now, we were doing the checks on
each child processor method, but that was inneficient and
prone to errors (easy to miss the check in a child so some
orphaned piezes of restore may be causing mess here and there).
Once implemented, it's simlpy a matter of the parent deciding if
all its children must be processed or no. Easier for developers
and also small speed improvement because avoids unnecesary
dispatching/processing to happen.

Surely only will be used in parts of core, like in question_categories,
saving 50-60 sub processors (sub-paths) to be dispatched.
  • Loading branch information...
1 parent d911c72 commit 0149e6c713ead8ac1f0ce552c5fd477cd4fb5d6b @stronk7 stronk7 committed
Showing with 30 additions and 5 deletions.
  1. +1 −1 backup/moodle2/restore_stepslib.php
  2. +29 −4 backup/util/plan/restore_structure_step.class.php
View
2 backup/moodle2/restore_stepslib.php
@@ -2219,7 +2219,7 @@ protected function process_question_category($data) {
// Check we have one mapping for this category
if (!$mapping = $this->get_mapping('question_category', $oldid)) {
- return; // No mapping = this category doesn't need to be created/mapped
+ return self::SKIP_ALL_CHILDREN; // No mapping = this category doesn't need to be created/mapped
}
// Check we have to create the category (newitemid = 0)
View
33 backup/util/plan/restore_structure_step.class.php
@@ -38,6 +38,11 @@
protected $elementsoldid; // Array to store last oldid used on each element
protected $elementsnewid; // Array to store last newid used on each element
+ protected $pathlock; // Path currently locking processing of children
+
+ const SKIP_ALL_CHILDREN = -991399; // To instruct the dispatcher about to ignore
+ // all children below path processor returning it
+
/**
* Constructor - instantiates one object of this class
*/
@@ -50,10 +55,11 @@ public function __construct($name, $filename, $task = null) {
$this->pathelements = array();
$this->elementsoldid = array();
$this->elementsnewid = array();
+ $this->pathlock = null;
parent::__construct($name, $task);
}
- public function execute() {
+ final public function execute() {
if (!$this->execute_condition()) { // Check any condition to execute this
return;
@@ -106,18 +112,37 @@ public function execute() {
* Receive one chunk of information form the xml parser processor and
* dispatch it, following the naming rules
*/
- public function process($data) {
+ final public function process($data) {
if (!array_key_exists($data['path'], $this->pathelements)) { // Incorrect path, must not happen
throw new restore_step_exception('restore_structure_step_missing_path', $data['path']);
}
$element = $this->pathelements[$data['path']];
$object = $element->get_processing_object();
$method = $element->get_processing_method();
+ $rdata = null;
if (empty($object)) { // No processing object defined
throw new restore_step_exception('restore_structure_step_missing_pobject', $object);
}
- $rdata = $object->$method($data['tags']); // Dispatch to proper object/method
- if ($rdata !== null) { // If the method has returned any info, set element data to it
+ // Release the lock if we aren't anymore within children of it
+ if (!is_null($this->pathlock) and strpos($data['path'], $this->pathlock) === false) {
+ $this->pathlock = null;
+ }
+ if (is_null($this->pathlock)) { // Only dispatch if there isn't any lock
+ $rdata = $object->$method($data['tags']); // Dispatch to proper object/method
+ }
+
+ // If the dispatched method returns SKIP_ALL_CHILDREN, we grab current path in order to
+ // lock dispatching to any children
+ if ($rdata === self::SKIP_ALL_CHILDREN) {
+ // Check we haven't any previous lock
+ if (!is_null($this->pathlock)) {
+ throw new restore_step_exception('restore_structure_step_already_skipping', $data['path']);
+ }
+ // Set the lock
+ $this->pathlock = $data['path'] . '/'; // Lock everything below current path
+
+ // Continue with normal processing of return values
+ } else if ($rdata !== null) { // If the method has returned any info, set element data to it
$element->set_data($rdata);
} else { // Else, put the original parsed data
$element->set_data($data);

0 comments on commit 0149e6c

Please sign in to comment.
Something went wrong with that request. Please try again.