Merge lp:~michael.nelson/launchpad/copy-binaries-timeout into lp:launchpad

Proposed by Michael Nelson
Status: Merged
Approved by: Muharem Hrnjadovic
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~michael.nelson/launchpad/copy-binaries-timeout
Merge into: lp:launchpad
Diff against target: 196 lines
3 files modified
lib/lp/soyuz/interfaces/publishing.py (+17/-0)
lib/lp/soyuz/model/publishing.py (+69/-26)
lib/lp/soyuz/scripts/packagecopier.py (+6/-25)
To merge this branch: bzr merge lp:~michael.nelson/launchpad/copy-binaries-timeout
Reviewer Review Type Date Requested Status
Muharem Hrnjadovic (community) Approve
Review via email: mp+14157@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Michael Nelson (michael.nelson) wrote :

= Summary =

This branch addresses some of the causes of bug 447138.

Five options for improving the performance when copying a large number
of binaries are identified at:
https://bugs.edge.launchpad.net/soyuz/+bug/447138/comments/1

This branch addresses points (1) and (4).

== Proposed fix ==

Create IPublishingSet.copyBinariesTo() so that we only need to lookup
the 'main' component once (point 1 above) and only need one query to
obtain all the newly created BPPHs.

== Pre-implementation notes ==

See comment #1 on bug above.

== Implementation details ==

== Tests ==

bin/test -vv -t test_copypackage -t doc/pubishing.txt

== Demo and Q/A ==

I'll start Q/Aing this on dogfood now. In production we can ask the arch
admins to try including binaries when copying linux kernel package.

= Launchpad lint =

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/lp/soyuz/scripts/packagecopier.py
  lib/lp/soyuz/model/publishing.py
  lib/lp/soyuz/interfaces/publishing.py

== Pylint notices ==

lib/lp/soyuz/scripts/packagecopier.py
    27: [F0401] Unable to import 'lazr.delegates' (No module named
delegates)

lib/lp/soyuz/interfaces/publishing.py
    33: [F0401] Unable to import 'lazr.enum' (No module named enum)
    40: [F0401] Unable to import 'lazr.restful.fields' (No module named
restful)
    41: [F0401] Unable to import 'lazr.restful.declarations' (No module
named restful)

--
Michael

Revision history for this message
Muharem Hrnjadovic (al-maisan) wrote :

