Merge lp:~sinzui/launchpad/milestone-table-bug-490648 into lp:launchpad

Proposed by Curtis Hovey
Status: Merged
Approved by: Curtis Hovey
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~sinzui/launchpad/milestone-table-bug-490648
Merge into: lp:launchpad
Diff against target: 129 lines (+34/-8)
4 files modified
lib/lp/registry/browser/configure.zcml (+1/-0)
lib/lp/registry/browser/milestone.py (+15/-2)
lib/lp/registry/browser/tests/milestone-views.txt (+14/-2)
lib/lp/registry/templates/productseries-milestone-table-row.pt (+4/-4)
To merge this branch: bzr merge lp:~sinzui/launchpad/milestone-table-bug-490648
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Review via email: mp+15503@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

This is my branch to improve the performance of milestone table rows.
Remove the duplicate queries and do not query objects that will not be used.

    lp:~sinzui/launchpad/milestone-table-bug-490648
    Diff size: 112
    Launchpad bug: https://bugs.launchpad.net/bugs/490648
    Test command: ./bin/test -vv -t "reg.*milestone"
    Pre-implementation: no one
    Target release: 3.1.12

= Improve the performance of the milestone table rows =

For each milestone that is shown in the milestone table, the release is looked
up three times and the structuralsubscription is looked up once, but never
used. The MilestoneView provides the release as view/release. The other two
uses must use the view's copy. The structuralsubscription is gotten because
the navigation menu is used to get the edit link. A new menu is needed that
only provides the edit link to ensure the extra db call is made.

== Rules ==

    * Create a navigation menu for the MilestoneView (used by portlets and
      tables) to provide only th links needed.
    * Update the template to use the view's copy of the release.

== QA ==

    Comparing https://edge.launchpad.net/launchpad-registry/3.1 with
    https://launchpad.net/launchpad-registry/3.1, there should be 12
    fewer queries.

== Lint ==

Linting changed files:
  lib/lp/registry/browser/configure.zcml
  lib/lp/registry/browser/milestone.py
  lib/lp/registry/browser/tests/milestone-views.txt
  lib/lp/registry/templates/productseries-milestone-table-row.pt

== Test ==

    * lib/lp/registry/browser/tests/milestone-views.txt
      * Added a test to verify the link in the new menu is legitimate.

== Implementation ==

    * lib/lp/registry/browser/configure.zcml
      * Registered the new menu.
    * lib/lp/registry/browser/milestone.py
      * Added a new navigation menu and updated MilestoneView to use it.
    * lib/lp/registry/templates/productseries-milestone-table-row.pt
      * Updated the template to use the new menu.
      * Replaced the 2 calls to product_release to use the view's release.

Revision history for this message
Gavin Panella (allenap) wrote :
Download full text (4.5 KiB)

Hi Curtis,

This is an elegant fix with a nicely big payoff.

Just a couple of comments.

Gavin.

> === modified file 'lib/lp/registry/browser/configure.zcml'
> --- lib/lp/registry/browser/configure.zcml 2009-11-26 06:41:27 +0000
> +++ lib/lp/registry/browser/configure.zcml 2009-12-02 12:04:29 +0000
> @@ -1310,6 +1310,7 @@
> <browser:menus
> classes="
> MilestoneContextMenu
> + MilestoneInlineNavigationMenu
> MilestoneOverviewMenu
> MilestoneOverviewNavigationMenu"
> module="lp.registry.browser.milestone"/>
>
> === modified file 'lib/lp/registry/browser/milestone.py'
> --- lib/lp/registry/browser/milestone.py 2009-11-24 21:27:17 +0000
> +++ lib/lp/registry/browser/milestone.py 2009-12-02 12:04:29 +0000
> @@ -11,6 +11,7 @@
> 'MilestoneContextMenu',
> 'MilestoneDeleteView',
> 'MilestoneEditView',
> + 'MilestoneInlineNavigationMenu',
> 'MilestoneNavigation',
> 'MilestoneOverviewNavigationMenu',
> 'MilestoneSetNavigation',
> @@ -22,6 +23,7 @@
>
> from zope.component import getUtility
> from zope.formlib import form
> +from zope.interface import implements, Interface
> from zope.schema import Choice
>
> from canonical.cachedproperty import cachedproperty
> @@ -131,11 +133,22 @@
> links = ('create_release', )
>
>
> +class IMilestoneInline(Interface):
> + """A marker interface for views that show a milestone inline."""
> +
> +
> +class MilestoneInlineNavigationMenu(NavigationMenu, MilestoneLinkMixin):
> + """An inline navigation menus for milestone views."""

s/menus/menu

> + usedfor = IMilestoneInline
> + facet = 'overview'
> + links = ('edit', )
> +
> +
> class MilestoneView(LaunchpadView, ProductDownloadFileMixin):
> """A View for listing milestones and releases."""
> # XXX sinzui 2009-05-29 bug=381672: Extract the BugTaskListingItem rules
> # to a mixin so that MilestoneView and others can use it.
> -
> + implements(IMilestoneInline)
> show_series_context = False
>
> def __init__(self, context, request):
>
> === modified file 'lib/lp/registry/browser/tests/milestone-views.txt'
> --- lib/lp/registry/browser/tests/milestone-views.txt 2009-09-30 22:49:58 +0000
> +++ lib/lp/registry/browser/tests/milestone-views.txt 2009-12-02 12:04:29 +0000
> @@ -21,8 +21,8 @@
> Milestone defines several menus.
>
> >>> from lp.registry.browser.milestone import (
> - ... MilestoneContextMenu, MilestoneOverviewMenu,
> - ... MilestoneOverviewNavigationMenu)
> + ... MilestoneContextMenu, MilestoneInlineNavigationMenu,
> + ... MilestoneOverviewMenu, MilestoneOverviewNavigationMenu)
> >>> from lp.testing.menu import check_menu_links
>
> >>> check_menu_links(MilestoneContextMenu(milestone))
> @@ -31,6 +31,9 @@
> True
> >>> check_menu_links(MilestoneOverviewNavigationMenu(milestone))
> True
> + >>> check_menu_links(MilestoneInlineNavigationMenu(milestone))
> + True
> +

Should there also be a test to show that the
MilestoneInlineNavigationMenu is chosen for MilestoneView, or is that
going too far?

>
> The MilestoneView provides access to the milesto...

Read more...

review: Approve
Revision history for this message
Curtis Hovey (sinzui) wrote :
Download full text (3.8 KiB)

Hi Gavin.

Thanks for the review.

On Wed, 2009-12-02 at 12:11 +0000, Gavin Panella wrote:

...

> > === modified file 'lib/lp/registry/browser/milestone.py'
> > --- lib/lp/registry/browser/milestone.py 2009-11-24 21:27:17 +0000
> > +++ lib/lp/registry/browser/milestone.py 2009-12-02 12:04:29 +0000
> > @@ -11,6 +11,7 @@
> > 'MilestoneContextMenu',
> > 'MilestoneDeleteView',
> > 'MilestoneEditView',
> > + 'MilestoneInlineNavigationMenu',
> > 'MilestoneNavigation',
> > 'MilestoneOverviewNavigationMenu',
> > 'MilestoneSetNavigation',
> > @@ -22,6 +23,7 @@
> >
> > from zope.component import getUtility
> > from zope.formlib import form
> > +from zope.interface import implements, Interface
> > from zope.schema import Choice
> >
> > from canonical.cachedproperty import cachedproperty
> > @@ -131,11 +133,22 @@
> > links = ('create_release', )
> >
> >
> > +class IMilestoneInline(Interface):
> > + """A marker interface for views that show a milestone inline."""
> > +
> > +
> > +class MilestoneInlineNavigationMenu(NavigationMenu, MilestoneLinkMixin):
> > + """An inline navigation menus for milestone views."""
>
> s/menus/menu

Fixed.

...

> > === modified file 'lib/lp/registry/browser/tests/milestone-views.txt'
> > --- lib/lp/registry/browser/tests/milestone-views.txt 2009-09-30 22:49:58 +0000
> > +++ lib/lp/registry/browser/tests/milestone-views.txt 2009-12-02 12:04:29 +0000
> > @@ -21,8 +21,8 @@
> > Milestone defines several menus.
> >
> > >>> from lp.registry.browser.milestone import (
> > - ... MilestoneContextMenu, MilestoneOverviewMenu,
> > - ... MilestoneOverviewNavigationMenu)
> > + ... MilestoneContextMenu, MilestoneInlineNavigationMenu,
> > + ... MilestoneOverviewMenu, MilestoneOverviewNavigationMenu)
> > >>> from lp.testing.menu import check_menu_links
> >
> > >>> check_menu_links(MilestoneContextMenu(milestone))
> > @@ -31,6 +31,9 @@
> > True
> > >>> check_menu_links(MilestoneOverviewNavigationMenu(milestone))
> > True
> > + >>> check_menu_links(MilestoneInlineNavigationMenu(milestone))
> > + True
> > +
>
> Should there also be a test to show that the
> MilestoneInlineNavigationMenu is chosen for MilestoneView, or is that
> going too far?

Yes, I think there should given that I botched the ZCML registration the
first time.

{{{
=== modified file 'lib/lp/registry/browser/milestone.py'
--- lib/lp/registry/browser/milestone.py 2009-12-01 18:31:10 +0000
+++ lib/lp/registry/browser/milestone.py 2009-12-02 14:53:08 +0000
@@ -120,7 +120,7 @@

 class MilestoneOverviewNavigationMenu(NavigationMenu, MilestoneLinkMixin):
- """Overview navigation menus for `IMilestone` objects."""
+ """Overview navigation menu for `IMilestone` objects."""
     usedfor = IMilestone
     facet = 'overview'
     links = ('edit', 'delete', 'subscribe')

=== modified file 'lib/lp/registry/browser/tests/milestone-views.txt'
--- lib/lp/registry/browser/tests/milestone-views.txt 2009-12-01 18:31:10 +0000
+++ lib/lp/registry/browser/tests/milestone-views.txt 2009-12-02 15:14:33 +0000
@@ -34,6 +34,15 @@
     >>> check_menu_links(MilestoneInlineNavigationMen...

Read more...

Revision history for this message
Gavin Panella (allenap) wrote :

On Wed, 02 Dec 2009 15:18:13 -0000
Curtis Hovey <email address hidden> wrote:

...
> > Should there also be a test to show that the
> > MilestoneInlineNavigationMenu is chosen for MilestoneView, or is that
> > going too far?
>
> Yes, I think there should given that I botched the ZCML registration the
> first time.
>

Cool, and it looks good.

> === modified file 'lib/lp/registry/browser/tests/milestone-views.txt'
> --- lib/lp/registry/browser/tests/milestone-views.txt 2009-12-01 18:31:10 +0000
> +++ lib/lp/registry/browser/tests/milestone-views.txt 2009-12-02 15:14:33 +0000
> @@ -34,6 +34,15 @@
> >>> check_menu_links(MilestoneInlineNavigationMenu(milestone))
> True
>
> +The MilestoneView used can be adapted to a MilestoneInlineNavigationMenu
> +for use with inline presentation of milestones.
> +
> + >>> from canonical.lazr.canonicalurl import nearest_adapter
> + >>> from canonical.launchpad.webapp.interfaces import INavigationMenu
> +
> + >>> view = create_view(milestone, name='+productseries-table-row')
> + >>> nearest_adapter(view, INavigationMenu, name='overview')
> + <lp.registry.browser.milestone.MilestoneInlineNavigationMenu ...>
>
> The MilestoneView provides access to the milestone and to its release if
> it has one.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/browser/configure.zcml'
2--- lib/lp/registry/browser/configure.zcml 2009-11-26 06:41:27 +0000
3+++ lib/lp/registry/browser/configure.zcml 2009-12-02 15:21:20 +0000
4@@ -1310,6 +1310,7 @@
5 <browser:menus
6 classes="
7 MilestoneContextMenu
8+ MilestoneInlineNavigationMenu
9 MilestoneOverviewMenu
10 MilestoneOverviewNavigationMenu"
11 module="lp.registry.browser.milestone"/>
12
13=== modified file 'lib/lp/registry/browser/milestone.py'
14--- lib/lp/registry/browser/milestone.py 2009-11-24 21:27:17 +0000
15+++ lib/lp/registry/browser/milestone.py 2009-12-02 15:21:20 +0000
16@@ -11,6 +11,7 @@
17 'MilestoneContextMenu',
18 'MilestoneDeleteView',
19 'MilestoneEditView',
20+ 'MilestoneInlineNavigationMenu',
21 'MilestoneNavigation',
22 'MilestoneOverviewNavigationMenu',
23 'MilestoneSetNavigation',
24@@ -22,6 +23,7 @@
25
26 from zope.component import getUtility
27 from zope.formlib import form
28+from zope.interface import implements, Interface
29 from zope.schema import Choice
30
31 from canonical.cachedproperty import cachedproperty
32@@ -118,7 +120,7 @@
33
34
35 class MilestoneOverviewNavigationMenu(NavigationMenu, MilestoneLinkMixin):
36- """Overview navigation menus for `IMilestone` objects."""
37+ """Overview navigation menu for `IMilestone` objects."""
38 usedfor = IMilestone
39 facet = 'overview'
40 links = ('edit', 'delete', 'subscribe')
41@@ -131,11 +133,22 @@
42 links = ('create_release', )
43
44
45+class IMilestoneInline(Interface):
46+ """A marker interface for views that show a milestone inline."""
47+
48+
49+class MilestoneInlineNavigationMenu(NavigationMenu, MilestoneLinkMixin):
50+ """An inline navigation menus for milestone views."""
51+ usedfor = IMilestoneInline
52+ facet = 'overview'
53+ links = ('edit', )
54+
55+
56 class MilestoneView(LaunchpadView, ProductDownloadFileMixin):
57 """A View for listing milestones and releases."""
58 # XXX sinzui 2009-05-29 bug=381672: Extract the BugTaskListingItem rules
59 # to a mixin so that MilestoneView and others can use it.
60-
61+ implements(IMilestoneInline)
62 show_series_context = False
63
64 def __init__(self, context, request):
65
66=== modified file 'lib/lp/registry/browser/tests/milestone-views.txt'
67--- lib/lp/registry/browser/tests/milestone-views.txt 2009-09-30 22:49:58 +0000
68+++ lib/lp/registry/browser/tests/milestone-views.txt 2009-12-02 15:21:20 +0000
69@@ -21,8 +21,8 @@
70 Milestone defines several menus.
71
72 >>> from lp.registry.browser.milestone import (
73- ... MilestoneContextMenu, MilestoneOverviewMenu,
74- ... MilestoneOverviewNavigationMenu)
75+ ... MilestoneContextMenu, MilestoneInlineNavigationMenu,
76+ ... MilestoneOverviewMenu, MilestoneOverviewNavigationMenu)
77 >>> from lp.testing.menu import check_menu_links
78
79 >>> check_menu_links(MilestoneContextMenu(milestone))
80@@ -31,6 +31,18 @@
81 True
82 >>> check_menu_links(MilestoneOverviewNavigationMenu(milestone))
83 True
84+ >>> check_menu_links(MilestoneInlineNavigationMenu(milestone))
85+ True
86+
87+The MilestoneView used can be adapted to a MilestoneInlineNavigationMenu
88+for use with inline presentation of milestones.
89+
90+ >>> from canonical.lazr.canonicalurl import nearest_adapter
91+ >>> from canonical.launchpad.webapp.interfaces import INavigationMenu
92+
93+ >>> view = create_view(milestone, name='+productseries-table-row')
94+ >>> nearest_adapter(view, INavigationMenu, name='overview')
95+ <lp.registry.browser.milestone.MilestoneInlineNavigationMenu ...>
96
97 The MilestoneView provides access to the milestone and to its release if
98 it has one.
99
100=== modified file 'lib/lp/registry/templates/productseries-milestone-table-row.pt'
101--- lib/lp/registry/templates/productseries-milestone-table-row.pt 2009-11-03 19:04:53 +0000
102+++ lib/lp/registry/templates/productseries-milestone-table-row.pt 2009-12-02 15:21:20 +0000
103@@ -2,8 +2,9 @@
104 xmlns:tal="http://xml.zope.org/namespaces/tal"
105 xmlns:metal="http://xml.zope.org/namespaces/metal"
106 xmlns:i18n="http://xml.zope.org/namespaces/i18n"
107- define="milestone_menu view/milestone/menu:navigation;
108- milestone view/milestone">
109+ define="milestone_menu view/menu:navigation;
110+ milestone view/milestone;
111+ release view/release">
112 <tr>
113 <td>
114 <img src="/@@/milestone" alt="" />
115@@ -43,13 +44,12 @@
116 </td>
117 <td tal:condition="not: view/is_distroseries_milestone">
118 <span
119- tal:define="release milestone/product_release"
120 tal:condition="release"
121 tal:attributes="title release/datereleased/fmt:datetime"
122 tal:content="release/datereleased/fmt:approximatedate">
123 2005-12-13
124 </span>
125- <tal:no-release condition="not: milestone/product_release">
126+ <tal:no-release condition="not: release">
127 <em tal:condition="not: milestone/active">
128 <img src="/@@/info"/> This is an inactive milestone
129 </em>