Merge lp:~jtv/launchpad/bug-884649-branch-5 into lp:launchpad

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Julian Edwards
Approved revision: no longer in the source branch.
Merged at revision: 14572
Proposed branch: lp:~jtv/launchpad/bug-884649-branch-5
Merge into: lp:launchpad
Diff against target: 292 lines (+67/-91)
2 files modified
lib/lp/archivepublisher/domination.py (+67/-78)
lib/lp/archivepublisher/tests/test_dominator.py (+0/-13)
To merge this branch: bzr merge lp:~jtv/launchpad/bug-884649-branch-5
Reviewer Review Type Date Requested Status
Julian Edwards (community) Approve
Review via email: mp+86518@code.launchpad.net

Commit message

[r=julian-edwards][bug=884649] Use denormalized [BS]PPH.[bs]pn columns in dominator.

Description of the change

= Summary =

To get to a source package publication record's source package name, we no longer have to go through the associated source package release. There is now a column on SourcePackagePublishingHistory that gives us the SourcePackageName. Similar for BinaryPackagePublishingHistory & BinaryPackageName.

== Pre-implementation notes ==

The work to introduce these new columns wasn't moving along so I helped optimize the populators, kept an eye on them, retired them, added NOT NULL constraints, and initialized the sample data accordingly.

Meanwhile, on the flip side of the coin, domination is actually pretty fast already now. It probably takes less than 10% of the publication process that we're trying to speed up (though it's close enough to its current run-time target that a few percent of optimization are probably still welcome). I chose to keep thebranch because it's also a chance to make things just a bit shorter.

== Implementation details ==

Sadly, the extra column on BPPH doesn't seem to help the dominator all that much — at least not in terms of code simplicity. Most use-cases need the BinaryPackageRelease as well anyway.

== Tests ==

{{{
./bin/test -vvc lp.archvepublisher -t dominator
}}}

== Demo and Q/A ==

Run publish-ftpmaster for Ubuntu. Domination should still work.

Similarly, run gina and verify domination for Debian.

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/archivepublisher/domination.py
  lib/lp/archivepublisher/tests/test_dominator.py

