Exploit equivalency to skip unneeded computation

Signed-off-by: Niels Thykier <niels@thykier.net>
debian
Niels Thykier 11 years ago
parent 37608071e9
commit 12691baa87

@ -1950,28 +1950,50 @@ class Britney(object):
sources = self.sources sources = self.sources
packages_t = self.binaries['testing'] packages_t = self.binaries['testing']
get_reverse_tree = partial(compute_reverse_tree, packages_t) get_reverse_tree = partial(compute_reverse_tree, packages_t)
inst_tester = self._inst_tester
eqv_set = set()
# remove all binary packages (if the source already exists) # remove all binary packages (if the source already exists)
if item.architecture == 'source' or not item.is_removal: if item.architecture == 'source' or not item.is_removal:
if item.package in sources['testing']: if item.package in sources['testing']:
source = sources['testing'][item.package] source = sources['testing'][item.package]
_, bins, _ = self._compute_groups(item.package, updates, rms, _ = self._compute_groups(item.package,
item.suite, item.suite,
item.architecture, item.architecture,
item.is_removal, item.is_removal,
removals=removals) removals=removals)
eqv_table = {}
for binary, version, parch in rms:
key = (binary, parch)
eqv_table[key] = version
for p1 in updates:
binary, _, parch = p1
key = (binary, parch)
old_version = eqv_table.get(key)
if old_version is not None:
p2 = (binary, old_version, parch)
if inst_tester.are_equivalent(p1, p2):
eqv_set.add(key)
# remove all the binaries which aren't being smooth updated # remove all the binaries which aren't being smooth updated
for rm_tuple in bins: for rm_tuple in rms:
binary, version, parch = rm_tuple binary, version, parch = rm_tuple
p = binary + "/" + parch p = binary + "/" + parch
binaries_t_a, provides_t_a = packages_t[parch] binaries_t_a, provides_t_a = packages_t[parch]
pkey = (binary, parch)
pkg_data = binaries_t_a[binary] pkg_data = binaries_t_a[binary]
# save the old binary for undo # save the old binary for undo
undo['binaries'][p] = pkg_data undo['binaries'][p] = pkg_data
# all the reverse dependencies are affected by the change if pkey not in eqv_set:
# all the reverse dependencies are affected by
# the change
affected.update(get_reverse_tree(binary, parch)) affected.update(get_reverse_tree(binary, parch))
# remove the provided virtual packages # remove the provided virtual packages
for j in pkg_data[PROVIDES]: for j in pkg_data[PROVIDES]:
key = j + "/" + parch key = j + "/" + parch
@ -1982,7 +2004,7 @@ class Britney(object):
del provides_t_a[j] del provides_t_a[j]
# finally, remove the binary package # finally, remove the binary package
del binaries_t_a[binary] del binaries_t_a[binary]
self._inst_tester.remove_testing_binary(binary, version, parch) inst_tester.remove_testing_binary(binary, version, parch)
# remove the source package # remove the source package
if item.architecture == 'source': if item.architecture == 'source':
undo['sources'][item.package] = source undo['sources'][item.package] = source
@ -1999,7 +2021,7 @@ class Britney(object):
affected.update(get_reverse_tree(item.package, item.architecture)) affected.update(get_reverse_tree(item.package, item.architecture))
version = binaries_t_a[item.package][VERSION] version = binaries_t_a[item.package][VERSION]
del binaries_t_a[item.package] del binaries_t_a[item.package]
self._inst_tester.remove_testing_binary(item.package, version, item.architecture) inst_tester.remove_testing_binary(item.package, version, item.architecture)
# add the new binary packages (if we are not removing) # add the new binary packages (if we are not removing)
@ -2011,8 +2033,11 @@ class Britney(object):
if item.architecture not in ['source', parch]: continue if item.architecture not in ['source', parch]: continue
key = (binary, parch) key = (binary, parch)
binaries_t_a, provides_t_a = packages_t[parch] binaries_t_a, provides_t_a = packages_t[parch]
equivalent_replacement = key in eqv_set
# obviously, added/modified packages are affected # obviously, added/modified packages are affected
if key not in affected: affected.add(key) if not equivalent_replacement and key not in affected:
affected.add(key)
# if the binary already exists in testing, it is currently # if the binary already exists in testing, it is currently
# built by another source package. we therefore remove the # built by another source package. we therefore remove the
# version built by the other source package, after marking # version built by the other source package, after marking
@ -2021,13 +2046,16 @@ class Britney(object):
old_pkg_data = binaries_t_a[binary] old_pkg_data = binaries_t_a[binary]
# save the old binary package # save the old binary package
undo['binaries'][p] = old_pkg_data undo['binaries'][p] = old_pkg_data
# all the reverse dependencies are affected by the change if not equivalent_replacement:
# all the reverse dependencies are affected by
# the change
affected.update(get_reverse_tree(binary, parch)) affected.update(get_reverse_tree(binary, parch))
# all the reverse conflicts and their dependency tree are affected by the change # all the reverse conflicts and their
# dependency tree are affected by the change
for j in old_pkg_data[RCONFLICTS]: for j in old_pkg_data[RCONFLICTS]:
affected.update(get_reverse_tree(j, parch)) affected.update(get_reverse_tree(j, parch))
old_version = old_pkg_data[VERSION] old_version = old_pkg_data[VERSION]
self._inst_tester.remove_testing_binary(binary, old_version, parch) inst_tester.remove_testing_binary(binary, old_version, parch)
else: else:
# the binary isn't in testing, but it may have been at # the binary isn't in testing, but it may have been at
# the start of the current hint and have been removed # the start of the current hint and have been removed
@ -2045,11 +2073,12 @@ class Britney(object):
for rdep in tundo['binaries'][p][RDEPENDS]: for rdep in tundo['binaries'][p][RDEPENDS]:
if rdep in binaries_t_a and rdep not in source[BINARIES]: if rdep in binaries_t_a and rdep not in source[BINARIES]:
affected.update(get_reverse_tree(rdep, parch)) affected.update(get_reverse_tree(rdep, parch))
# add/update the binary package from the source suite # add/update the binary package from the source suite
new_pkg_data = packages_s[parch][0][binary] new_pkg_data = packages_s[parch][0][binary]
new_version = new_pkg_data[VERSION] new_version = new_pkg_data[VERSION]
binaries_t_a[binary] = new_pkg_data binaries_t_a[binary] = new_pkg_data
self._inst_tester.add_testing_binary(binary, new_version, parch) inst_tester.add_testing_binary(binary, new_version, parch)
# register new provided packages # register new provided packages
for j in new_pkg_data[PROVIDES]: for j in new_pkg_data[PROVIDES]:
key = j + "/" + parch key = j + "/" + parch
@ -2059,6 +2088,7 @@ class Britney(object):
elif key not in undo['virtual']: elif key not in undo['virtual']:
undo['virtual'][key] = provides_t_a[j][:] undo['virtual'][key] = provides_t_a[j][:]
provides_t_a[j].append(binary) provides_t_a[j].append(binary)
if not equivalent_replacement:
# all the reverse dependencies are affected by the change # all the reverse dependencies are affected by the change
affected.update(get_reverse_tree(binary, parch)) affected.update(get_reverse_tree(binary, parch))