Looks good, needs more testing/corroboration on the Soyuz dogfood system prior to landing though.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/soyuz/interfaces/publishing.py'
2--- lib/lp/soyuz/interfaces/publishing.py 2009-10-05 18:29:12 +0000
3+++ lib/lp/soyuz/interfaces/publishing.py 2009-10-29 12:30:28 +0000
4@@ -856,6 +856,23 @@
5 class IPublishingSet(Interface):
6 """Auxiliary methods for dealing with sets of publications."""
7
8+ def copyBinariesTo(binaries, distroseries, pocket, archive):
9+ """Copy multiple binaries to a given destination.
10+
11+ Processing multiple binaries in a batch allows certain
12+ performance optimisations such as looking up the main
13+ component once only, and getting all the BPPH records
14+ with one query.
15+
16+ :param binaries: A list of binaries to copy.
17+ :param distroseries: The target distroseries.
18+ :param pocket: The target pocket.
19+ :param archive: The target archive.
20+
21+ :return: A result set of the created binary package
22+ publishing histories.
23+ """
24+
25 def newBinaryPublication(archive, binarypackagerelease, distroarchseries,
26 component, section, priority, pocket):
27 """Create a new `BinaryPackagePublishingHistory`.
28
29=== modified file 'lib/lp/soyuz/model/publishing.py'
30--- lib/lp/soyuz/model/publishing.py 2009-10-06 11:16:03 +0000
31+++ lib/lp/soyuz/model/publishing.py 2009-10-29 12:30:28 +0000
32@@ -1049,32 +1049,9 @@
33
34 def copyTo(self, distroseries, pocket, archive):
35 """See `BinaryPackagePublishingHistory`."""
36- current = self.secure_record
37-
38- if current.binarypackagerelease.architecturespecific:
39- try:
40- target_architecture = distroseries[
41- current.distroarchseries.architecturetag]
42- except NotFoundError:
43- return []
44- destination_architectures = [target_architecture]
45- else:
46- destination_architectures = distroseries.architectures
47-
48- copies = []
49- for architecture in destination_architectures:
50- copy = getUtility(IPublishingSet).newBinaryPublication(
51- archive,
52- self.binarypackagerelease,
53- architecture,
54- current.component,
55- current.section,
56- current.priority,
57- pocket
58- )
59- copies.append(copy)
60-
61- return copies
62+
63+ return getUtility(IPublishingSet).copyBinariesTo(
64+ [self], distroseries, pocket, archive)
65
66 def getAncestry(self, archive=None, distroseries=None, pocket=None,
67 status=None):
68@@ -1120,6 +1097,72 @@
69
70 implements(IPublishingSet)
71
72+ def copyBinariesTo(self, binaries, distroseries, pocket, archive):
73+ """See `IPublishingSet`."""
74+
75+ # If the target archive is a ppa then we will need to override
76+ # the component for each copy - so lookup the main component
77+ # here once.
78+ override_component = None
79+ if archive.is_ppa:
80+ override_component = getUtility(IComponentSet)['main']
81+
82+ secure_copies = []
83+
84+ for binary in binaries:
85+ binarypackagerelease = binary.binarypackagerelease
86+ target_component = override_component or binary.component
87+
88+ if binarypackagerelease.architecturespecific:
89+ # If the binary is architecture specific and the target
90+ # distroseries does not include the architecture then we
91+ # skip the binary and continue.
92+ try:
93+ # For safety, we use the architecture the binary was
94+ # built, and not the one it is published, coping with
95+ # single arch-indep publications for architectures that
96+ # do not exist in the destination series.
97+ # See #387589 for more information.
98+ target_architecture = distroseries[
99+ binarypackagerelease.build.arch_tag]
100+ except NotFoundError:
101+ continue
102+ destination_architectures = [target_architecture]
103+ else:
104+ destination_architectures = distroseries.architectures
105+
106+ for distroarchseries in destination_architectures:
107+
108+ # We only copy the binary if it doesn't already exist
109+ # in the destination.
110+ binary_in_destination = archive.getAllPublishedBinaries(
111+ name=binarypackagerelease.name, exact_match=True,
112+ version=binarypackagerelease.version,
113+ status=active_publishing_status, pocket=pocket,
114+ distroarchseries=distroarchseries)
115+
116+ if binary_in_destination.count() == 0:
117+ pub = SecureBinaryPackagePublishingHistory(
118+ archive=archive,
119+ binarypackagerelease=binarypackagerelease,
120+ distroarchseries=distroarchseries,
121+ component=target_component,
122+ section=binary.section,
123+ priority=binary.priority,
124+ status=PackagePublishingStatus.PENDING,
125+ datecreated=UTC_NOW,
126+ pocket=pocket,
127+ embargo=False)
128+ secure_copies.append(pub)
129+
130+ # One day, this will not be necessary when we have time to kill
131+ # the Secure* records.
132+ copy_ids = [secure_copy.id for secure_copy in secure_copies]
133+
134+ store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
135+ return store.find(BinaryPackagePublishingHistory,
136+ BinaryPackagePublishingHistory.id.is_in(copy_ids))
137+
138 def newBinaryPublication(self, archive, binarypackagerelease,
139 distroarchseries, component, section, priority,
140 pocket):
141
142=== modified file 'lib/lp/soyuz/scripts/packagecopier.py'
143--- lib/lp/soyuz/scripts/packagecopier.py 2009-08-24 20:09:38 +0000
144+++ lib/lp/soyuz/scripts/packagecopier.py 2009-10-29 12:30:28 +0000
145@@ -22,7 +22,6 @@
146
147 from zope.component import getUtility
148
149-from canonical.launchpad.interfaces.launchpad import NotFoundError
150 from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet
151 from canonical.librarian.utils import copy_and_close
152 from lazr.delegates import delegates
153@@ -33,8 +32,8 @@
154 from lp.soyuz.interfaces.build import (
155 BuildStatus, BuildSetStatus)
156 from lp.soyuz.interfaces.publishing import (
157- IBinaryPackagePublishingHistory, ISourcePackagePublishingHistory,
158- active_publishing_status)
159+ IBinaryPackagePublishingHistory, IPublishingSet,
160+ ISourcePackagePublishingHistory, active_publishing_status)
161 from lp.soyuz.interfaces.queue import (
162 IPackageUpload, IPackageUploadSet)
163 from lp.soyuz.scripts.ftpmasterbase import (
164@@ -520,28 +519,10 @@
165 # unique publication per binary package releases (i.e. excludes
166 # irrelevant arch-indep publications) and IBPPH.copy is prepared
167 # to expand arch-indep publications.
168- # For safety, we use the architecture the binary was built, and
169- # not the one it is published, coping with single arch-indep
170- # publications for architectures that do not exist in the
171- # destination series. See #387589 for more information.
172- for binary in source.getBuiltBinaries():
173- binarypackagerelease = binary.binarypackagerelease
174- try:
175- target_distroarchseries = series[
176- binarypackagerelease.build.arch_tag]
177- except NotFoundError:
178- # It is not an error if the destination series doesn't
179- # support all the architectures originally built. We
180- # simply do not copy the binary and life goes on.
181- continue
182- binary_in_destination = archive.getAllPublishedBinaries(
183- name=binarypackagerelease.name, exact_match=True,
184- version=binarypackagerelease.version,
185- status=active_publishing_status, pocket=pocket,
186- distroarchseries=target_distroarchseries)
187- if binary_in_destination.count() == 0:
188- binary_copy = binary.copyTo(series, pocket, archive)
189- copies.extend(binary_copy)
190+ binary_copies = getUtility(IPublishingSet).copyBinariesTo(
191+ source.getBuiltBinaries(), series, pocket, archive)
192+
193+ copies.extend(binary_copies)
194
195 # Always ensure the needed builds exist in the copy destination
196 # after copying the binaries.