Merge lp:~lifeless/launchpad/bug-724033 into lp:launchpad

Proposed by Robert Collins
Status: Merged
Approved by: Robert Collins
Approved revision: no longer in the source branch.
Merged at revision: 12488
Proposed branch: lp:~lifeless/launchpad/bug-724033
Merge into: lp:launchpad
Diff against target: 174 lines (+55/-23)
5 files modified
lib/lp/bugs/browser/bugtask.py (+10/-11)
lib/lp/bugs/configure.zcml (+1/-0)
lib/lp/bugs/interfaces/bugnomination.py (+5/-1)
lib/lp/bugs/model/bug.py (+38/-10)
lib/lp/registry/model/distribution.py (+1/-1)
To merge this branch: bzr merge lp:~lifeless/launchpad/bug-724033
Reviewer Review Type Date Requested Status
Tim Penhey (community) code Approve
William Grant code* Approve
Review via email: mp+51676@code.launchpad.net

Commit message

[r=thumper,wgrant][ui=none][bug=724033]

Description of the change

Reduce more scaling issues with BugTask:+index. No tests for this because we're still batshit insanely far from having a flat profile (which is needed to write a clean test. Tests will come when we're flat, which will be soon.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) wrote :

Gratuitous ILaunchBag import in lib/lp/bugs/model/bug.py. Also, I'm not a fan of "IDs" as a variable name.

Your bugtask target preloading serves the same role as something I did in lib/lp/bugs/scripts/bugtasktargetnamecaches.py, but rather differently. We probably want a well-known pattern for this sort of thing.

review: Approve (code*)
Revision history for this message
Tim Penhey (thumper) wrote :

I agree with William in that I don't like the "IDs" as a variable name. Even "ids" is better to me.

review: Approve (code)
Revision history for this message
Robert Collins (lifeless) wrote :