To post a comment you must log in.
Revision history for this message
Julian Edwards (julian-edwards) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/archivepublisher/domination.py'
--- lib/lp/archivepublisher/domination.py 2011-12-19 23:38:16 +0000
+++ lib/lp/archivepublisher/domination.py 2011-12-21 09:51:27 +0000
@@ -98,10 +98,15 @@
98apt_pkg.InitSystem()98apt_pkg.InitSystem()
9999
100100
101def join_spr_spn():101def join_spph_spn():
102 """Join condition: SourcePackageRelease/SourcePackageName."""102 """Join condition: SourcePackagePublishingHistory/SourcePackageName."""
103 return (103 # Avoid circular imports.
104 SourcePackageName.id == SourcePackageRelease.sourcepackagenameID)104 from lp.soyuz.model.publishing import SourcePackagePublishingHistory
105
106 SPPH = SourcePackagePublishingHistory
107 SPN = SourcePackageName
108
109 return SPN.id == SPPH.sourcepackagenameID
105110
106111
107def join_spph_spr():112def join_spph_spr():
@@ -110,9 +115,10 @@
110 # Avoid circular imports.115 # Avoid circular imports.
111 from lp.soyuz.model.publishing import SourcePackagePublishingHistory116 from lp.soyuz.model.publishing import SourcePackagePublishingHistory
112117
113 return (118 SPPH = SourcePackagePublishingHistory
114 SourcePackageRelease.id ==119 SPR = SourcePackageRelease
115 SourcePackagePublishingHistory.sourcepackagereleaseID)120
121 return SPR.id == SPPH.sourcepackagereleaseID
116122
117123
118class SourcePublicationTraits:124class SourcePublicationTraits:
@@ -127,7 +133,7 @@
127 @staticmethod133 @staticmethod
128 def getPackageName(spph):134 def getPackageName(spph):
129 """Return the name of this publication's source package."""135 """Return the name of this publication's source package."""
130 return spph.sourcepackagerelease.sourcepackagename.name136 return spph.sourcepackagename.name
131137
132 @staticmethod138 @staticmethod
133 def getPackageRelease(spph):139 def getPackageRelease(spph):
@@ -147,7 +153,7 @@
147 @staticmethod153 @staticmethod
148 def getPackageName(bpph):154 def getPackageName(bpph):
149 """Return the name of this publication's binary package."""155 """Return the name of this publication's binary package."""
150 return bpph.binarypackagerelease.binarypackagename.name156 return bpph.binarypackagename.name
151157
152 @staticmethod158 @staticmethod
153 def getPackageRelease(bpph):159 def getPackageRelease(bpph):
@@ -178,12 +184,6 @@
178 """Obtain the version string for a publication record."""184 """Obtain the version string for a publication record."""
179 return self.traits.getPackageRelease(pub).version185 return self.traits.getPackageRelease(pub).version
180186
181 def load_releases(self, pubs):
182 """Load the releases associated with a series of publications."""
183 return load_related(
184 self.traits.release_class, pubs,
185 [self.traits.release_reference_name])
186
187 def compare(self, pub1, pub2):187 def compare(self, pub1, pub2):
188 """Compare publications by version.188 """Compare publications by version.
189189
@@ -201,17 +201,7 @@
201201
202 def sortPublications(self, publications):202 def sortPublications(self, publications):
203 """Sort publications from most to least current versions."""203 """Sort publications from most to least current versions."""
204 # Listify; we want to iterate this twice, which won't do for a204 return sorted(publications, cmp=self.compare, reverse=True)
205 # non-persistent sequence.
206 publications = list(publications)
207 # Batch-load associated package releases; we'll be needing them
208 # to compare versions.
209 self.load_releases(publications)
210 # Now sort. This is that second iteration. An in-place sort
211 # won't hurt the original, because we're working on a copy of
212 # the original iterable.
213 publications.sort(cmp=self.compare, reverse=True)
214 return publications
215205
216206
217def find_live_source_versions(sorted_pubs):207def find_live_source_versions(sorted_pubs):
@@ -335,12 +325,20 @@
335 has active arch-specific publications.325 has active arch-specific publications.
336 :return: A list of live versions.326 :return: A list of live versions.
337 """327 """
328 # Avoid circular imports
329 from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
330
338 sorted_pubs = list(sorted_pubs)331 sorted_pubs = list(sorted_pubs)
339 latest = sorted_pubs.pop(0)332 latest = sorted_pubs.pop(0)
340 is_arch_specific = attrgetter('architecture_specific')333 is_arch_specific = attrgetter('architecture_specific')
341 arch_specific_pubs = list(ifilter(is_arch_specific, sorted_pubs))334 arch_specific_pubs = list(ifilter(is_arch_specific, sorted_pubs))
342 arch_indep_pubs = list(ifilterfalse(is_arch_specific, sorted_pubs))335 arch_indep_pubs = list(ifilterfalse(is_arch_specific, sorted_pubs))
343336
337 bpbs = load_related(
338 BinaryPackageBuild,
339 [pub.binarypackagerelease for pub in arch_indep_pubs], ['buildID'])
340 load_related(SourcePackageRelease, bpbs, ['source_package_release_id'])
341
344 reprieved_pubs = [342 reprieved_pubs = [
345 pub343 pub
346 for pub in arch_indep_pubs344 for pub in arch_indep_pubs
@@ -577,46 +575,33 @@
577 # Avoid circular imports.575 # Avoid circular imports.
578 from lp.soyuz.model.publishing import BinaryPackagePublishingHistory576 from lp.soyuz.model.publishing import BinaryPackagePublishingHistory
579577
578 BPPH = BinaryPackagePublishingHistory
579 BPR = BinaryPackageRelease
580
580 bpph_location_clauses = [581 bpph_location_clauses = [
581 BinaryPackagePublishingHistory.status ==582 BPPH.status == PackagePublishingStatus.PUBLISHED,
582 PackagePublishingStatus.PUBLISHED,583 BPPH.distroarchseries == distroarchseries,
583 BinaryPackagePublishingHistory.distroarchseries ==584 BPPH.archive == self.archive,
584 distroarchseries,585 BPPH.pocket == pocket,
585 BinaryPackagePublishingHistory.archive == self.archive,
586 BinaryPackagePublishingHistory.pocket == pocket,
587 ]586 ]
588 candidate_binary_names = Select(587 candidate_binary_names = Select(
589 BinaryPackageName.id,588 BPPH.binarypackagenameID, And(*bpph_location_clauses),
590 And(589 group_by=BPPH.binarypackagenameID, having=(Count() > 1))
591 BinaryPackageRelease.binarypackagenameID ==590 main_clauses = bpph_location_clauses + [
592 BinaryPackageName.id,591 BPR.id == BPPH.binarypackagereleaseID,
593 BinaryPackagePublishingHistory.binarypackagereleaseID ==592 BPR.binarypackagenameID.is_in(candidate_binary_names),
594 BinaryPackageRelease.id,593 BPR.binpackageformat != BinaryPackageFormat.DDEB,
595 bpph_location_clauses,
596 ),
597 group_by=BinaryPackageName.id,
598 having=Count(BinaryPackagePublishingHistory.id) > 1)
599 main_clauses = [
600 BinaryPackageRelease.id ==
601 BinaryPackagePublishingHistory.binarypackagereleaseID,
602 BinaryPackageRelease.binarypackagenameID.is_in(
603 candidate_binary_names),
604 BinaryPackageRelease.binpackageformat !=
605 BinaryPackageFormat.DDEB,
606 ]594 ]
607 main_clauses.extend(bpph_location_clauses)
608
609 store = IStore(BinaryPackagePublishingHistory)
610595
611 # We're going to access the BPRs as well. Since we make the596 # We're going to access the BPRs as well. Since we make the
612 # database look them up anyway, and since there won't be many597 # database look them up anyway, and since there won't be many
613 # duplications among them, load them alongside the publications.598 # duplications among them, load them alongside the publications.
614 # We'll also want their BinaryPackageNames, but adding those to599 # We'll also want their BinaryPackageNames, but adding those to
615 # the join would complicate the query.600 # the join would complicate the query.
616 query = store.find(601 query = IStore(BPPH).find((BPPH, BPR), *main_clauses)
617 (BinaryPackagePublishingHistory, BinaryPackageRelease),602 bpphs = list(DecoratedResultSet(query, itemgetter(0)))
618 *main_clauses)603 load_related(BinaryPackageName, bpphs, ['binarypackagenameID'])
619 return DecoratedResultSet(query, itemgetter(0))604 return bpphs
620605
621 def dominateBinaries(self, distroseries, pocket):606 def dominateBinaries(self, distroseries, pocket):
622 """Perform domination on binary package publications.607 """Perform domination on binary package publications.
@@ -684,12 +669,13 @@
684 # Avoid circular imports.669 # Avoid circular imports.
685 from lp.soyuz.model.publishing import SourcePackagePublishingHistory670 from lp.soyuz.model.publishing import SourcePackagePublishingHistory
686671
672 SPPH = SourcePackagePublishingHistory
673
687 return And(674 return And(
688 SourcePackagePublishingHistory.status ==675 SPPH.status == PackagePublishingStatus.PUBLISHED,
689 PackagePublishingStatus.PUBLISHED,676 SPPH.distroseries == distroseries,
690 SourcePackagePublishingHistory.distroseries == distroseries,677 SPPH.archive == self.archive,
691 SourcePackagePublishingHistory.archive == self.archive,678 SPPH.pocket == pocket,
692 SourcePackagePublishingHistory.pocket == pocket,
693 )679 )
694680
695 def findSourcesForDomination(self, distroseries, pocket):681 def findSourcesForDomination(self, distroseries, pocket):
@@ -706,15 +692,16 @@
706 # Avoid circular imports.692 # Avoid circular imports.
707 from lp.soyuz.model.publishing import SourcePackagePublishingHistory693 from lp.soyuz.model.publishing import SourcePackagePublishingHistory
708694
695 SPPH = SourcePackagePublishingHistory
696 SPR = SourcePackageRelease
697
709 spph_location_clauses = self._composeActiveSourcePubsCondition(698 spph_location_clauses = self._composeActiveSourcePubsCondition(
710 distroseries, pocket)699 distroseries, pocket)
711 having_multiple_active_publications = (
712 Count(SourcePackagePublishingHistory.id) > 1)
713 candidate_source_names = Select(700 candidate_source_names = Select(
714 SourcePackageName.id,701 SPPH.sourcepackagenameID,
715 And(join_spph_spr(), join_spr_spn(), spph_location_clauses),702 And(join_spph_spr(), spph_location_clauses),
716 group_by=SourcePackageName.id,703 group_by=SPPH.sourcepackagenameID,
717 having=having_multiple_active_publications)704 having=(Count() > 1))
718705
719 # We'll also access the SourcePackageReleases associated with706 # We'll also access the SourcePackageReleases associated with
720 # the publications we find. Since they're in the join anyway,707 # the publications we find. Since they're in the join anyway,
@@ -722,13 +709,14 @@
722 # Actually we'll also want the SourcePackageNames, but adding709 # Actually we'll also want the SourcePackageNames, but adding
723 # those to the (outer) query would complicate it, and710 # those to the (outer) query would complicate it, and
724 # potentially slow it down.711 # potentially slow it down.
725 query = IStore(SourcePackagePublishingHistory).find(712 query = IStore(SPPH).find(
726 (SourcePackagePublishingHistory, SourcePackageRelease),713 (SPPH, SPR),
727 join_spph_spr(),714 join_spph_spr(),
728 SourcePackageRelease.sourcepackagenameID.is_in(715 SPPH.sourcepackagenameID.is_in(candidate_source_names),
729 candidate_source_names),
730 spph_location_clauses)716 spph_location_clauses)
731 return DecoratedResultSet(query, itemgetter(0))717 spphs = DecoratedResultSet(query, itemgetter(0))
718 load_related(SourcePackageName, spphs, ['sourcepackagenameID'])
719 return spphs
732720
733 def dominateSources(self, distroseries, pocket):721 def dominateSources(self, distroseries, pocket):
734 """Perform domination on source package publications.722 """Perform domination on source package publications.
@@ -771,7 +759,7 @@
771 result = IStore(SourcePackageName).find(759 result = IStore(SourcePackageName).find(
772 looking_for,760 looking_for,
773 join_spph_spr(),761 join_spph_spr(),
774 join_spr_spn(),762 join_spph_spn(),
775 self._composeActiveSourcePubsCondition(distroseries, pocket))763 self._composeActiveSourcePubsCondition(distroseries, pocket))
776 return result.group_by(SourcePackageName.name)764 return result.group_by(SourcePackageName.name)
777765
@@ -780,18 +768,19 @@
780 # Avoid circular imports.768 # Avoid circular imports.
781 from lp.soyuz.model.publishing import SourcePackagePublishingHistory769 from lp.soyuz.model.publishing import SourcePackagePublishingHistory
782770
771 SPPH = SourcePackagePublishingHistory
772 SPR = SourcePackageRelease
773
783 query = IStore(SourcePackagePublishingHistory).find(774 query = IStore(SourcePackagePublishingHistory).find(
784 SourcePackagePublishingHistory,775 SPPH,
785 join_spph_spr(),776 join_spph_spr(),
786 join_spr_spn(),777 join_spph_spn(),
787 SourcePackageName.name == package_name,778 SourcePackageName.name == package_name,
788 self._composeActiveSourcePubsCondition(distroseries, pocket))779 self._composeActiveSourcePubsCondition(distroseries, pocket))
789 # Sort by descending version (SPR.version has type debversion in780 # Sort by descending version (SPR.version has type debversion in
790 # the database, so this should be a real proper comparison) so781 # the database, so this should be a real proper comparison) so
791 # that _sortPackage will have slightly less work to do later.782 # that _sortPackage will have slightly less work to do later.
792 return query.order_by(783 return query.order_by(Desc(SPR.version), Desc(SPPH.datecreated))
793 Desc(SourcePackageRelease.version),
794 Desc(SourcePackagePublishingHistory.datecreated))
795784
796 def dominateSourceVersions(self, distroseries, pocket, package_name,785 def dominateSourceVersions(self, distroseries, pocket, package_name,
797 live_versions):786 live_versions):
798787
=== modified file 'lib/lp/archivepublisher/tests/test_dominator.py'
--- lib/lp/archivepublisher/tests/test_dominator.py 2011-11-04 19:11:18 +0000
+++ lib/lp/archivepublisher/tests/test_dominator.py 2011-12-21 09:51:27 +0000
@@ -473,19 +473,6 @@
473 bpph.binarypackagerelease.version,473 bpph.binarypackagerelease.version,
474 GeneralizedPublication(is_source=False).getPackageVersion(bpph))474 GeneralizedPublication(is_source=False).getPackageVersion(bpph))
475475
476 def test_load_releases_loads_sourcepackagerelease(self):
477 spph = self.factory.makeSourcePackagePublishingHistory()
478 self.assertContentEqual(
479 [spph.sourcepackagerelease],
480 GeneralizedPublication(is_source=True).load_releases([spph]))
481
482 def test_load_releases_loads_binarypackagerelease(self):
483 bpph = self.factory.makeBinaryPackagePublishingHistory(
484 binarypackagerelease=self.factory.makeBinaryPackageRelease())
485 self.assertContentEqual(
486 [bpph.binarypackagerelease],
487 GeneralizedPublication(is_source=False).load_releases([bpph]))
488
489 def test_compare_sorts_versions(self):476 def test_compare_sorts_versions(self):
490 versions = [477 versions = [
491 '1.1v2',478 '1.1v2',