Merge lp:~edwin-grubbs/launchpad/bug-668047-project-dsp-portlet-timeout into lp:launchpad

Proposed by Edwin Grubbs
Status: Merged
Approved by: Robert Collins
Approved revision: no longer in the source branch.
Merged at revision: 11920
Proposed branch: lp:~edwin-grubbs/launchpad/bug-668047-project-dsp-portlet-timeout
Merge into: lp:launchpad
Diff against target: 213 lines (+45/-38)
5 files modified
lib/lp/registry/browser/tests/product-portlet-packages-view.txt (+3/-3)
lib/lp/registry/doc/distribution.txt (+19/-15)
lib/lp/registry/model/distribution.py (+14/-12)
lib/lp/registry/stories/webservice/xx-distribution.txt (+7/-6)
lib/lp/soyuz/browser/tests/distribution-views.txt (+2/-2)
To merge this branch: bzr merge lp:~edwin-grubbs/launchpad/bug-668047-project-dsp-portlet-timeout
Reviewer Review Type Date Requested Status
Robert Collins (community) Approve
Review via email: mp+39917@code.launchpad.net

Commit message

Fix timeout finding suggested ubuntu packages to link to a project.

Description of the change

Summary
-------

The project page would timeout when the "Packages in Ubuntu" portlet
would find a huge number of packages matching the project's name that
could be suggested for linking. The subquery for checking the
SourcePackageRelease and SourcePackagePublishingHistory table forced
postgres to use a nested loop, which was very inefficent.

Switching to using a join made it about 200 times faster. Because there
can be multiple SPPH records per DSP, the SELECT had to be made
DISTINCT. The DISTINCT caused some of the tests to break because the
order of the results was nondeterministic when the rank is NULL (i.e.
when a DSP is matched with LIKE as opposed to with the fti). I added the
DSP.name to the ORDER BY clause to make the tests less fragile.

Tests
-----

./bin/test -vv -t 'doc/distribution.txt|xx-distribution.txt'

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

* Open https://qastaging.launchpad.net/do
  * It should not timeout.

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote :

