Merge lp:~edwin-grubbs/launchpad/bug-535430-needspackaging-timeout-part3 into lp:launchpad/db-devel

Proposed by Edwin Grubbs
Status: Merged
Approved by: Edwin Grubbs
Approved revision: no longer in the source branch.
Merged at revision: 9497
Proposed branch: lp:~edwin-grubbs/launchpad/bug-535430-needspackaging-timeout-part3
Merge into: lp:launchpad/db-devel
Prerequisite: lp:~edwin-grubbs/launchpad/bug-535430-needspackaging-timeout-part3-base
Diff against target: 347 lines (+97/-80)
6 files modified
database/schema/comments.sql (+1/-1)
database/schema/patch-2207-56-0.sql (+52/-1)
lib/lp/registry/doc/distroseries.txt (+1/-1)
lib/lp/registry/model/distributionsourcepackage.py (+33/-47)
lib/lp/registry/model/distroseries.py (+9/-29)
lib/lp/registry/templates/distroseries-needs-packaging.pt (+1/-1)
To merge this branch: bzr merge lp:~edwin-grubbs/launchpad/bug-535430-needspackaging-timeout-part3
Reviewer Review Type Date Requested Status
Stuart Bishop (community) db Approve
Brad Crittenden (community) code Approve
Björn Tillenius db Pending
Review via email: mp+28240@code.launchpad.net

Description of the change

Summary
-------

This branch extends the work from
bug-535430-needspackaging-timeout-part2, which was landed in db-devel
revision 9449 but got reverted in revision 9451 due to the NOT NULL
constraint on the DistributionSourcePackage.section column that was
added. After looking into it more, it became apparent that caching the
section in the DSP table wasn't really necessary, since it was only used
to guess if a package is a metapackage by checking if it was in the
'misc' section. A metapackage does not need a link to its upstream
project, so it can be safely ignored by the
$distroseries/+needs-packaging page, which is what we are optimizing in
the first place.

This branch changes the db patch to add the is_upstream_link_allowed
boolean to the DistributionSourcePackage table instead of the section
foreign key.

Implementation details
----------------------

DistributionSourcePackage.is_upstream_link_allowed:
    database/schema/comments.sql
    database/schema/patch-2207-56-0.sql
    lib/lp/registry/model/distributionsourcepackage.py

Modified the getPrioritizedUnlinkedSourcePackages() method that the
+needs-packaging page uses:
    lib/lp/registry/model/distroseries.py
    lib/lp/registry/templates/distroseries-needs-packaging.pt
    lib/lp/registry/doc/distroseries.txt

Tests
-----

./bin/test -vv -t 'xx-show-distroseries-packaging.txt|xx-sourcepackage-packaging.txt|doc/distroseries.txt|test_distroseries|bugheat|bug-heat'

Demo and Q/A
------------

* Open http://launchpad.dev/ubuntu/hoary/+needs-packaging
  * On staging, this should no longer timeout.

To post a comment you must log in.
Revision history for this message
Brad Crittenden (bac) wrote :

Hi Edwin,

We already discussed some of these on IRC:

* "Whether an upstream link should be added if it does not already exist." s/should/may

* For clarity I'd change
   is_upstream_link_allowed = spph.section.name == 'misc' to
   is_upstream_link_allowed = (spph.section.name == 'misc')

I also note that code appears twice in the module. Perhaps you can refactor it.

Otherwise the branch looks good. Thanks.

review: Approve (code)
Revision history for this message
Stuart Bishop (stub) wrote :

The first INSERT needs an ORDER BY clause, or we could end up with inconsistent data between the master and slave databases:

INSERT INTO DistributionSourcePackage (distribution,sourcepackagename)
SELECT ds.distribution, sourcepackagename
FROM SourcePackagePublishingHistory spph
JOIN Archive ON spph.archive = Archive.id
JOIN SourcePackageRelease spr ON spph.sourcepackagerelease = spr.id
JOIN DistroSeries ds ON spph.distroseries = ds.id
WHERE ds.releasestatus = 4 -- CURRENT
    AND Archive.purpose = 1 -- PRIMARY
EXCEPT
SELECT distribution, sourcepackagename
FROM DistributionSourcePackage
ORDER BY distribution, sourcepackagename;

We also need to repack the table when we are done, so add at the end:

