launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #03004
[Merge] lp:~lifeless/launchpad/bug-711071 into lp:launchpad
Robert Collins has proposed merging lp:~lifeless/launchpad/bug-711071 into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~lifeless/launchpad/bug-711071/+merge/53956
The bugtarget stats portlet was querying each statistic separately; this walks over the same bugs many times and is thus terribly slow. Doing the most expensive examine-all-bugs case and deriving the other information from it is much faster - so this patch does that for the most expensive properties. See the linked bug for analysis of which things are grouped and why.
--
https://code.launchpad.net/~lifeless/launchpad/bug-711071/+merge/53956
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~lifeless/launchpad/bug-711071 into lp:launchpad.
=== modified file 'lib/lp/bugs/browser/bugtask.py'
--- lib/lp/bugs/browser/bugtask.py 2011-03-15 22:58:07 +0000
+++ lib/lp/bugs/browser/bugtask.py 2011-03-18 08:35:57 +0000
@@ -77,6 +77,7 @@
from lazr.uri import URI
from pytz import utc
from simplejson import dumps
+from storm.expr import SQL
from z3c.ptcompat import ViewPageTemplateFile
from zope import (
component,
@@ -247,6 +248,8 @@
from lp.bugs.interfaces.bugwatch import BugWatchActivityStatus
from lp.bugs.interfaces.cve import ICveSet
from lp.bugs.interfaces.malone import IMaloneApplication
+from lp.bugs.model.bug import Bug
+from lp.bugs.model.bugtask import BugTask
from lp.registry.interfaces.distribution import (
IDistribution,
IDistributionSet,
@@ -1762,12 +1765,54 @@
These can be expensive to obtain.
"""
+ @cachedproperty
+ def _bug_stats(self):
+ bug_task_set = getUtility(IBugTaskSet)
+ upstream_open_bugs = bug_task_set.open_bugtask_search
+ upstream_open_bugs.setTarget(self.context)
+ upstream_open_bugs.resolved_upstream = True
+ fixed_upstream_clause = SQL(
+ bug_task_set.buildUpstreamClause(upstream_open_bugs))
+ open_bugs = bug_task_set.open_bugtask_search
+ open_bugs.setTarget(self.context)
+ groups = (BugTask.status, BugTask.importance,
+ Bug.latest_patch_uploaded != None, fixed_upstream_clause)
+ counts = bug_task_set.countBugs(open_bugs, groups)
+ # Sum the split out aggregates.
+ new = 0
+ open = 0
+ inprogress = 0
+ critical = 0
+ high = 0
+ with_patch = 0
+ resolved_upstream = 0
+ for metadata, count in counts.items():
+ status = metadata[0]
+ importance = metadata[1]
+ has_patch = metadata[2]
+ was_resolved_upstream = metadata[3]
+ if status == BugTaskStatus.NEW:
+ new += count
+ elif status == BugTaskStatus.INPROGRESS:
+ inprogress += count
+ if importance == BugTaskImportance.CRITICAL:
+ critical += count
+ elif importance == BugTaskImportance.HIGH:
+ high += count
+ if has_patch:
+ with_patch += count
+ if was_resolved_upstream:
+ resolved_upstream += count
+ open += count
+ result = dict(new=new, open=open, inprogress=inprogress, high=high,
+ critical=critical, with_patch=with_patch,
+ resolved_upstream=resolved_upstream)
+ return result
+
@property
def bugs_fixed_elsewhere_count(self):
"""A count of bugs fixed elsewhere."""
- params = get_default_search_params(self.user)
- params.resolved_upstream = True
- return self.context.searchTasks(params).count()
+ return self._bug_stats['resolved_upstream']
@property
def open_cve_bugs_count(self):
@@ -1810,27 +1855,27 @@
@property
def new_bugs_count(self):
"""A count of new bugs."""
- return self.context.new_bugtasks.count()
+ return self._bug_stats['new']
@property
def open_bugs_count(self):
"""A count of open bugs."""
- return self.context.open_bugtasks.count()
+ return self._bug_stats['open']
@property
def inprogress_bugs_count(self):
"""A count of in-progress bugs."""
- return self.context.inprogress_bugtasks.count()
+ return self._bug_stats['inprogress']
@property
def critical_bugs_count(self):
"""A count of critical bugs."""
- return self.context.critical_bugtasks.count()
+ return self._bug_stats['critical']
@property
def high_bugs_count(self):
"""A count of high priority bugs."""
- return self.context.high_bugtasks.count()
+ return self._bug_stats['high']
@property
def my_bugs_count(self):
@@ -1845,10 +1890,7 @@
@property
def bugs_with_patches_count(self):
"""A count of unresolved bugs with patches."""
- return self.context.searchTasks(
- None, user=self.user,
- status=UNRESOLVED_BUGTASK_STATUSES,
- omit_duplicates=True, has_patch=True).count()
+ return self._bug_stats['with_patch']
class BugListingPortletInfoView(LaunchpadView, BugsInfoMixin):
=== modified file 'lib/lp/bugs/configure.zcml'
--- lib/lp/bugs/configure.zcml 2011-03-16 13:26:30 +0000
+++ lib/lp/bugs/configure.zcml 2011-03-18 08:35:57 +0000
@@ -309,6 +309,11 @@
attributes="
setTarget
"/>
+ <require
+ permission="zope.Public"
+ set_attributes="
+ resolved_upstream
+ "/>
</class>
<!-- BugTaskSet -->
=== modified file 'lib/lp/bugs/interfaces/bugtask.py'
--- lib/lp/bugs/interfaces/bugtask.py 2011-03-15 22:58:07 +0000
+++ lib/lp/bugs/interfaces/bugtask.py 2011-03-18 08:35:57 +0000
@@ -1274,7 +1274,9 @@
supported.
"""
# Yay circular deps.
+ from lp.registry.interfaces.distribution import IDistribution
from lp.registry.interfaces.distroseries import IDistroSeries
+ from lp.registry.interfaces.product import IProduct
from lp.registry.interfaces.productseries import IProductSeries
from lp.registry.interfaces.milestone import IMilestone
if isinstance(target, (any, all)):
@@ -1283,8 +1285,12 @@
instance = target.query_values[0]
else:
instance = target
- if IDistroSeries.providedBy(instance):
+ if IDistribution.providedBy(instance):
+ self.setDistribution(target)
+ elif IDistroSeries.providedBy(instance):
self.setDistroSeries(target)
+ elif IProduct.providedBy(instance):
+ self.setProduct(target)
elif IProductSeries.providedBy(instance):
self.setProductSeries(target)
elif IMilestone.providedBy(instance):
@@ -1597,6 +1603,12 @@
open_bugtask_search = Attribute("A search returning open bugTasks.")
+ def buildUpstreamClause(params):
+ """Create a SQL clause to do upstream checks in a bug search.
+
+ :return: A string SQL expression.
+ """
+
def valid_remote_bug_url(value):
"""Verify that the URL is to a bug to a known bug tracker."""
=== modified file 'lib/lp/bugs/model/bugtask.py'
--- lib/lp/bugs/model/bugtask.py 2011-03-15 22:58:07 +0000
+++ lib/lp/bugs/model/bugtask.py 2011-03-18 08:35:57 +0000
@@ -1690,6 +1690,14 @@
"project group, or distribution")
return (join_tables, extra_clauses)
+ def _require_params(self, params):
+ assert zope_isinstance(params, BugTaskSearchParams)
+ if not isinstance(params, BugTaskSearchParams):
+ # Browser code let this get wrapped, unwrap it here as its just a
+ # dumb data store that has no security implications.
+ params = removeSecurityProxy(params)
+ return params
+
def buildQuery(self, params):
"""Build and return an SQL query with the given parameters.
@@ -1698,11 +1706,7 @@
:return: A query, the tables to query, ordering expression and a
decorator to call on each returned row.
"""
- assert zope_isinstance(params, BugTaskSearchParams)
- if not isinstance(params, BugTaskSearchParams):
- # Browser code let this get wrapped, unwrap it here as its just a
- # dumb data store that has no security implications.
- params = removeSecurityProxy(params)
+ params = self._require_params(params)
from lp.bugs.model.bug import Bug
extra_clauses = ['Bug.id = BugTask.bug']
clauseTables = [BugTask, Bug]
@@ -1934,7 +1938,7 @@
"""BugTask.sourcepackagename in (
select sourcepackagename from spns)""")
- upstream_clause = self._buildUpstreamClause(params)
+ upstream_clause = self.buildUpstreamClause(params)
if upstream_clause:
extra_clauses.append(upstream_clause)
@@ -2085,12 +2089,13 @@
query, clauseTables, orderby_arg, decorator, join_tables,
has_duplicate_results, with_clause)
- def _buildUpstreamClause(self, params):
+ def buildUpstreamClause(self, params):
"""Return an clause for returning upstream data if the data exists.
This method will handles BugTasks that do not have upstream BugTasks
as well as thoses that do.
"""
+ params = self._require_params(params)
upstream_clauses = []
if params.pending_bugwatch_elsewhere:
if params.product: