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
=== 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-09 05:07:29 +0000
@@ -22,7 +22,7 @@
22from string import Template22from string import Template
2323
24from storm.info import ClassAlias24from storm.info import ClassAlias
25from storm.expr import And, LeftJoin25from storm.expr import And, Join, LeftJoin
26from storm.store import Store26from storm.store import Store
2727
28from sqlobject import ForeignKey, StringCol28from sqlobject import ForeignKey, StringCol
@@ -713,14 +713,11 @@
713 Team = ClassAlias(Person)713 Team = ClassAlias(Person)
714 tables = (714 tables = (
715 Person,715 Person,
716 LeftJoin(Account, Account.id == Person.accountID),716 Join(Account, Account.id == Person.accountID),
717 LeftJoin(EmailAddress, EmailAddress.personID == Person.id),717 Join(EmailAddress, EmailAddress.personID == Person.id),
718 LeftJoin(TeamParticipation,718 Join(TeamParticipation, TeamParticipation.personID == Person.id),
719 TeamParticipation.personID == Person.id),719 Join(MailingList, MailingList.teamID == TeamParticipation.teamID),
720 LeftJoin(MailingList,720 Join(Team, Team.id == MailingList.teamID),
721 MailingList.teamID == TeamParticipation.teamID),
722 LeftJoin(Team,
723 Team.id == MailingList.teamID),
724 )721 )
725 team_ids = set(722 team_ids = set(
726 team.id for team in store.find(723 team.id for team in store.find(
@@ -729,20 +726,13 @@
729 Person.teamowner != None))726 Person.teamowner != None))
730 )727 )
731 team_members = store.using(*tables).find(728 team_members = store.using(*tables).find(
732 (EmailAddress, MailingList, Person, Team),729 (Team.name, Person.displayname, EmailAddress.email),
733 And(TeamParticipation.teamID.is_in(team_ids),730 And(TeamParticipation.teamID.is_in(team_ids),
734 MailingList.status != MailingListStatus.INACTIVE,731 MailingList.status != MailingListStatus.INACTIVE,
735 Person.teamowner == None,732 Person.teamowner == None,
736 EmailAddress.status.is_in(EMAIL_ADDRESS_STATUSES),733 EmailAddress.status.is_in(EMAIL_ADDRESS_STATUSES),
737 Account.status == AccountStatus.ACTIVE,734 Account.status == AccountStatus.ACTIVE,
738 ))735 ))
739 # Sort allowed posters by team/mailing list.
740 by_team = {}
741 for address, mailing_list, person, team in team_members:
742 assert team.name in team_names, (
743 'Unexpected team name in results: %s' % team.name)
744 value = (person.displayname, address.email)
745 by_team.setdefault(team.name, set()).add(value)
746 # Second, find all of the email addresses for all of the people who736 # Second, find all of the email addresses for all of the people who
747 # have been explicitly approved for posting to the team mailing lists.737 # have been explicitly approved for posting to the team mailing lists.
748 # This occurs as part of first post moderation, but since they've738 # This occurs as part of first post moderation, but since they've
@@ -750,31 +740,32 @@
750 # for three global approvals.740 # for three global approvals.
751 tables = (741 tables = (
752 Person,742 Person,
753 LeftJoin(Account, Account.id == Person.accountID),743 Join(Account, Account.id == Person.accountID),
754 LeftJoin(EmailAddress, EmailAddress.personID == Person.id),744 Join(EmailAddress, EmailAddress.personID == Person.id),
755 LeftJoin(MessageApproval,745 Join(MessageApproval, MessageApproval.posted_byID == Person.id),
756 MessageApproval.posted_byID == Person.id),746 Join(MailingList,
757 LeftJoin(MailingList,
758 MailingList.id == MessageApproval.mailing_listID),747 MailingList.id == MessageApproval.mailing_listID),
759 LeftJoin(Team,748 Join(Team, Team.id == MailingList.teamID),
760 Team.id == MailingList.teamID),
761 )749 )
762 list_ids = set(750 list_ids = set(
763 mailing_list.id for mailing_list in store.find(751 mailing_list.id for mailing_list in store.find(
764 MailingList,752 MailingList,
765 MailingList.teamID.is_in(team_ids)))753 MailingList.teamID.is_in(team_ids)))
766 approved_posters = store.using(*tables).find(754 approved_posters = store.using(*tables).find(
767 (EmailAddress, MessageApproval, Person, Team),755 (Team.name, Person.displayname, EmailAddress.email),
768 And(MessageApproval.mailing_listID.is_in(list_ids),756 And(MessageApproval.mailing_listID.is_in(list_ids),
769 MessageApproval.status.is_in(MESSAGE_APPROVAL_STATUSES),757 MessageApproval.status.is_in(MESSAGE_APPROVAL_STATUSES),
770 EmailAddress.status.is_in(EMAIL_ADDRESS_STATUSES),758 EmailAddress.status.is_in(EMAIL_ADDRESS_STATUSES),
771 Account.status == AccountStatus.ACTIVE,759 Account.status == AccountStatus.ACTIVE,
772 ))760 ))
773 for address, message_approval, person, team in approved_posters:761 # Sort allowed posters by team/mailing list.
774 assert team.name in team_names, (762 by_team = {}
775 'Unexpected team name in results: %s' % team.name)763 all_posters = team_members.union(approved_posters)
776 value = (person.displayname, address.email)764 for team_name, person_displayname, email in all_posters:
777 by_team.setdefault(team.name, set()).add(value)765 assert team_name in team_names, (
766 'Unexpected team name in results: %s' % team_name)
767 value = (person_displayname, email)
768 by_team.setdefault(team_name, set()).add(value)
778 # Turn the results into a mapping of lists.769 # Turn the results into a mapping of lists.
779 results = {}770 results = {}
780 for team_name, address_set in by_team.items():771 for team_name, address_set in by_team.items():
781772
=== modified file 'lib/lp/services/mailman/doc/staging.txt'
--- lib/lp/services/mailman/doc/staging.txt 2010-04-15 11:44:04 +0000
+++ lib/lp/services/mailman/doc/staging.txt 2010-06-09 05:07:29 +0000
@@ -29,7 +29,8 @@
29 >>> transaction.commit()29 >>> transaction.commit()
30 >>> logout()30 >>> logout()
3131
32 >>> browser = Browser('%s:%s' %32 >>> from canonical.launchpad.testing.pages import setupBrowser
33 >>> browser = setupBrowser('Basic %s:%s' %
33 ... (owner._preferredemail_cached.email,34 ... (owner._preferredemail_cached.email,
34 ... owner._password_cleartext_cached))35 ... owner._password_cleartext_cached))
3536