Merge lp:~stevenk/launchpad/bugtask-activity-preload into lp:launchpad

Proposed by Steve Kowalik
Status: Merged
Approved by: Steve Kowalik
Approved revision: no longer in the source branch.
Merged at revision: 15928
Proposed branch: lp:~stevenk/launchpad/bugtask-activity-preload
Merge into: lp:launchpad
Diff against target: 138 lines (+48/-2)
4 files modified
lib/lp/bugs/browser/bug.py (+8/-0)
lib/lp/bugs/browser/tests/test_bug_views.py (+34/-0)
lib/lp/bugs/interfaces/bugactivity.py (+5/-1)
lib/lp/bugs/templates/bug-activity.pt (+1/-1)
To merge this branch: bzr merge lp:~stevenk/launchpad/bugtask-activity-preload
Reviewer Review Type Date Requested Status
Ian Booth (community) Approve
Review via email: mp+123484@code.launchpad.net

Commit message

Pre-load persons for Bug:+activity.

Description of the change

Change Bug:+activity to bulk load the people from ValidPersonCache. With 10 BugActivity rows, the query count drops from 13 to 5, and with 50 rows the query count drops from 53 to 5. This also required adding a personID attribute onto IBugActivity.

To post a comment you must log in.
Revision history for this message
Ian Booth (wallyworld) wrote :