Will change to ids.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/browser/bugtask.py'
2--- lib/lp/bugs/browser/bugtask.py 2011-02-22 08:42:07 +0000
3+++ lib/lp/bugs/browser/bugtask.py 2011-03-01 03:41:39 +0000
4@@ -509,7 +509,7 @@
5 # anonymous user is presented with a login screen at the correct URL,
6 # rather than making it look as though this task was "not found",
7 # because it was filtered out by privacy-aware code.
8- for bugtask in list(bug.bugtasks):
9+ for bugtask in bug.bugtasks:
10 if bugtask.target == context:
11 # Security proxy this object on the way out.
12 return getUtility(IBugTaskSet).get(bugtask.id)
13@@ -650,6 +650,8 @@
14 self.context = getUtility(ILaunchBag).bugtask
15 else:
16 self.context = context
17+ list(getUtility(IPersonSet).getPrecachedPersonsFromIDs(
18+ [self.context.bug.ownerID], need_validity=True))
19
20 @property
21 def page_title(self):
22@@ -3246,6 +3248,13 @@
23 # nominations here, so we can pass it to getNominations() later
24 # on.
25 nominations = list(bug.getNominations())
26+ # Eager load validity for all the persons we know of that will be
27+ # displayed.
28+ ids = set(map(attrgetter('ownerID'), nominations))
29+ ids.discard(None)
30+ if ids:
31+ list(getUtility(IPersonSet).getPrecachedPersonsFromIDs(
32+ ids, need_validity=True))
33
34 # Build a cache we can pass on to getConjoinedMaster(), so that
35 # it doesn't have to iterate over all the bug tasks in each loop
36@@ -3271,16 +3280,6 @@
37 for nomination in target_nominations
38 if nomination.status != BugNominationStatus.APPROVED)
39
40- # Fill the ValidPersonOrTeamCache cache (using getValidPersons()),
41- # so that checking person.is_valid_person, when rendering the
42- # link, won't issue a DB query.
43- assignees = set(
44- bugtask.assignee for bugtask in all_bugtasks
45- if bugtask.assignee is not None)
46- reporters = set(
47- bugtask.owner for bugtask in all_bugtasks)
48- getUtility(IPersonSet).getValidPersons(assignees.union(reporters))
49-
50 return bugtask_and_nomination_views
51
52 @property
53
54=== modified file 'lib/lp/bugs/configure.zcml'
55--- lib/lp/bugs/configure.zcml 2011-02-21 04:23:02 +0000
56+++ lib/lp/bugs/configure.zcml 2011-03-01 03:41:39 +0000
57@@ -902,6 +902,7 @@
58 productseries
59 bug
60 owner
61+ ownerID
62 decider
63 target
64 status
65
66=== modified file 'lib/lp/bugs/interfaces/bugnomination.py'
67--- lib/lp/bugs/interfaces/bugnomination.py 2011-01-31 17:08:35 +0000
68+++ lib/lp/bugs/interfaces/bugnomination.py 2011-03-01 03:41:39 +0000
69@@ -33,7 +33,10 @@
70 Reference,
71 ReferenceChoice,
72 )
73-from zope.interface import Interface
74+from zope.interface import (
75+ Attribute,
76+ Interface,
77+ )
78 from zope.schema import (
79 Choice,
80 Datetime,
81@@ -130,6 +133,7 @@
82 owner = exported(PublicPersonChoice(
83 title=_('Submitter'), required=True, readonly=True,
84 vocabulary='ValidPersonOrTeam'))
85+ ownerID = Attribute('The db id of the owner.')
86 decider = exported(PublicPersonChoice(
87 title=_('Decided By'), required=False, readonly=True,
88 vocabulary='ValidPersonOrTeam'))
89
90=== modified file 'lib/lp/bugs/model/bug.py'
91--- lib/lp/bugs/model/bug.py 2011-02-23 23:46:00 +0000
92+++ lib/lp/bugs/model/bug.py 2011-03-01 03:41:39 +0000
93@@ -143,6 +143,7 @@
94 )
95 from lp.bugs.interfaces.bugnotification import IBugNotificationSet
96 from lp.bugs.interfaces.bugtask import (
97+ BugTaskSearchParams,
98 BugTaskStatus,
99 IBugTaskSet,
100 UNRESOLVED_BUGTASK_STATUSES,
101@@ -175,7 +176,10 @@
102 IDistributionSourcePackage,
103 )
104 from lp.registry.interfaces.distroseries import IDistroSeries
105-from lp.registry.interfaces.person import validate_public_person
106+from lp.registry.interfaces.person import (
107+ IPersonSet,
108+ validate_public_person,
109+ )
110 from lp.registry.interfaces.product import IProduct
111 from lp.registry.interfaces.productseries import IProductSeries
112 from lp.registry.interfaces.series import SeriesStatus
113@@ -549,15 +553,39 @@
114 @cachedproperty
115 def bugtasks(self):
116 """See `IBug`."""
117- result = BugTask.select('BugTask.bug = %s' % sqlvalues(self.id))
118- result = result.prejoin(
119- ["assignee", "product", "sourcepackagename",
120- "owner", "bugwatch"])
121- # Do not use the default orderBy as the prejoins cause ambiguities
122- # across the tables.
123- result = result.orderBy("id")
124- result = sorted(result, key=bugtask_sort_key)
125- return result
126+ # \o/ circular imports.
127+ from lp.bugs.model.bugwatch import BugWatch
128+ from lp.registry.model.distribution import Distribution
129+ from lp.registry.model.distroseries import DistroSeries
130+ from lp.registry.model.product import Product
131+ from lp.registry.model.productseries import ProductSeries
132+ from lp.registry.model.sourcepackagename import SourcePackageName
133+ store = Store.of(self)
134+ tasks = list(store.find(BugTask, BugTask.bugID == self.id))
135+ # The bugtasks attribute is iterated in the API and web services, so it
136+ # needs to preload all related data otherwise late evaluation is
137+ # triggered in both places. Separately, bugtask_sort_key requires
138+ # the related products, series, distros, distroseries and source
139+ # package names to be loaded.
140+ ids = set(map(operator.attrgetter('assigneeID'), tasks))
141+ ids.update(map(operator.attrgetter('ownerID'), tasks))
142+ ids.discard(None)
143+ if ids:
144+ list(getUtility(IPersonSet).getPrecachedPersonsFromIDs(
145+ ids, need_validity=True))
146+ def load_something(attrname, klass):
147+ ids = set(map(operator.attrgetter(attrname), tasks))
148+ ids.discard(None)
149+ if not ids:
150+ return
151+ list(store.find(klass, klass.id.is_in(ids)))
152+ load_something('productID', Product)
153+ load_something('productseriesID', ProductSeries)
154+ load_something('distributionID', Distribution)
155+ load_something('distroseriesID', DistroSeries)
156+ load_something('sourcepackagenameID', SourcePackageName)
157+ list(store.find(BugWatch, BugWatch.bugID == self.id))
158+ return sorted(tasks, key=bugtask_sort_key)
159
160 @property
161 def default_bugtask(self):
162
163=== modified file 'lib/lp/registry/model/distribution.py'
164--- lib/lp/registry/model/distribution.py 2011-02-24 15:57:05 +0000
165+++ lib/lp/registry/model/distribution.py 2011-03-01 03:41:39 +0000
166@@ -282,7 +282,7 @@
167 SQLBase._init(self, *args, **kw)
168 # Add a marker interface to set permissions for this kind
169 # of distribution.
170- if self == getUtility(ILaunchpadCelebrities).ubuntu:
171+ if self.name == 'ubuntu':
172 alsoProvides(self, IBaseDistribution)
173 else:
174 alsoProvides(self, IDerivativeDistribution)