@ -391,14 +391,7 @@ class InstallabilityTesterBuilder(object):
for pkg_list in find_eqv_table.itervalues(): for pkg_list in find_eqv_table.itervalues():
if len(pkg_list) < 2: if len(pkg_list) < 2:
continue continue
if (len(pkg_list) == 2 and pkg_list[0][0] == pkg_list[1][0]
and pkg_list[0][2] == pkg_list[1][2]):
# This is a (most likely) common and boring case. It
# is when pkgA depends on pkgB and is satisfied with
# any version available. However, at most one version
# of pkgB will be available in testing, so other
# filters will make this case redundant.
continue
eqv_set = frozenset(pkg_list) eqv_set = frozenset(pkg_list)
for pkg in pkg_list: for pkg in pkg_list:
eqv_table[pkg] = eqv_set eqv_table[pkg] = eqv_set

@ -98,6 +98,17 @@ class InstallabilityTester(object):
cbroken |= eqv_set cbroken |= eqv_set
def are_equivalent(self, p1, p2):
"""Test if p1 and p2 are equivalent
Returns True if p1 and p2 have the same "signature" in
the package dependency graph (i.e. relations can not tell
them appart sematically except for their name)
"""
eqv_table = self._eqv_table
return p1 in eqv_table and p2 in eqv_table[p1]
def add_testing_binary(self, pkg_name, pkg_version, pkg_arch): def add_testing_binary(self, pkg_name, pkg_version, pkg_arch):
"""Add a binary package to "testing" """Add a binary package to "testing"

Loading…
Cancel
Save