Look good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/bugs/browser/bug.py'
--- lib/lp/bugs/browser/bug.py 2012-08-26 22:50:37 +0000
+++ lib/lp/bugs/browser/bug.py 2012-09-10 06:51:58 +0000
@@ -103,6 +103,7 @@
103 get_structural_subscriptions_for_bug,103 get_structural_subscriptions_for_bug,
104 )104 )
105from lp.registry.enums import PRIVATE_INFORMATION_TYPES105from lp.registry.enums import PRIVATE_INFORMATION_TYPES
106from lp.registry.interfaces.person import IPersonSet
106from lp.registry.vocabularies import InformationTypeVocabulary107from lp.registry.vocabularies import InformationTypeVocabulary
107from lp.services.fields import DuplicateBug108from lp.services.fields import DuplicateBug
108from lp.services.librarian.browser import ProxiedLibraryFileAlias109from lp.services.librarian.browser import ProxiedLibraryFileAlias
@@ -605,6 +606,13 @@
605606
606 page_title = 'Activity log'607 page_title = 'Activity log'
607608
609 @property
610 def activity(self):
611 activity = IBug(self.context).activity
612 list(getUtility(IPersonSet).getPrecachedPersonsFromIDs(
613 [a.personID for a in activity], need_validity=True))
614 return activity
615
608616
609class BugSubscriptionPortletDetails:617class BugSubscriptionPortletDetails:
610 """A mixin used to collate bug subscription details for a view."""618 """A mixin used to collate bug subscription details for a view."""
611619
=== modified file 'lib/lp/bugs/browser/tests/test_bug_views.py'
--- lib/lp/bugs/browser/tests/test_bug_views.py 2012-09-06 00:01:38 +0000
+++ lib/lp/bugs/browser/tests/test_bug_views.py 2012-09-10 06:51:58 +0000
@@ -5,20 +5,29 @@
55
6__metaclass__ = type6__metaclass__ = type
77
8from datetime import (
9 datetime,
10 timedelta,
11 )
12
8from BeautifulSoup import BeautifulSoup13from BeautifulSoup import BeautifulSoup
14import pytz
9import simplejson15import simplejson
10from soupmatchers import (16from soupmatchers import (
11 HTMLContains,17 HTMLContains,
12 Tag,18 Tag,
13 )19 )
20from storm.store import Store
14from testtools.matchers import (21from testtools.matchers import (
15 Contains,22 Contains,
23 Equals,
16 MatchesAll,24 MatchesAll,
17 Not,25 Not,
18 )26 )
19from zope.component import getUtility27from zope.component import getUtility
20from zope.security.proxy import removeSecurityProxy28from zope.security.proxy import removeSecurityProxy
2129
30from lp.bugs.adapters.bugchange import BugAttachmentChange
22from lp.registry.enums import (31from lp.registry.enums import (
23 BugSharingPolicy,32 BugSharingPolicy,
24 InformationType,33 InformationType,
@@ -35,12 +44,14 @@
35 BrowserTestCase,44 BrowserTestCase,
36 login_person,45 login_person,
37 person_logged_in,46 person_logged_in,
47 StormStatementRecorder,
38 TestCaseWithFactory,48 TestCaseWithFactory,
39 )49 )
40from lp.testing.layers import (50from lp.testing.layers import (
41 DatabaseFunctionalLayer,51 DatabaseFunctionalLayer,
42 LaunchpadFunctionalLayer,52 LaunchpadFunctionalLayer,
43 )53 )
54from lp.testing.matchers import HasQueryCount
44from lp.testing.pages import find_tag_by_id55from lp.testing.pages import find_tag_by_id
45from lp.testing.views import (56from lp.testing.views import (
46 create_initialized_view,57 create_initialized_view,
@@ -673,3 +684,26 @@
673 'table',684 'table',
674 {'id': 'affected-software', 'class': 'listing'})685 {'id': 'affected-software', 'class': 'listing'})
675 self.assertIsNotNone(table)686 self.assertIsNotNone(table)
687
688
689class TestBugActivityView(TestCaseWithFactory):
690
691 layer = LaunchpadFunctionalLayer
692
693 def test_bug_activity_query_count(self):
694 # Bug:+activity doesn't make O(n) queries based on the amount of
695 # activity.
696 bug = self.factory.makeBug()
697 ten_minutes_ago = datetime.now(pytz.UTC) - timedelta(minutes=10)
698 with person_logged_in(bug.owner):
699 attachment = self.factory.makeBugAttachment(bug=bug)
700 for i in range(10):
701 bug.addChange(BugAttachmentChange(
702 ten_minutes_ago, self.factory.makePerson(), 'attachment',
703 None, attachment))
704 Store.of(bug).invalidate()
705 with StormStatementRecorder() as recorder:
706 view = create_initialized_view(
707 bug.default_bugtask, name='+activity')
708 view.render()
709 self.assertThat(recorder, HasQueryCount(Equals(7)))
676710
=== modified file 'lib/lp/bugs/interfaces/bugactivity.py'
--- lib/lp/bugs/interfaces/bugactivity.py 2011-12-24 16:54:44 +0000
+++ lib/lp/bugs/interfaces/bugactivity.py 2012-09-10 06:51:58 +0000
@@ -16,7 +16,10 @@
16 export_as_webservice_entry,16 export_as_webservice_entry,
17 exported,17 exported,
18 )18 )
19from zope.interface import Interface19from zope.interface import (
20 Attribute,
21 Interface,
22 )
20from zope.schema import (23from zope.schema import (
21 Datetime,24 Datetime,
22 Text,25 Text,
@@ -42,6 +45,7 @@
42 description=_("The date on which this activity occurred."),45 description=_("The date on which this activity occurred."),
43 readonly=True))46 readonly=True))
4447
48 personID = Attribute('DB ID for Person')
45 person = exported(PersonChoice(49 person = exported(PersonChoice(
46 title=_('Person'), required=True, vocabulary='ValidPersonOrTeam',50 title=_('Person'), required=True, vocabulary='ValidPersonOrTeam',
47 readonly=True, description=_("The person's Launchpad ID or "51 readonly=True, description=_("The person's Launchpad ID or "
4852
=== modified file 'lib/lp/bugs/templates/bug-activity.pt'
--- lib/lp/bugs/templates/bug-activity.pt 2010-10-10 21:54:16 +0000
+++ lib/lp/bugs/templates/bug-activity.pt 2012-09-10 06:51:58 +0000
@@ -20,7 +20,7 @@
20 </tr>20 </tr>
21 </thead>21 </thead>
22 <tbody>22 <tbody>
23 <tr tal:repeat="log context/bug/activity">23 <tr tal:repeat="log view/activity">
24 <tal:comment condition="nothing">24 <tal:comment condition="nothing">
25 XXX: Gavin Panella 2009-08-12 bug=412963: Using strftime()25 XXX: Gavin Panella 2009-08-12 bug=412963: Using strftime()
26 here because fmt:datetime changes timezone, even though we26 here because fmt:datetime changes timezone, even though we