Nice.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/browser/tests/product-portlet-packages-view.txt'
2--- lib/lp/registry/browser/tests/product-portlet-packages-view.txt 2010-10-19 18:44:31 +0000
3+++ lib/lp/registry/browser/tests/product-portlet-packages-view.txt 2010-11-12 16:05:06 +0000
4@@ -179,8 +179,8 @@
5 ... principal=product.owner)
6 >>> for dsp in view.suggestions:
7 ... print dsp.name
8+ ba-bingo
9 bingo
10- ba-bingo
11
12 >>> content = find_tag_by_id(view.render(), 'portlet-packages')
13 >>> print extract_text(content)
14@@ -191,8 +191,8 @@
15 let distribution and upstream maintainers share bugs, patches, and
16 translations efficiently.
17 Ubuntu Hoary packages:
18- bingo
19- ba-bingo...
20+ ba-bingo
21+ bingo...
22
23 But the limit is 8 packages.
24
25
26=== modified file 'lib/lp/registry/doc/distribution.txt'
27--- lib/lp/registry/doc/distribution.txt 2010-11-02 05:48:54 +0000
28+++ lib/lp/registry/doc/distribution.txt 2010-11-12 16:05:06 +0000
29@@ -172,8 +172,11 @@
30 a certain string through the magic of fti. For instance:
31
32 >>> packages = ubuntu.searchSourcePackageCaches("mozilla")
33- >>> print packages.count()
34- 1
35+ >>> for distro_source_package_cache, source_name, rank in packages:
36+ ... print "%-17s rank:%s" % (
37+ ... distro_source_package_cache.name,
38+ ... type(rank))
39+ mozilla-firefox rank:<type 'float'>
40
41 The search also matches on exact package names which fti doesn't like,
42 and even on substrings:
43@@ -183,14 +186,15 @@
44 1
45 >>> packages = ubuntu.searchSourcePackageCaches('a')
46 >>> for distro_source_package_cache, source_name, rank in packages:
47- ... print "%s: %s" % (
48+ ... print "%s: %-17s rank:%s" % (
49 ... distro_source_package_cache.__class__.__name__,
50- ... distro_source_package_cache.name)
51- DistributionSourcePackageCache: mozilla-firefox
52- DistributionSourcePackageCache: netapplet
53- DistributionSourcePackageCache: alsa-utils
54- DistributionSourcePackageCache: foobar
55- DistributionSourcePackageCache: commercialpackage
56+ ... distro_source_package_cache.name,
57+ ... type(rank))
58+ DistributionSourcePackageCache: alsa-utils rank:<type 'NoneType'>
59+ DistributionSourcePackageCache: commercialpackage rank:<type 'NoneType'>
60+ DistributionSourcePackageCache: foobar rank:<type 'NoneType'>
61+ DistributionSourcePackageCache: mozilla-firefox rank:<type 'NoneType'>
62+ DistributionSourcePackageCache: netapplet rank:<type 'NoneType'>
63
64 The searchSourcePackages() method just returns a decorated version
65 of the results from searchSourcePackageCaches():
66@@ -198,11 +202,11 @@
67 >>> packages = ubuntu.searchSourcePackages('a')
68 >>> for dsp in packages:
69 ... print "%s: %s" % (dsp.__class__.__name__, dsp.name)
70+ DistributionSourcePackage: alsa-utils
71+ DistributionSourcePackage: commercialpackage
72+ DistributionSourcePackage: foobar
73 DistributionSourcePackage: mozilla-firefox
74 DistributionSourcePackage: netapplet
75- DistributionSourcePackage: alsa-utils
76- DistributionSourcePackage: foobar
77- DistributionSourcePackage: commercialpackage
78
79 searchSourcePackages() also has a has_packaging parameter that
80 it just passes on to searchSourcePackageCaches(), and it restricts
81@@ -212,14 +216,14 @@
82 >>> packages = ubuntu.searchSourcePackages('a', has_packaging=True)
83 >>> for dsp in packages:
84 ... print "%s: %s" % (dsp.__class__.__name__, dsp.name)
85+ DistributionSourcePackage: alsa-utils
86 DistributionSourcePackage: mozilla-firefox
87 DistributionSourcePackage: netapplet
88- DistributionSourcePackage: alsa-utils
89 >>> packages = ubuntu.searchSourcePackages('a', has_packaging=False)
90 >>> for dsp in packages:
91 ... print "%s: %s" % (dsp.__class__.__name__, dsp.name)
92+ DistributionSourcePackage: commercialpackage
93 DistributionSourcePackage: foobar
94- DistributionSourcePackage: commercialpackage
95
96 searchSourcePackages() also has a publishing_distroseries parameter that
97 it just passes on to searchSourcePackageCaches(), and it restricts the
98@@ -230,8 +234,8 @@
99 ... 'a', publishing_distroseries=ubuntu.currentseries)
100 >>> for dsp in packages:
101 ... print "%s: %s" % (dsp.__class__.__name__, dsp.name)
102+ DistributionSourcePackage: alsa-utils
103 DistributionSourcePackage: netapplet
104- DistributionSourcePackage: alsa-utils
105
106
107 Searching for binary packages
108
109=== modified file 'lib/lp/registry/model/distribution.py'
110--- lib/lp/registry/model/distribution.py 2010-11-05 14:56:34 +0000
111+++ lib/lp/registry/model/distribution.py 2010-11-12 16:05:06 +0000
112@@ -1142,16 +1142,17 @@
113
114 publishing_condition = ''
115 if publishing_distroseries is not None:
116- publishing_condition = """
117- AND EXISTS (
118- SELECT 1
119- FROM SourcePackageRelease spr
120- JOIN SourcePackagePublishingHistory spph
121- ON spph.sourcepackagerelease = spr.id
122- WHERE spr.sourcepackagename = SourcePackageName.id
123- AND spph.distroseries = %d
124- )""" % (
125- publishing_distroseries.id)
126+ origin += [
127+ Join(SourcePackageRelease,
128+ SourcePackageRelease.sourcepackagename ==
129+ SourcePackageName.id),
130+ Join(SourcePackagePublishingHistory,
131+ SourcePackagePublishingHistory.sourcepackagerelease ==
132+ SourcePackageRelease.id),
133+ ]
134+ publishing_condition = (
135+ "AND SourcePackagePublishingHistory.distroseries = %d"
136+ % publishing_distroseries.id)
137
138 packaging_query = """
139 SELECT 1
140@@ -1178,8 +1179,9 @@
141 quote(text), quote_like(text), has_packaging_condition,
142 publishing_condition)
143 dsp_caches_with_ranks = store.using(*origin).find(
144- find_spec, condition).order_by('rank DESC')
145-
146+ find_spec, condition).order_by(
147+ 'rank DESC, DistributionSourcePackageCache.name')
148+ dsp_caches_with_ranks.config(distinct=True)
149 return dsp_caches_with_ranks
150
151 def searchSourcePackages(
152
153=== modified file 'lib/lp/registry/stories/webservice/xx-distribution.txt'
154--- lib/lp/registry/stories/webservice/xx-distribution.txt 2010-10-18 22:24:59 +0000
155+++ lib/lp/registry/stories/webservice/xx-distribution.txt 2010-11-12 16:05:06 +0000
156@@ -1,4 +1,5 @@
157-= Distributions =
158+Distributions
159+=============
160
161 At the top level we provide the collection of all distributions, with
162 Ubuntu and its flavours being the first on the list.
163@@ -50,7 +51,8 @@
164 title: u'Ubuntu Linux'
165
166
167-== Distribution Custom Operations ==
168+Distribution Custom Operations
169+==============================
170
171 Distribution has some custom operations.
172
173@@ -113,11 +115,11 @@
174
175 >>> for entry in alsa_results['entries']:
176 ... print entry['self_link']
177+ http://.../ubuntu/+source/alsa-utils
178+ http://.../ubuntu/+source/commercialpackage
179+ http://.../ubuntu/+source/foobar
180 http://.../ubuntu/+source/mozilla-firefox
181 http://.../ubuntu/+source/netapplet
182- http://.../ubuntu/+source/alsa-utils
183- http://.../ubuntu/+source/foobar
184- http://.../ubuntu/+source/commercialpackage
185
186 "getArchive" returns a distribution archive (not a PPA) with the given name.
187
188@@ -190,7 +192,6 @@
189 >>> antarctica_patch_target = webservice.named_get(
190 ... ubuntu['self_link'], 'getMirrorByName',
191 ... name='mirror.showa.antarctica.org-archive').jsonBody()
192- ... )
193
194 >>> response = karl_webservice.patch(
195 ... antarctica_patch_target['self_link'], 'application/json',
196
197=== modified file 'lib/lp/soyuz/browser/tests/distribution-views.txt'
198--- lib/lp/soyuz/browser/tests/distribution-views.txt 2010-06-28 15:22:25 +0000
199+++ lib/lp/soyuz/browser/tests/distribution-views.txt 2010-11-12 16:05:06 +0000
200@@ -94,11 +94,11 @@
201 False
202 >>> for package in distro_pkg_search_view.search_results:
203 ... print package.name
204- netapplet
205 alsa-utils
206+ commercialpackage
207 foobar
208 mozilla-firefox
209- commercialpackage
210+ netapplet
211
212 Unless the distribution being searched does not support binaries, in which
213 cases it will always be on source: