From 7b087d4a6c3a9b3f1df275558305ac58e0738ced Mon Sep 17 00:00:00 2001 From: chris meyers Date: Mon, 19 Nov 2018 11:32:13 -0500 Subject: [PATCH] loop over dnr nodes by topological sort * Perform topological sort on graph nodes before looping over them to mark do not run. This guarantees that parent nodes will be processed before calling dependent child nodes. The complexity of the sorting is N. The complexity of marking the the nodes is N*V --- awx/main/scheduler/dag_simple.py | 25 +++++++++++++++++++++++++ awx/main/scheduler/dag_workflow.py | 7 +------ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/awx/main/scheduler/dag_simple.py b/awx/main/scheduler/dag_simple.py index fd54b6a34f..2ebda0375b 100644 --- a/awx/main/scheduler/dag_simple.py +++ b/awx/main/scheduler/dag_simple.py @@ -1,3 +1,5 @@ +from collections import deque + class SimpleDAG(object): ''' A simple implementation of a directed acyclic graph ''' @@ -198,3 +200,26 @@ class SimpleDAG(object): node_objs_visited.add(node_obj) path.discard(node_obj) return res + + def sort_nodes_topological(self): + nodes_sorted = deque() + obj_ids_processed = set([]) + + def visit(node): + obj = node['node_object'] + if obj.id in obj_ids_processed: + return + + for child in self.get_dependencies(obj): + visit(child) + obj_ids_processed.add(obj.id) + nodes_sorted.appendleft(node) + + for node in self.nodes: + obj = node['node_object'] + if obj.id in obj_ids_processed: + continue + + visit(node) + + return nodes_sorted diff --git a/awx/main/scheduler/dag_workflow.py b/awx/main/scheduler/dag_workflow.py index b405262218..41aba609b7 100644 --- a/awx/main/scheduler/dag_workflow.py +++ b/awx/main/scheduler/dag_workflow.py @@ -1,6 +1,5 @@ # Python -import copy from awx.main.models import ( WorkflowJobTemplateNode, WorkflowJobNode, @@ -201,10 +200,9 @@ class WorkflowDAG(SimpleDAG): def mark_dnr_nodes(self): root_nodes = self.get_root_nodes() - nodes = copy.copy(root_nodes) nodes_marked_do_not_run = [] - for index, node in enumerate(nodes): + for node in self.sort_nodes_topological(): obj = node['node_object'] if obj.do_not_run is False and not obj.job: @@ -217,7 +215,4 @@ class WorkflowDAG(SimpleDAG): obj.do_not_run = True nodes_marked_do_not_run.append(node) - nodes.extend(self.get_dependencies(obj, 'success_nodes') + - self.get_dependencies(obj, 'failure_nodes') + - self.get_dependencies(obj, 'always_nodes')) return [n['node_object'] for n in nodes_marked_do_not_run]