Merge lp:~edwin-grubbs/launchpad/bug-590840-getMembershipInformation-timeout into lp:launchpad

Proposed by Edwin Grubbs
Status: Merged
Approved by: Edwin Grubbs
Approved revision: no longer in the source branch.
Merged at revision: 10996
Proposed branch: lp:~edwin-grubbs/launchpad/bug-590840-getMembershipInformation-timeout
Merge into: lp:launchpad
Diff against target: 113 lines (+23/-31)
2 files modified
lib/lp/registry/model/mailinglist.py (+21/-30)
lib/lp/services/mailman/doc/staging.txt (+2/-1)
To merge this branch: bzr merge lp:~edwin-grubbs/launchpad/bug-590840-getMembershipInformation-timeout
Reviewer Review Type Date Requested Status
Michael Nelson (community) code Approve
Review via email: mp+27108@code.launchpad.net

Description of the change

Summary
-------

The MailingListAPIView.getMembershipInformation() method in
canonical.launchpad.xmlrpc.mailinglist was causing soft timeouts
(See OOPS-1612S995).

This was caused by the MailingListSet.getSenderAddresses(team_names)
retrieving all the columns from the tables being joined instead of
just the three columns actually needed.

Implementation details
----------------------

Improved performance of getSenderAddresses(team_names):
    lib/lp/registry/model/mailinglist.py

Drive-by testfix. I'm not sure if this test is being run by buildbot,
since it didn't look like it could possibly work otherwise.
    lib/lp/services/mailman/doc/staging.txt

Tests
-----

./bin/test -vv -t mailinglist
./bin/test -vv --layer=Mailman

To post a comment you must log in.
Revision history for this message
Michael Nelson (michael.nelson) wrote :

Great, thanks Edwin. Small note below that you can choose to ignore.

