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: 12538
Proposed branch: lp:~lifeless/launchpad/bug-724033
Merge into: lp:launchpad
Diff against target: 125 lines (+25/-14)
5 files modified
lib/canonical/launchpad/doc/vocabularies.txt (+0/-3)
lib/canonical/launchpad/vocabularies/dbobjects.py (+0/-3)
lib/canonical/launchpad/webapp/vocabulary.py (+0/-3)
lib/lp/bugs/browser/bugtask.py (+22/-5)
lib/lp/registry/vocabularies.py (+3/-0)
To merge this branch: bzr merge lp:~lifeless/launchpad/bug-724033
Reviewer Review Type Date Requested Status
Jeroen T. Vermeulen (community) code Approve
Review via email: mp+52358@code.launchpad.net

Commit message

[r=jtv][bug=724033] More scaling improvements for BugTask:+index - use the edit form milestone cache for the view rows too.

Description of the change

More scaling improvements for BugTask:+index: this should halve the number of milestone/distro/product lookups happening by using an existing caching layer for milestones more effectively. Further work beyond this involves making the cache eager load for all contexts at once, but these are separate changes and this change alone will make a significant difference.

To post a comment you must log in.
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Strange to see the check that "return None" returns None—and good riddance I suppose.

I would still have liked to see a test, especially since the version I originally tried to review had a performance bug and the overall page is not in a shape that can be tested for query counts yet. I know it's arguably not a "new layer" and this is just a refactoring but you're trying to make an important change and you almost made things worse because of untested new code—however small.

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

Thanks for the review. I'm going to skip the test - but I'd like to note that the test you suggested would have passed even with the original bug in place.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/doc/vocabularies.txt'
2--- lib/canonical/launchpad/doc/vocabularies.txt 2010-10-18 22:24:59 +0000
3+++ lib/canonical/launchpad/doc/vocabularies.txt 2011-03-07 02:54:15 +0000
4@@ -85,9 +85,6 @@
5 >>> debian in using_malone_vocabulary
6 False
7
8- >>> using_malone_vocabulary.getQuery() is None
9- True
10-
11 >>> term = using_malone_vocabulary.getTerm(ubuntu)
12 >>> print term.token, term.value.displayname, term.title
13 ubuntu Ubuntu Ubuntu
14
15=== modified file 'lib/canonical/launchpad/vocabularies/dbobjects.py'
16--- lib/canonical/launchpad/vocabularies/dbobjects.py 2010-12-01 18:58:44 +0000
17+++ lib/canonical/launchpad/vocabularies/dbobjects.py 2011-03-07 02:54:15 +0000
18@@ -487,9 +487,6 @@
19 return (IDistribution.providedBy(obj)
20 and obj.bug_tracking_usage == ServiceUsage.LAUNCHPAD)
21
22- def getQuery(self):
23- return None
24-
25 def getTerm(self, obj):
26 if obj not in self:
27 raise LookupError(obj)
28
29=== modified file 'lib/canonical/launchpad/webapp/vocabulary.py'
30--- lib/canonical/launchpad/webapp/vocabulary.py 2010-12-01 18:58:44 +0000
31+++ lib/canonical/launchpad/webapp/vocabulary.py 2011-03-07 02:54:15 +0000
32@@ -281,9 +281,6 @@
33 found_obj = self._table.selectOne(clause)
34 return found_obj is not None
35
36- def getQuery(self):
37- return None
38-
39 def getTerm(self, value):
40 # Short circuit. There is probably a design problem here since
41 # we sometimes get the id and sometimes an SQLBase instance.
42
43=== modified file 'lib/lp/bugs/browser/bugtask.py'
44--- lib/lp/bugs/browser/bugtask.py 2011-03-03 10:58:03 +0000
45+++ lib/lp/bugs/browser/bugtask.py 2011-03-07 02:54:15 +0000
46@@ -3124,14 +3124,25 @@
47
48 def __init__(self):
49 self.vocabularies = {}
50+ self.contexts = set()
51
52 def __call__(self, context):
53+ assert context in self.contexts, ("context %r not added to "
54+ "self.contexts (%r)." % (context, self.contexts))
55+ self._load()
56 target = MilestoneVocabulary.getMilestoneTarget(context)
57- milestone_vocabulary = self.vocabularies.get(target)
58- if milestone_vocabulary is None:
59- milestone_vocabulary = MilestoneVocabulary(context)
60+ return self.vocabularies[target]
61+
62+ def _load(self):
63+ """Load all the vocabularies, once only."""
64+ if self.vocabularies:
65+ return
66+ targets = set(
67+ map(MilestoneVocabulary.getMilestoneTarget, self.contexts))
68+ # TODO: instantiate for all targets at once.
69+ for target in targets:
70+ milestone_vocabulary = MilestoneVocabulary(target)
71 self.vocabularies[target] = milestone_vocabulary
72- return milestone_vocabulary
73
74
75 class BugTasksAndNominationsView(LaunchpadView):
76@@ -3205,6 +3216,7 @@
77 The view's is_conjoined_slave and is_converted_to_question
78 attributes are set, as well as the edit view.
79 """
80+ self.cached_milestone_source.contexts.add(context)
81 view = getMultiAdapter(
82 (context, self.request),
83 name='+bugtasks-and-nominations-table-row')
84@@ -3212,6 +3224,7 @@
85 view.is_conjoined_slave = is_conjoined_slave
86 if IBugTask.providedBy(context):
87 view.target_link_title = self.getTargetLinkTitle(context.target)
88+ view.milestone_source = self.cached_milestone_source
89
90 view.edit_view = getMultiAdapter(
91 (context, self.request), name='+edit-form')
92@@ -3383,6 +3396,10 @@
93 target_link_title = None
94 many_bugtasks = False
95
96+ def __init__(self, context, request):
97+ super(BugTaskTableRowView, self).__init__(context, request)
98+ self.milestone_source = MilestoneVocabulary
99+
100 def canSeeTaskDetails(self):
101 """Whether someone can see a task's status details.
102
103@@ -3509,7 +3526,7 @@
104 @cachedproperty
105 def _visible_milestones(self):
106 """The visible milestones for this context."""
107- return MilestoneVocabulary(self.context).visible_milestones
108+ return self.milestone_source(self.context).visible_milestones
109
110 @property
111 def milestone_widget_items(self):
112
113=== modified file 'lib/lp/registry/vocabularies.py'
114--- lib/lp/registry/vocabularies.py 2011-01-31 19:44:36 +0000
115+++ lib/lp/registry/vocabularies.py 2011-03-07 02:54:15 +0000
116@@ -1291,6 +1291,9 @@
117 for milestone in self.visible_milestones:
118 yield self.toTerm(milestone)
119
120+ def __len__(self):
121+ return len(self.visible_milestones)
122+
123 def __contains__(self, obj):
124 if IProjectGroupMilestone.providedBy(obj):
125 # ProjectGroup milestones are pseudo content objects