← Back to team overview

launchpad-reviewers team mailing list archive

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

 

Edwin Grubbs has proposed merging lp:~edwin-grubbs/launchpad/bug-668047-project-dsp-portlet-timeout into lp:launchpad/devel.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  #668047 Project:+index : Project page timeout on qastaging with 11s of SQL
  https://bugs.launchpad.net/bugs/668047


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.
-- 
https://code.launchpad.net/~edwin-grubbs/launchpad/bug-668047-project-dsp-portlet-timeout/+merge/39917
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~edwin-grubbs/launchpad/bug-668047-project-dsp-portlet-timeout into lp:launchpad/devel.
=== modified file 'lib/lp/registry/doc/distribution.txt'
--- lib/lp/registry/doc/distribution.txt	2010-11-02 05:48:54 +0000
+++ lib/lp/registry/doc/distribution.txt	2010-11-03 02:02:46 +0000
@@ -172,8 +172,11 @@
 a certain string through the magic of fti. For instance:
 
     >>> packages = ubuntu.searchSourcePackageCaches("mozilla")
-    >>> print packages.count()
-    1
+    >>> for distro_source_package_cache, source_name, rank in packages:
+    ...     print "%-17s rank:%s" % (
+    ...         distro_source_package_cache.name,
+    ...         type(rank))
+    mozilla-firefox   rank:<type 'float'>
 
 The search also matches on exact package names which fti doesn't like,
 and even on substrings:
@@ -183,14 +186,15 @@
     1
     >>> packages = ubuntu.searchSourcePackageCaches('a')
     >>> for distro_source_package_cache, source_name, rank in packages:
-    ...     print "%s: %s" % (
+    ...     print "%s: %-17s rank:%s" % (
     ...         distro_source_package_cache.__class__.__name__,
-    ...         distro_source_package_cache.name)
-    DistributionSourcePackageCache: mozilla-firefox
-    DistributionSourcePackageCache: netapplet
-    DistributionSourcePackageCache: alsa-utils
-    DistributionSourcePackageCache: foobar
-    DistributionSourcePackageCache: commercialpackage
+    ...         distro_source_package_cache.name,
+    ...         type(rank))
+    DistributionSourcePackageCache: alsa-utils        rank:<type 'NoneType'>
+    DistributionSourcePackageCache: commercialpackage rank:<type 'NoneType'>
+    DistributionSourcePackageCache: foobar            rank:<type 'NoneType'>
+    DistributionSourcePackageCache: mozilla-firefox   rank:<type 'NoneType'>
+    DistributionSourcePackageCache: netapplet         rank:<type 'NoneType'>
 
 The searchSourcePackages() method just returns a decorated version
 of the results from searchSourcePackageCaches():
@@ -198,11 +202,11 @@
     >>> packages = ubuntu.searchSourcePackages('a')
     >>> for dsp in packages:
     ...     print "%s: %s" % (dsp.__class__.__name__, dsp.name)
+    DistributionSourcePackage: alsa-utils
+    DistributionSourcePackage: commercialpackage
+    DistributionSourcePackage: foobar
     DistributionSourcePackage: mozilla-firefox
     DistributionSourcePackage: netapplet
-    DistributionSourcePackage: alsa-utils
-    DistributionSourcePackage: foobar
-    DistributionSourcePackage: commercialpackage
 
 searchSourcePackages() also has a has_packaging parameter that
 it just passes on to searchSourcePackageCaches(), and it restricts
@@ -212,14 +216,14 @@
     >>> packages = ubuntu.searchSourcePackages('a', has_packaging=True)
     >>> for dsp in packages:
     ...     print "%s: %s" % (dsp.__class__.__name__, dsp.name)
+    DistributionSourcePackage: alsa-utils
     DistributionSourcePackage: mozilla-firefox
     DistributionSourcePackage: netapplet
-    DistributionSourcePackage: alsa-utils
     >>> packages = ubuntu.searchSourcePackages('a', has_packaging=False)
     >>> for dsp in packages:
     ...     print "%s: %s" % (dsp.__class__.__name__, dsp.name)