> === modified file 'lib/lp/registry/model/mailinglist.py'
> --- lib/lp/registry/model/mailinglist.py 2010-04-23 15:19:10 +0000
> +++ lib/lp/registry/model/mailinglist.py 2010-06-10 13:10:37 +0000
> @@ -729,20 +726,13 @@
> Person.teamowner != None))
> )
> team_members = store.using(*tables).find(
> - (EmailAddress, MailingList, Person, Team),
> + (Team.name, Person.displayname, EmailAddress.email),
> And(TeamParticipation.teamID.is_in(team_ids),

I only realised that it wasn't part of your change after testing it, but the And expression is not needed here. Up to you (other examples follow too.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/model/mailinglist.py'
2--- lib/lp/registry/model/mailinglist.py 2010-04-23 15:19:10 +0000
3+++ lib/lp/registry/model/mailinglist.py 2010-06-09 05:07:29 +0000
4@@ -22,7 +22,7 @@
5 from string import Template
6
7 from storm.info import ClassAlias
8-from storm.expr import And, LeftJoin
9+from storm.expr import And, Join, LeftJoin
10 from storm.store import Store
11
12 from sqlobject import ForeignKey, StringCol
13@@ -713,14 +713,11 @@
14 Team = ClassAlias(Person)
15 tables = (
16 Person,
17- LeftJoin(Account, Account.id == Person.accountID),
18- LeftJoin(EmailAddress, EmailAddress.personID == Person.id),
19- LeftJoin(TeamParticipation,
20- TeamParticipation.personID == Person.id),
21- LeftJoin(MailingList,
22- MailingList.teamID == TeamParticipation.teamID),
23- LeftJoin(Team,
24- Team.id == MailingList.teamID),
25+ Join(Account, Account.id == Person.accountID),
26+ Join(EmailAddress, EmailAddress.personID == Person.id),
27+ Join(TeamParticipation, TeamParticipation.personID == Person.id),
28+ Join(MailingList, MailingList.teamID == TeamParticipation.teamID),
29+ Join(Team, Team.id == MailingList.teamID),
30 )
31 team_ids = set(
32 team.id for team in store.find(
33@@ -729,20 +726,13 @@
34 Person.teamowner != None))
35 )
36 team_members = store.using(*tables).find(
37- (EmailAddress, MailingList, Person, Team),
38+ (Team.name, Person.displayname, EmailAddress.email),
39 And(TeamParticipation.teamID.is_in(team_ids),
40 MailingList.status != MailingListStatus.INACTIVE,
41 Person.teamowner == None,
42 EmailAddress.status.is_in(EMAIL_ADDRESS_STATUSES),
43 Account.status == AccountStatus.ACTIVE,
44 ))
45- # Sort allowed posters by team/mailing list.
46- by_team = {}
47- for address, mailing_list, person, team in team_members:
48- assert team.name in team_names, (
49- 'Unexpected team name in results: %s' % team.name)
50- value = (person.displayname, address.email)
51- by_team.setdefault(team.name, set()).add(value)
52 # Second, find all of the email addresses for all of the people who
53 # have been explicitly approved for posting to the team mailing lists.
54 # This occurs as part of first post moderation, but since they've
55@@ -750,31 +740,32 @@
56 # for three global approvals.
57 tables = (
58 Person,
59- LeftJoin(Account, Account.id == Person.accountID),
60- LeftJoin(EmailAddress, EmailAddress.personID == Person.id),
61- LeftJoin(MessageApproval,
62- MessageApproval.posted_byID == Person.id),
63- LeftJoin(MailingList,
64+ Join(Account, Account.id == Person.accountID),
65+ Join(EmailAddress, EmailAddress.personID == Person.id),
66+ Join(MessageApproval, MessageApproval.posted_byID == Person.id),
67+ Join(MailingList,
68 MailingList.id == MessageApproval.mailing_listID),
69- LeftJoin(Team,
70- Team.id == MailingList.teamID),
71+ Join(Team, Team.id == MailingList.teamID),
72 )
73 list_ids = set(
74 mailing_list.id for mailing_list in store.find(
75 MailingList,
76 MailingList.teamID.is_in(team_ids)))
77 approved_posters = store.using(*tables).find(
78- (EmailAddress, MessageApproval, Person, Team),
79+ (Team.name, Person.displayname, EmailAddress.email),
80 And(MessageApproval.mailing_listID.is_in(list_ids),
81 MessageApproval.status.is_in(MESSAGE_APPROVAL_STATUSES),
82 EmailAddress.status.is_in(EMAIL_ADDRESS_STATUSES),
83 Account.status == AccountStatus.ACTIVE,
84 ))
85- for address, message_approval, person, team in approved_posters:
86- assert team.name in team_names, (
87- 'Unexpected team name in results: %s' % team.name)
88- value = (person.displayname, address.email)
89- by_team.setdefault(team.name, set()).add(value)
90+ # Sort allowed posters by team/mailing list.
91+ by_team = {}
92+ all_posters = team_members.union(approved_posters)
93+ for team_name, person_displayname, email in all_posters:
94+ assert team_name in team_names, (
95+ 'Unexpected team name in results: %s' % team_name)
96+ value = (person_displayname, email)
97+ by_team.setdefault(team_name, set()).add(value)
98 # Turn the results into a mapping of lists.
99 results = {}
100 for team_name, address_set in by_team.items():
101
102=== modified file 'lib/lp/services/mailman/doc/staging.txt'
103--- lib/lp/services/mailman/doc/staging.txt 2010-04-15 11:44:04 +0000
104+++ lib/lp/services/mailman/doc/staging.txt 2010-06-09 05:07:29 +0000
105@@ -29,7 +29,8 @@
106 >>> transaction.commit()
107 >>> logout()
108
109- >>> browser = Browser('%s:%s' %
110+ >>> from canonical.launchpad.testing.pages import setupBrowser
111+ >>> browser = setupBrowser('Basic %s:%s' %
112 ... (owner._preferredemail_cached.email,
113 ... owner._password_cleartext_cached))
114