launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #02698
[Merge] lp:~lifeless/launchpad/bug-717394-4 into lp:launchpad
Robert Collins has proposed merging lp:~lifeless/launchpad/bug-717394-4 into lp:launchpad with lp:~lifeless/launchpad/bug-717394-3 as a prerequisite.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
#722429 bugs with milestones trigger just in time lookups in bug searches
https://bugs.launchpad.net/bugs/722429
For more details, see:
https://code.launchpad.net/~lifeless/launchpad/bug-717394-4/+merge/50548
Bug searches were doing lazy evaluation of bug milestones during rendering the mouseover text. This is a problem in milestone heavy environments. Eager load the milestones for the current batch.
--
https://code.launchpad.net/~lifeless/launchpad/bug-717394-4/+merge/50548
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~lifeless/launchpad/bug-717394-4 into lp:launchpad.
=== modified file 'lib/lp/bugs/configure.zcml'
--- lib/lp/bugs/configure.zcml 2011-02-18 08:01:09 +0000
+++ lib/lp/bugs/configure.zcml 2011-02-21 04:27:58 +0000
@@ -193,6 +193,7 @@
date_fix_released
date_left_closed
date_closed
+ milestoneID
productseriesID
task_age
bug_subscribers
=== modified file 'lib/lp/bugs/interfaces/bugtask.py'
--- lib/lp/bugs/interfaces/bugtask.py 2011-02-21 04:27:58 +0000
+++ lib/lp/bugs/interfaces/bugtask.py 2011-02-21 04:27:58 +0000
@@ -477,6 +477,7 @@
readonly=True,
vocabulary='Milestone',
schema=Interface)) # IMilestone
+ milestoneID = Attribute('The id of the milestone.')
# XXX kiko 2006-03-23:
# The status and importance's vocabularies do not
=== modified file 'lib/lp/bugs/model/bugtask.py'
--- lib/lp/bugs/model/bugtask.py 2011-02-21 04:27:58 +0000
+++ lib/lp/bugs/model/bugtask.py 2011-02-21 04:27:58 +0000
@@ -145,7 +145,10 @@
IDistroSeries,
IDistroSeriesSet,
)
-from lp.registry.interfaces.milestone import IProjectGroupMilestone
+from lp.registry.interfaces.milestone import (
+ IMilestoneSet,
+ IProjectGroupMilestone,
+ )
from lp.registry.interfaces.person import (
IPerson,
validate_person,
@@ -1559,6 +1562,13 @@
SpecificationBug.bugID.is_in(bug_ids)))
bug_ids_with_branches = set(IStore(BugBranch).find(
BugBranch.bugID, BugBranch.bugID.is_in(bug_ids)))
+ # Badging looks up milestones too : eager load into the storm cache.
+ milestoneset = getUtility(IMilestoneSet)
+ # And trigger a load:
+ milestone_ids = set(map(attrgetter('milestoneID'), bugtasks))
+ milestone_ids.discard(None)
+ if milestone_ids:
+ list(milestoneset.getByIds(milestone_ids))
# Check if the bugs are cached. If not, cache all uncached bugs
# at once to avoid one query per bugtask. We could rely on the
=== modified file 'lib/lp/registry/browser/tests/test_milestone.py'
--- lib/lp/registry/browser/tests/test_milestone.py 2011-02-13 23:02:49 +0000
+++ lib/lp/registry/browser/tests/test_milestone.py 2011-02-21 04:27:58 +0000
@@ -234,12 +234,14 @@
def test_bugtasks_queries(self):
# The view.bugtasks attribute will make four queries:
# 1. Load bugtasks and bugs.
- # 2. Load assignees (Person, Account, and EmailAddress).
- # 3. Load links to specifications.
- # 4. Load links to branches.
+ # 2. Loads the target (sourcepackagename / product)
+ # 3. Load assignees (Person, Account, and EmailAddress).
+ # 4. Load links to specifications.
+ # 5. Load links to branches.
+ # 6. Loads milestones
bugtask_count = 10
self.assert_bugtasks_query_count(
- self.milestone, bugtask_count, query_limit=6)
+ self.milestone, bugtask_count, query_limit=7)
def test_milestone_eager_loading(self):
# Verify that the number of queries does not increase with more
@@ -260,7 +262,7 @@
# is very large already, if the test fails due to such a change,
# please cut some more of the existing fat out of it rather than
# increasing the cap.
- page_query_limit = 34
+ page_query_limit = 35
product = self.factory.makeProduct()
login_person(product.owner)
milestone = self.factory.makeMilestone(
@@ -359,9 +361,10 @@
# 3. Load assignees (Person, Account, and EmailAddress).
# 4. Load links to specifications.
# 5. Load links to branches.
+ # 6. Loads milestones.
bugtask_count = 10
self.assert_bugtasks_query_count(
- self.milestone, bugtask_count, query_limit=6)
+ self.milestone, bugtask_count, query_limit=7)
def test_milestone_eager_loading(self):
# Verify that the number of queries does not increase with more
@@ -419,17 +422,19 @@
# 2. Check if the user is in the admin team.
# 3. Check if the user is in the owner of the admin team.
# 4. Load bugtasks and bugs.
- # 5. Load assignees (Person, Account, and EmailAddress).
- # 6. Load links to specifications.
- # 7. Load links to branches.
+ # 5. load the source package names.
+ # 6. Load assignees (Person, Account, and EmailAddress).
+ # 7. Load links to specifications.
+ # 8. Load links to branches.
+ # 9. Load links to milestones.
bugtask_count = 10
self.assert_bugtasks_query_count(
- self.milestone, bugtask_count, query_limit=9)
+ self.milestone, bugtask_count, query_limit=10)
def test_milestone_eager_loading(self):
# Verify that the number of queries does not increase with more
# bugs with different assignees.
- query_limit = 33
+ query_limit = 34
self.add_bug(3)
self.assert_milestone_page_query_count(
self.milestone, query_limit=query_limit)
=== modified file 'lib/lp/registry/interfaces/milestone.py'
--- lib/lp/registry/interfaces/milestone.py 2011-01-21 08:12:29 +0000
+++ lib/lp/registry/interfaces/milestone.py 2011-02-21 04:27:58 +0000
@@ -229,6 +229,9 @@
NotFoundError will be raised.
"""
+ def getByIds(milestoneids):
+ """Get the milestones for milestoneids."""
+
def getByNameAndProduct(name, product, default=None):
"""Get a milestone by its name and product.
=== modified file 'lib/lp/registry/model/milestone.py'
--- lib/lp/registry/model/milestone.py 2011-01-21 08:12:29 +0000
+++ lib/lp/registry/model/milestone.py 2011-02-21 04:27:58 +0000
@@ -37,6 +37,7 @@
SQLBase,
sqlvalues,
)
+from canonical.launchpad.interfaces.lpstorm import IStore
from canonical.launchpad.webapp.sorting import expand_numbers
from lp.app.errors import NotFoundError
from lp.blueprints.model.specification import Specification
@@ -257,11 +258,16 @@
def get(self, milestoneid):
"""See lp.registry.interfaces.milestone.IMilestoneSet."""
- try:
- return Milestone.get(milestoneid)
- except SQLObjectNotFound:
+ result = list(self.getByIds([milestoneid]))
+ if not result:
raise NotFoundError(
"Milestone with ID %d does not exist" % milestoneid)
+ return result[0]
+
+ def getByIds(self, milestoneids):
+ """See `IMilestoneSet`."""
+ return IStore(Milestone).find(Milestone,
+ Milestone.id.is_in(milestoneids))
def getByNameAndProduct(self, name, product, default=None):
"""See lp.registry.interfaces.milestone.IMilestoneSet."""
=== modified file 'lib/lp/registry/tests/test_milestone.py'
--- lib/lp/registry/tests/test_milestone.py 2011-01-12 18:05:13 +0000
+++ lib/lp/registry/tests/test_milestone.py 2011-02-21 04:27:58 +0000
@@ -5,6 +5,7 @@
__metaclass__ = type
+from operator import attrgetter
import unittest
from zope.component import getUtility
@@ -53,6 +54,17 @@
self.assertEqual(milestone_set.get(1).id, 1)
self.assertRaises(NotFoundError, milestone_set.get, 100000)
+ def testMilestoneSetGetIDs(self):
+ """Test of MilestoneSet.getByIds()"""
+ milestone_set = getUtility(IMilestoneSet)
+ milestones = milestone_set.getByIds([1,3])
+ ids = sorted(map(attrgetter('id'), milestones))
+ self.assertEqual([1, 3], ids)
+
+ def testMilestoneSetGetByIDs_ignores_missing(self):
+ milestone_set = getUtility(IMilestoneSet)
+ self.assertEqual([], list(milestone_set.getByIds([100000])))
+
def testMilestoneSetGetByNameAndProduct(self):
"""Test of MilestoneSet.getByNameAndProduct()"""
firefox = getUtility(IProductSet).getByName('firefox')