Improve cache invalidation of (pseudo-)essential set

If a new pseudo-essential package was added to testing *and* it is
mutually-exclusive with an existing member, britney would incorrectly
flag it as uninstallable (unless another change triggered a cache
invalidation of the pseudo-essential set).

With this commit, the cache invalidation is now done based on whether
we add something that *might* be in the (effective) pseudo-essential
set.  It is an overapproximation as there are cases where the
invalidation is unnecessary, but at the moment it is not a performance
concern.

Closes: https://bugs.debian.org/944190
Signed-off-by: Niels Thykier <niels@thykier.net>
ubuntu/rebased
Niels Thykier 5 years ago
parent c3ca2bc703
commit 0d5ea5eb8c
No known key found for this signature in database
GPG Key ID: A65B78DBE67C7AAC

@ -17,7 +17,7 @@ from functools import partial
import logging import logging
from itertools import chain, filterfalse from itertools import chain, filterfalse
from britney2.utils import iter_except from britney2.utils import iter_except, add_transitive_dependencies_flatten
class InstallabilityTester(object): class InstallabilityTester(object):
@ -52,12 +52,16 @@ class InstallabilityTester(object):
# are essential and packages that will always follow. # are essential and packages that will always follow.
# #
# It may not be a complete essential set, since alternatives # It may not be a complete essential set, since alternatives
# are not always resolved. Noticably cases like "awk" may be # are not always resolved. Noticeably cases like "awk" may be
# left out (since it could be either gawk, mawk or # left out (since it could be either gawk, mawk or
# original-awk) unless something in this sets depends strictly # original-awk) unless something in this sets depends strictly
# on one of them # on one of them
self._cache_ess = {} self._cache_ess = {}
essential_w_transitive_deps = set(universe.essential_packages)
add_transitive_dependencies_flatten(universe, essential_w_transitive_deps)
self._cache_essential_transitive_dependencies = essential_w_transitive_deps
def compute_installability(self): def compute_installability(self):
"""Computes the installability of all the packages in the suite """Computes the installability of all the packages in the suite
@ -137,8 +141,8 @@ class InstallabilityTester(object):
# Re-add broken packages as some of them may now be installable # Re-add broken packages as some of them may now be installable
self._suite_contents |= self._cache_broken self._suite_contents |= self._cache_broken
self._cache_broken = set() self._cache_broken = set()
if pkg_id in self._universe.essential_packages and pkg_id.architecture in self._cache_ess: if pkg_id in self._cache_essential_transitive_dependencies and pkg_id.architecture in self._cache_ess:
# Adds new essential => "pseudo-essential" set needs to be # Adds new possibly pseudo-essential => "pseudo-essential" set needs to be
# recomputed # recomputed
del self._cache_ess[pkg_id.architecture] del self._cache_ess[pkg_id.architecture]

@ -30,7 +30,7 @@ import time
from collections import defaultdict from collections import defaultdict
from datetime import datetime from datetime import datetime
from functools import partial from functools import partial
from itertools import filterfalse from itertools import filterfalse, chain
import yaml import yaml
@ -127,6 +127,25 @@ def compute_reverse_tree(pkg_universe, affected):
return None return None
def add_transitive_dependencies_flatten(pkg_universe, initial_set):
"""Find and include all transitive dependencies
This method updates the initial_set parameter to include all transitive
dependencies. The first argument is an instance of the BinaryPackageUniverse
and the second argument are a set of BinaryPackageId.
The set of initial packages will be updated in place and must
therefore be mutable.
"""
remain = list(initial_set)
while remain:
pkg_id = remain.pop()
new_pkg_ids = [x for x in chain.from_iterable(pkg_universe.dependencies_of(pkg_id)) if x not in initial_set]
initial_set.update(new_pkg_ids)
remain.extend(new_pkg_ids)
return None
def write_nuninst(filename, nuninst): def write_nuninst(filename, nuninst):
"""Write the non-installable report """Write the non-installable report

Loading…
Cancel
Save