diff options
-rw-r--r-- | pym/_emerge/__init__.py | 74 |
1 files changed, 35 insertions, 39 deletions
diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index 74f07ec05..4ebfbde9e 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -4300,6 +4300,7 @@ class depgraph(object): # blocker validation is only able to account for one package per slot. self._slot_collision_nodes = set() self._serialized_tasks_cache = None + self._scheduler_graph = None self._displayed_list = None self._pprovided_args = [] self._missing_args = [] @@ -6154,7 +6155,8 @@ class depgraph(object): while self._serialized_tasks_cache is None: self._resolve_conflicts() try: - self._serialized_tasks_cache = self._serialize_tasks() + self._serialized_tasks_cache, self._scheduler_graph = \ + self._serialize_tasks() except self._serialize_tasks_retry: pass @@ -6163,6 +6165,25 @@ class depgraph(object): retlist.reverse() return retlist + def schedulerGraph(self): + """ + The scheduler graph is identical to the normal one except that + uninstall edges are reversed in specific cases that require + conflicting packages to be temporarily installed simultaneously. + This is intended for use by the Scheduler in it's parallelization + logic. It ensures that temporary simultaneous installation of + conflicting packages is avoided when appropriate (especially for + !!atom blockers), but allowed in specific cases that require it. + + Note that this method calls break_refs() which alters the state of + internal Package instances such that this depgraph instance should + not be used to perform any more calculations. + """ + if self._scheduler_graph is None: + self.altlist() + self.break_refs(self._scheduler_graph.order) + return self._scheduler_graph + def break_refs(self, nodes): """ Take a mergelist like that returned from self.altlist() and @@ -6189,6 +6210,7 @@ class depgraph(object): raise self._unknown_internal_error() def _serialize_tasks(self): + scheduler_graph = self.digraph.copy() mygraph=self.digraph.copy() # Prune "nomerge" root nodes if nothing depends on them, since # otherwise they slow down merge order calculation. Don't remove @@ -6608,6 +6630,10 @@ class depgraph(object): for blocked_pkg in parent_nodes: mygraph.add(blocked_pkg, uninst_task, priority=BlockerDepPriority.instance) + scheduler_graph.remove_edge(uninst_task, blocked_pkg) + scheduler_graph.add(blocked_pkg, uninst_task, + priority=BlockerDepPriority.instance) + else: # None of the Uninstall tasks are acceptable, so # the corresponding blockers are unresolvable. @@ -6718,14 +6744,16 @@ class depgraph(object): not self._accept_blocker_conflicts(): self._unsatisfied_blockers_for_display = unsolvable_blockers self._serialized_tasks_cache = retlist[:] + self._scheduler_graph = scheduler_graph raise self._unknown_internal_error() if self._slot_collision_info and \ not self._accept_blocker_conflicts(): self._serialized_tasks_cache = retlist[:] + self._scheduler_graph = scheduler_graph raise self._unknown_internal_error() - return retlist + return retlist, scheduler_graph def _show_circular_deps(self, mygraph): # No leaf nodes are available, so we have a circular @@ -9247,35 +9275,8 @@ class Scheduler(PollScheduler): return self._digraph = digraph - self._reverse_uninstall_edges() self._prune_digraph() - def _reverse_uninstall_edges(self): - """ - The uninstall is performed only after blocking packages have been - merged on top of it (similar to how a normal upgrade is performed - by first merging the new version on top of the old version). This - is implemented by reversing the parent -> uninstall edges in - the graph. - """ - - graph = self._digraph - - # TODO: Invert specific edges that the depgraph has decided are - # necessary and allowed to be inverted. Currently the below code - # does not invert edges for uninstalls that happen as part of an - # upgrade with in a slot (though it should). - for node in self._mergelist: - if not isinstance(node, Package) or \ - node.operation != "uninstall": - continue - - parent_nodes = graph.parent_nodes(node) - graph.remove(node) - for blocked_pkg in parent_nodes: - graph.add(blocked_pkg, node, - priority=BlockerDepPriority.instance) - def _prune_digraph(self): """ Prune any root nodes that are irrelevant. @@ -10268,11 +10269,8 @@ class Scheduler(PollScheduler): mylist = mydepgraph.altlist() mydepgraph.break_refs(mylist) - mydepgraph.break_refs(dropped_tasks) - mydepgraph.break_refs(mydepgraph.digraph.order) - self._mergelist = mylist - self._set_digraph(mydepgraph.digraph) + self._set_digraph(mydepgraph.schedulerGraph()) msg_width = 75 for task in dropped_tasks: @@ -13187,10 +13185,9 @@ def action_build(settings, trees, mtimedb, time.sleep(3) # allow the parent to have first fetch mymergelist = mydepgraph.altlist() mydepgraph.break_refs(mymergelist) - mydepgraph.break_refs(mydepgraph.digraph.order) mergetask = Scheduler(settings, trees, mtimedb, myopts, - spinner, mymergelist, favorites, mydepgraph.digraph) - del mydepgraph + spinner, mymergelist, favorites, mydepgraph.schedulerGraph()) + del mydepgraph, mymergelist clear_caches(trees) retval = mergetask.merge() @@ -13235,10 +13232,9 @@ def action_build(settings, trees, mtimedb, pkglist = mydepgraph.altlist() mydepgraph.saveNomergeFavorites() mydepgraph.break_refs(pkglist) - mydepgraph.break_refs(mydepgraph.digraph.order) mergetask = Scheduler(settings, trees, mtimedb, myopts, - spinner, pkglist, favorites, mydepgraph.digraph) - del mydepgraph + spinner, pkglist, favorites, mydepgraph.schedulerGraph()) + del mydepgraph, pkglist clear_caches(trees) retval = mergetask.merge() |