+    DistributionSourcePackage: commercialpackage
     DistributionSourcePackage: foobar
-    DistributionSourcePackage: commercialpackage
 
 searchSourcePackages() also has a publishing_distroseries parameter that
 it just passes on to searchSourcePackageCaches(), and it restricts the
@@ -230,8 +234,8 @@
     ...     'a', publishing_distroseries=ubuntu.currentseries)
     >>> for dsp in packages:
     ...     print "%s: %s" % (dsp.__class__.__name__, dsp.name)
+    DistributionSourcePackage: alsa-utils
     DistributionSourcePackage: netapplet
-    DistributionSourcePackage: alsa-utils
 
 
 Searching for binary packages

=== modified file 'lib/lp/registry/model/distribution.py'
--- lib/lp/registry/model/distribution.py	2010-11-02 06:21:58 +0000
+++ lib/lp/registry/model/distribution.py	2010-11-03 02:02:46 +0000
@@ -1164,16 +1164,17 @@
 
         publishing_condition = ''
         if publishing_distroseries is not None:
-            publishing_condition = """
-                AND EXISTS (
-                    SELECT 1
-                    FROM SourcePackageRelease spr
-                        JOIN SourcePackagePublishingHistory spph
-                            ON spph.sourcepackagerelease = spr.id
-                    WHERE spr.sourcepackagename = SourcePackageName.id
-                        AND spph.distroseries = %d
-                    )""" % (
-                publishing_distroseries.id)
+            origin += [
+                Join(SourcePackageRelease,
+                    SourcePackageRelease.sourcepackagename ==
+                        SourcePackageName.id),
+                Join(SourcePackagePublishingHistory,
+                    SourcePackagePublishingHistory.sourcepackagerelease ==
+                        SourcePackageRelease.id),
+                ]
+            publishing_condition = (
+                "AND SourcePackagePublishingHistory.distroseries = %d"
+                % publishing_distroseries.id)
 
         packaging_query = """
             SELECT 1
@@ -1200,8 +1201,9 @@
                    quote(text), quote_like(text), has_packaging_condition,
                    publishing_condition)
         dsp_caches_with_ranks = store.using(*origin).find(
-            find_spec, condition).order_by('rank DESC')
-
+            find_spec, condition).order_by(
+                'rank DESC, DistributionSourcePackageCache.name')
+        dsp_caches_with_ranks.config(distinct=True)
         return dsp_caches_with_ranks
 
     def searchSourcePackages(

=== modified file 'lib/lp/registry/stories/webservice/xx-distribution.txt'
--- lib/lp/registry/stories/webservice/xx-distribution.txt	2010-10-18 22:24:59 +0000
+++ lib/lp/registry/stories/webservice/xx-distribution.txt	2010-11-03 02:02:46 +0000
@@ -1,4 +1,5 @@
-= Distributions =
+Distributions
+=============
 
 At the top level we provide the collection of all distributions, with
 Ubuntu and its flavours being the first on the list.
@@ -50,7 +51,8 @@
     title: u'Ubuntu Linux'
 
 
-== Distribution Custom Operations ==
+Distribution Custom Operations
+==============================
 
 Distribution has some custom operations.
 
@@ -113,11 +115,11 @@
 
     >>> for entry in alsa_results['entries']:
     ...     print entry['self_link']
+    http://.../ubuntu/+source/alsa-utils
+    http://.../ubuntu/+source/commercialpackage
+    http://.../ubuntu/+source/foobar
     http://.../ubuntu/+source/mozilla-firefox
     http://.../ubuntu/+source/netapplet
-    http://.../ubuntu/+source/alsa-utils
-    http://.../ubuntu/+source/foobar
-    http://.../ubuntu/+source/commercialpackage
 
 "getArchive" returns a distribution archive (not a PPA) with the given name.
 
@@ -190,7 +192,6 @@
     >>> antarctica_patch_target = webservice.named_get(
     ...     ubuntu['self_link'], 'getMirrorByName',
     ...     name='mirror.showa.antarctica.org-archive').jsonBody()
-    ... )
 
     >>> response = karl_webservice.patch(
     ...     antarctica_patch_target['self_link'], 'application/json',