CLUSTER DistributionSourcePackage
    USING distributionpackage__sourcepackagename__distribution__key;

review: Approve (db)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'database/schema/comments.sql'
2--- database/schema/comments.sql 2010-06-25 17:47:31 +0000
3+++ database/schema/comments.sql 2010-06-25 17:47:32 +0000
4@@ -476,7 +476,7 @@
5 COMMENT ON COLUMN DistributionSourcePackage.total_bug_heat IS 'Sum of bug heat matching the package distribution and sourcepackagename. NULL means it has not yet been calculated.';
6 COMMENT ON COLUMN DistributionSourcePackage.bug_count IS 'Number of bugs matching the package distribution and sourcepackagename. NULL means it has not yet been calculated.';
7 COMMENT ON COLUMN DistributionSourcePackage.po_message_count IS 'Number of translations matching the package distribution and sourcepackagename. NULL means it has not yet been calculated.';
8-COMMENT ON COLUMN DistributionSourcePackage.section IS 'Cached section matching the latest SourcePackagePublishingHistory record by distribution and sourcepackagename whose archive purpose is PRIMARY and whose distroseries releasestatus is CURRENT.';
9+COMMENT ON COLUMN DistributionSourcePackage.is_upstream_link_allowed IS 'Whether an upstream link may be added if it does not already exist.';
10 COMMENT ON COLUMN DistributionSourcePackage.bug_reported_acknowledgement IS 'A message of acknowledgement to display to a bug reporter after they\'ve reported a new bug.';
11
12 -- DistributionSourcePackageCache
13
14=== modified file 'database/schema/patch-2207-56-0.sql'
15--- database/schema/patch-2207-56-0.sql 2010-06-25 17:47:31 +0000
16+++ database/schema/patch-2207-56-0.sql 2010-06-25 17:47:32 +0000
17@@ -21,4 +21,55 @@
18 ALTER TABLE DistributionSourcePackage ADD COLUMN bug_count INTEGER;
19 ALTER TABLE DistributionSourcePackage ADD COLUMN po_message_count INTEGER;
20 ALTER TABLE DistributionSourcePackage
21- ADD COLUMN section INTEGER NOT NULL REFERENCES section(id);
22+ ADD COLUMN is_upstream_link_allowed BOOLEAN NOT NULL DEFAULT TRUE;
23+
24+/* Add DistributionSourcePackage row for each
25+ * SourcePackagePublishingHistory entry whose archive is primary and
26+ * whose distroseries is current.
27+ */
28+INSERT INTO DistributionSourcePackage (
29+ distribution,
30+ sourcepackagename
31+ )
32+ SELECT
33+ ds.distribution,
34+ sourcepackagename
35+ FROM SourcePackagePublishingHistory spph
36+ JOIN Archive ON spph.archive = Archive.id
37+ JOIN SourcePackageRelease spr ON spph.sourcepackagerelease = spr.id
38+ JOIN DistroSeries ds ON spph.distroseries = ds.id
39+ WHERE ds.releasestatus = 4 -- CURRENT
40+ AND Archive.purpose = 1 -- PRIMARY
41+ EXCEPT
42+ SELECT
43+ distribution,
44+ sourcepackagename
45+ FROM DistributionSourcePackage
46+ORDER BY distribution, sourcepackagename;
47+
48+
49+
50+/* Update cached bug values in DistributionSourcePackage. */
51+UPDATE DistributionSourcePackage
52+SET max_bug_heat = subquery.max_bug_heat,
53+ total_bug_heat = subquery.total_bug_heat,
54+ bug_count = subquery.bug_count
55+FROM (
56+ SELECT
57+ COALESCE(MAX(Bug.heat), 0) as max_bug_heat,
58+ COALESCE(SUM(Bug.heat), 0) as total_bug_heat,
59+ COALESCE(COUNT(Bug.id), 0) as bug_count,
60+ distribution as distro,
61+ sourcepackagename as spn
62+ FROM
63+ DistributionSourcePackage
64+ LEFT JOIN BugTask USING(distribution, sourcepackagename)
65+ LEFT JOIN Bug ON BugTask.bug = Bug.id
66+ GROUP BY distribution, sourcepackagename
67+ ) AS subquery
68+WHERE distribution = distro
69+ AND sourcepackagename = spn;
70+
71+
72+CLUSTER DistributionSourcePackage
73+ USING distributionpackage__sourcepackagename__distribution__key;
74
75=== modified file 'lib/lp/registry/doc/distroseries.txt'
76--- lib/lp/registry/doc/distroseries.txt 2010-05-18 13:55:07 +0000
77+++ lib/lp/registry/doc/distroseries.txt 2010-06-25 17:47:32 +0000
78@@ -449,7 +449,7 @@
79
80 >>> for summary in hoary.getPrioritizedUnlinkedSourcePackages():
81 ... print summary['package'].name
82- ... print '%(total_bugs)s %(total_messages)s' % summary
83+ ... print '%(bug_count)s %(total_messages)s' % summary
84 pmount 0 64
85 alsa-utils 0 0
86 cnews 0 0
87
88=== modified file 'lib/lp/registry/model/distributionsourcepackage.py'
89--- lib/lp/registry/model/distributionsourcepackage.py 2010-06-25 17:47:31 +0000
90+++ lib/lp/registry/model/distributionsourcepackage.py 2010-06-25 17:47:32 +0000
91@@ -17,7 +17,7 @@
92 from sqlobject.sqlbuilder import SQLConstant
93 from storm.expr import And, Count, Desc, In, Join, Lower, Max, Sum
94 from storm.store import EmptyResultSet
95-from storm.locals import Int, Reference, Store, Storm, Unicode
96+from storm.locals import Bool, Int, Reference, Store, Storm, Unicode
97 from zope.component import getUtility
98 from zope.error.interfaces import IErrorReportingUtility
99 from zope.interface import implements
100@@ -25,7 +25,6 @@
101
102 from canonical.database.sqlbase import sqlvalues
103 from canonical.launchpad.database.emailaddress import EmailAddress
104-from lp.registry.interfaces.series import SeriesStatus
105 from lp.registry.model.distroseries import DistroSeries
106 from lp.registry.model.packaging import Packaging
107 from lp.registry.model.structuralsubscription import (
108@@ -47,7 +46,6 @@
109 SourcePackage, SourcePackageQuestionTargetMixin)
110 from lp.soyuz.interfaces.archive import ArchivePurpose
111 from lp.soyuz.interfaces.publishing import PackagePublishingStatus
112-from lp.soyuz.interfaces.section import ISectionSet
113 from lp.soyuz.model.archive import Archive
114 from lp.soyuz.model.distributionsourcepackagerelease import (
115 DistributionSourcePackageRelease)
116@@ -58,6 +56,15 @@
117 from lp.translations.model.customlanguagecode import (
118 CustomLanguageCode, HasCustomLanguageCodesMixin)
119
120+def is_upstream_link_allowed(spph):
121+ """Metapackages shouldn't have upstream links.
122+
123+ Metapackages normally are in the 'misc' section.
124+ """
125+ if spph is None:
126+ return True
127+ return spph.section.name == 'misc'
128+
129
130 class DistributionSourcePackageProperty:
131 def __init__(self, attrname):
132@@ -85,11 +92,8 @@
133 SourcePackageRelease.sourcepackagenameID ==
134 obj.sourcepackagename.id
135 ).order_by(Desc(SourcePackagePublishingHistory.id)).first()
136- if spph is None:
137- section = getUtility(ISectionSet)['misc']
138- else:
139- section = spph.section
140- obj._new(obj.distribution, obj.sourcepackagename, section)
141+ obj._new(obj.distribution, obj.sourcepackagename,
142+ is_upstream_link_allowed(spph))
143 setattr(obj._self_in_database, self.attrname, value)
144
145
146@@ -119,7 +123,8 @@
147 total_bug_heat = DistributionSourcePackageProperty('total_bug_heat')
148 bug_count = DistributionSourcePackageProperty('bug_count')
149 po_message_count = DistributionSourcePackageProperty('po_message_count')
150- section = DistributionSourcePackageProperty('section')
151+ is_upstream_link_allowed = DistributionSourcePackageProperty(
152+ 'is_upstream_link_allowed')
153
154 def __init__(self, distribution, sourcepackagename):
155 self.distribution = distribution
156@@ -171,30 +176,19 @@
157
158 def recalculateBugHeatCache(self):
159 """See `IHasBugHeat`."""
160- self.max_bug_heat = IStore(Bug).find(
161- Max(Bug.heat),
162- BugTask.bug == Bug.id,
163- BugTask.distributionID == self.distribution.id,
164- BugTask.sourcepackagenameID == self.sourcepackagename.id).one()
165- if self.max_bug_heat is None:
166- # SELECT MAX(Bug.heat) returns NULL if zero rows match.
167- self.max_bug_heat = 0
168-
169- self.total_bug_heat = IStore(Bug).find(
170- Sum(Bug.heat),
171- BugTask.bug == Bug.id,
172- BugTask.distributionID == self.distribution.id,
173- BugTask.sourcepackagenameID == self.sourcepackagename.id).one()
174- if self.total_bug_heat is None:
175- self.total_bug_heat = 0
176-
177- self.bug_count = IStore(Bug).find(
178- Count(Bug.heat),
179- BugTask.bug == Bug.id,
180- BugTask.distributionID == self.distribution.id,
181- BugTask.sourcepackagenameID == self.sourcepackagename.id).one()
182- if self.bug_count is None:
183- self.bug_count = 0
184+ row = IStore(Bug).find(
185+ (Max(Bug.heat), Sum(Bug.heat), Count(Bug.id)),
186+ BugTask.bug == Bug.id,
187+ BugTask.distributionID == self.distribution.id,
188+ BugTask.sourcepackagenameID == self.sourcepackagename.id).one()
189+
190+ # Aggregate functions return NULL if zero rows match.
191+ row = list(row)
192+ for i in range(len(row)):
193+ if row[i] is None:
194+ row[i] = 0
195+
196+ self.max_bug_heat, self.total_bug_heat, self.bug_count = row
197
198 @property
199 def latest_overall_publication(self):
200@@ -523,11 +517,12 @@
201 ).one()
202
203 @classmethod
204- def _new(cls, distribution, sourcepackagename, section):
205+ def _new(cls, distribution, sourcepackagename,
206+ is_upstream_link_allowed=False):
207 dsp = DistributionSourcePackageInDatabase()
208 dsp.distribution = distribution
209 dsp.sourcepackagename = sourcepackagename
210- dsp.section = section
211+ dsp.is_upstream_link_allowed = is_upstream_link_allowed
212 Store.of(distribution).add(dsp)
213 return dsp
214
215@@ -536,22 +531,15 @@
216 """Create DistributionSourcePackage record, if necessary.
217
218 Only create a record for primary archives (i.e. not for PPAs).
219- If it already exists, update the section attribute.
220 """
221- # Import here to avoid import loop.
222 sourcepackagename = spph.sourcepackagerelease.sourcepackagename
223 distribution = spph.distroseries.distribution
224- section = spph.section
225
226 if spph.archive.purpose == ArchivePurpose.PRIMARY:
227 dsp = cls._get(distribution, sourcepackagename)
228 if dsp is None:
229- dsp = cls._new(distribution, sourcepackagename, section)
230- elif spph.distroseries.status == SeriesStatus.CURRENT:
231- # If the distroseries.status is not CURRENT, it should
232- # not override the section from a previously created
233- # SourcePackagePublishingHistory.
234- dsp.section = section
235+ cls._new(distribution, sourcepackagename,
236+ is_upstream_link_allowed(spph))
237
238
239 class DistributionSourcePackageInDatabase(Storm):
240@@ -581,6 +569,4 @@
241 total_bug_heat = Int()
242 bug_count = Int()
243 po_message_count = Int()
244-
245- section_id = Int(name='section')
246- section = Reference(section_id, 'Section.id')
247+ is_upstream_link_allowed = Bool()
248
249=== modified file 'lib/lp/registry/model/distroseries.py'
250--- lib/lp/registry/model/distroseries.py 2010-06-15 09:10:01 +0000
251+++ lib/lp/registry/model/distroseries.py 2010-06-25 17:47:32 +0000
252@@ -48,7 +48,6 @@
253 from lp.bugs.model.bugtarget import BugTargetBase, HasBugHeatMixin
254 from lp.bugs.model.bugtask import BugTask
255 from lp.bugs.interfaces.bugtarget import IHasBugHeat
256-from lp.bugs.interfaces.bugtask import UNRESOLVED_BUGTASK_STATUSES
257 from lp.soyuz.model.component import Component
258 from lp.soyuz.model.distroarchseries import (
259 DistroArchSeries, DistroArchSeriesSet, PocketChroot)
260@@ -326,9 +325,9 @@
261 find_spec = (
262 SourcePackageName,
263 SQL("""
264- coalesce(total_heat, 0) + coalesce(po_messages, 0) +
265+ coalesce(total_bug_heat, 0) + coalesce(po_messages, 0) +
266 CASE WHEN spr.component = 1 THEN 1000 ELSE 0 END AS score"""),
267- SQL("coalesce(total_bugs, 0) AS total_bugs"),
268+ SQL("coalesce(bug_count, 0) AS bug_count"),
269 SQL("coalesce(total_messages, 0) AS total_messages"))
270 joins, conditions = self._current_sourcepackage_joins_and_conditions
271 origin = SQL(joins)
272@@ -338,9 +337,9 @@
273 return [{
274 'package': SourcePackage(
275 sourcepackagename=spn, distroseries=self),
276- 'total_bugs': total_bugs,
277+ 'bug_count': bug_count,
278 'total_messages': total_messages}
279- for (spn, score, total_bugs, total_messages) in results]
280+ for (spn, score, bug_count, total_messages) in results]
281
282 def getPrioritizedlPackagings(self):
283 """See `IDistroSeries`.
284@@ -359,7 +358,7 @@
285 SQL("""
286 CASE WHEN spr.component = 1 THEN 1000 ELSE 0 END +
287 CASE WHEN Product.bugtracker IS NULL
288- THEN coalesce(total_heat, 10) ELSE 0 END +
289+ THEN coalesce(total_bug_heat, 10) ELSE 0 END +
290 CASE WHEN ProductSeries.translations_autoimport_mode = 1
291 THEN coalesce(po_messages, 10) ELSE 0 END +
292 CASE WHEN ProductSeries.branch IS NULL THEN 500
293@@ -383,29 +382,7 @@
294 # Bugs and PO messages are heuristically scored. These queries
295 # can easily timeout so filters and weights are used to create
296 # an acceptable prioritization of packages that is fast to excecute.
297- bug_heat_filter = 200
298 po_message_weight = .5
299- heat_score = ("""
300- LEFT JOIN (
301- SELECT
302- BugTask.sourcepackagename,
303- sum(Bug.heat) AS total_heat,
304- count(Bug.id) AS total_bugs
305- FROM BugTask
306- JOIN Bug
307- ON bugtask.bug = Bug.id
308- WHERE
309- BugTask.sourcepackagename is not NULL
310- AND BugTask.distribution = %(distribution)s
311- AND BugTask.status in %(statuses)s
312- AND Bug.heat > %(bug_heat_filter)s
313- GROUP BY BugTask.sourcepackagename
314- ) bugs
315- ON SourcePackageName.id = bugs.sourcepackagename
316- """ % sqlvalues(
317- distribution=self.distribution,
318- statuses=UNRESOLVED_BUGTASK_STATUSES,
319- bug_heat_filter=bug_heat_filter))
320 message_score = ("""
321 LEFT JOIN (
322 SELECT
323@@ -442,7 +419,10 @@
324 LEFT JOIN Packaging
325 ON SourcePackageName.id = Packaging.sourcepackagename
326 AND Packaging.distroseries = DistroSeries.id
327- """ + heat_score + message_score)
328+ LEFT JOIN DistributionSourcePackage dsp
329+ ON dsp.sourcepackagename = spr.sourcepackagename
330+ AND dsp.distribution = DistroSeries.distribution
331+ """ + message_score)
332 conditions = ("""
333 DistroSeries.id = %(distroseries)s
334 AND spph.status IN %(active_status)s
335
336=== modified file 'lib/lp/registry/templates/distroseries-needs-packaging.pt'
337--- lib/lp/registry/templates/distroseries-needs-packaging.pt 2010-01-30 18:15:36 +0000
338+++ lib/lp/registry/templates/distroseries-needs-packaging.pt 2010-06-25 17:47:32 +0000
339@@ -53,7 +53,7 @@
340 tal:attributes="href summary/package/fmt:url"
341 tal:content="summary/package/name">evolution</a>
342 </td>
343- <td tal:define="count summary/total_bugs;
344+ <td tal:define="count summary/bug_count;
345 singular string:bug;
346 plural string:bugs;">
347 <tal:no-bugs condition="not: count">

Subscribers

People subscribed via source and target branches

to status/vote changes: