From fba130930777b94d7161662b5316e15664d8e087 Mon Sep 17 00:00:00 2001 From: Chris Kuehl Date: Thu, 18 May 2023 18:09:30 -0500 Subject: [PATCH] perf: don't clear the entire contradicted_incompatibilies cache when backtracking (#7950) --- src/poetry/mixology/version_solver.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/poetry/mixology/version_solver.py b/src/poetry/mixology/version_solver.py index cb08ec61fe0..19de00afccc 100644 --- a/src/poetry/mixology/version_solver.py +++ b/src/poetry/mixology/version_solver.py @@ -1,5 +1,6 @@ from __future__ import annotations +import collections import functools import time @@ -94,7 +95,9 @@ def __init__(self, root: ProjectPackage, provider: Provider) -> None: self._provider = provider self._dependency_cache = DependencyCache(provider) self._incompatibilities: dict[str, list[Incompatibility]] = {} - self._contradicted_incompatibilities: set[Incompatibility] = set() + self._contradicted_incompatibilities: dict[int, set[Incompatibility]] = ( + collections.defaultdict(set) + ) self._solution = PartialSolution() @property @@ -143,7 +146,10 @@ def _propagate(self, package: str) -> None: # we can derive stronger assignments sooner and more eagerly find # conflicts. for incompatibility in reversed(self._incompatibilities[package]): - if incompatibility in self._contradicted_incompatibilities: + if any( + incompatibility in c + for c in self._contradicted_incompatibilities.values() + ): continue result = self._propagate_incompatibility(incompatibility) @@ -192,7 +198,9 @@ def _propagate_incompatibility( # If term is already contradicted by _solution, then # incompatibility is contradicted as well and there's nothing new we # can deduce from it. - self._contradicted_incompatibilities.add(incompatibility) + self._contradicted_incompatibilities[self._solution.decision_level].add( + incompatibility + ) return None elif relation == SetRelation.OVERLAPPING: # If more than one term is inconclusive, we can't deduce anything about @@ -210,7 +218,9 @@ def _propagate_incompatibility( if unsatisfied is None: return _conflict - self._contradicted_incompatibilities.add(incompatibility) + self._contradicted_incompatibilities[self._solution.decision_level].add( + incompatibility + ) adverb = "not " if unsatisfied.is_positive() else "" self._log(f"derived: {adverb}{unsatisfied.dependency}") @@ -304,8 +314,12 @@ def _resolve_conflict(self, incompatibility: Incompatibility) -> Incompatibility previous_satisfier_level < most_recent_satisfier.decision_level or most_recent_satisfier.cause is None ): + for level in range( + self._solution.decision_level, previous_satisfier_level, -1 + ): + self._contradicted_incompatibilities.pop(level, None) + self._solution.backtrack(previous_satisfier_level) - self._contradicted_incompatibilities.clear() self._dependency_cache.clear() if new_incompatibility: self._add_incompatibility(incompatibility)