Merge lp://staging/~intellectronica/launchpad/update-max-heat into lp://staging/launchpad/db-devel
- update-max-heat
- Merge into db-devel
Status: | Merged |
---|---|
Approved by: | Deryck Hodge |
Approved revision: | not available |
Merged at revision: | not available |
Proposed branch: | lp://staging/~intellectronica/launchpad/update-max-heat |
Merge into: | lp://staging/launchpad/db-devel |
Diff against target: |
272 lines (+141/-5) 8 files modified
database/schema/security.cfg (+5/-4) lib/lp/bugs/browser/bugtask.py (+2/-0) lib/lp/bugs/doc/bug-heat.txt (+56/-0) lib/lp/bugs/interfaces/bugtarget.py (+4/-0) lib/lp/bugs/model/bug.py (+7/-0) lib/lp/bugs/model/bugtarget.py (+56/-0) lib/lp/bugs/model/bugtask.py (+9/-0) lib/lp/registry/configure.zcml (+2/-1) |
To merge this branch: | bzr merge lp://staging/~intellectronica/launchpad/update-max-heat |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Deryck Hodge (community) | code | Approve | |
Review via email:
|
Commit message
Description of the change
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Eleanor Berger (intellectronica) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Deryck Hodge (deryck) wrote : | # |
Hi, Tom.
As we discussed on IRC, we should replace the UNION ALL queries with something like the following for each target type:
SELECT Bug.heat
FROM Bug, Bugtask, DistroSeries
WHERE Bugtask.bug = Bug.id
AND Bugtask.
OR Bugtask.
AND Bugtask.
ORDER BY Bug.heat DESC LIMIT 1;
This goes from 4 second queries to .2 ms queries. Given these savings, this can land with those changes. We don't have to worry about cowboy'ing on to staging unless you happen to catch Gavin on IRC before his cowboy'ed patch.
Thanks for working on this! The code looks good otherwise and will be a good to have done for the rollout.
This is marked approved assuming these changes are applied.
Cheers,
deryck
Preview Diff
1 | === modified file 'database/schema/security.cfg' | |||
2 | --- database/schema/security.cfg 2010-02-26 11:31:12 +0000 | |||
3 | +++ database/schema/security.cfg 2010-03-01 17:41:14 +0000 | |||
4 | @@ -1494,12 +1494,14 @@ | |||
5 | 1494 | public.archive = SELECT | 1494 | public.archive = SELECT |
6 | 1495 | public.archivearch = SELECT | 1495 | public.archivearch = SELECT |
7 | 1496 | public.component = SELECT | 1496 | public.component = SELECT |
9 | 1497 | public.distribution = SELECT | 1497 | public.distribution = SELECT, UPDATE |
10 | 1498 | public.distributionsourcepackage = SELECT, INSERT, UPDATE | ||
11 | 1498 | public.distrocomponentuploader = SELECT | 1499 | public.distrocomponentuploader = SELECT |
12 | 1500 | public.distroseries = SELECT | ||
13 | 1499 | public.archivepermission = SELECT | 1501 | public.archivepermission = SELECT |
14 | 1500 | public.distroseries = SELECT | 1502 | public.distroseries = SELECT |
17 | 1501 | public.project = SELECT | 1503 | public.project = SELECT, UPDATE |
18 | 1502 | public.product = SELECT | 1504 | public.product = SELECT, UPDATE |
19 | 1503 | public.productseries = SELECT | 1505 | public.productseries = SELECT |
20 | 1504 | public.packagebugsupervisor = SELECT | 1506 | public.packagebugsupervisor = SELECT |
21 | 1505 | public.sourcepackagename = SELECT | 1507 | public.sourcepackagename = SELECT |
22 | @@ -1566,7 +1568,6 @@ | |||
23 | 1566 | public.codereviewmessage = SELECT, INSERT | 1568 | public.codereviewmessage = SELECT, INSERT |
24 | 1567 | public.codereviewvote = SELECT, INSERT, UPDATE | 1569 | public.codereviewvote = SELECT, INSERT, UPDATE |
25 | 1568 | public.diff = SELECT, INSERT, UPDATE | 1570 | public.diff = SELECT, INSERT, UPDATE |
26 | 1569 | public.distribution = SELECT | ||
27 | 1570 | public.distroseries = SELECT | 1571 | public.distroseries = SELECT |
28 | 1571 | public.job = SELECT, INSERT, UPDATE | 1572 | public.job = SELECT, INSERT, UPDATE |
29 | 1572 | public.mergedirectivejob = SELECT, INSERT | 1573 | public.mergedirectivejob = SELECT, INSERT |
30 | 1573 | 1574 | ||
31 | === modified file 'lib/lp/bugs/browser/bugtask.py' | |||
32 | --- lib/lp/bugs/browser/bugtask.py 2010-02-28 10:00:45 +0000 | |||
33 | +++ lib/lp/bugs/browser/bugtask.py 2010-03-01 17:41:14 +0000 | |||
34 | @@ -1090,6 +1090,8 @@ | |||
35 | 1090 | """Calculate the number of heat 'flames' to display.""" | 1090 | """Calculate the number of heat 'flames' to display.""" |
36 | 1091 | heat = float(heat) | 1091 | heat = float(heat) |
37 | 1092 | max_bug_heat = float(max_bug_heat) | 1092 | max_bug_heat = float(max_bug_heat) |
38 | 1093 | if max_bug_heat == 0: | ||
39 | 1094 | return 0 | ||
40 | 1093 | if heat / max_bug_heat < 0.33333: | 1095 | if heat / max_bug_heat < 0.33333: |
41 | 1094 | return 0 | 1096 | return 0 |
42 | 1095 | if heat / max_bug_heat < 0.66666 or max_bug_heat < 2: | 1097 | if heat / max_bug_heat < 0.66666 or max_bug_heat < 2: |
43 | 1096 | 1098 | ||
44 | === modified file 'lib/lp/bugs/doc/bug-heat.txt' | |||
45 | --- lib/lp/bugs/doc/bug-heat.txt 2010-02-27 14:45:01 +0000 | |||
46 | +++ lib/lp/bugs/doc/bug-heat.txt 2010-03-01 17:41:14 +0000 | |||
47 | @@ -60,3 +60,59 @@ | |||
48 | 60 | 60 | ||
49 | 61 | >>> bug_1.heat > 0 | 61 | >>> bug_1.heat > 0 |
50 | 62 | True | 62 | True |
51 | 63 | |||
52 | 64 | |||
53 | 65 | Caculating the maximum heat for a target | ||
54 | 66 | ---------------------------------------- | ||
55 | 67 | |||
56 | 68 | When we update the heat value for a bug, the maximum heat value for the targets | ||
57 | 69 | for all of its tasks is calculated and cached. | ||
58 | 70 | |||
59 | 71 | >>> product = factory.makeProduct() | ||
60 | 72 | >>> bug = factory.makeBug(product=product) | ||
61 | 73 | >>> print product.max_bug_heat | ||
62 | 74 | None | ||
63 | 75 | >>> bug.setHeat(123) | ||
64 | 76 | >>> print product.max_bug_heat | ||
65 | 77 | 123 | ||
66 | 78 | |||
67 | 79 | The maximum heat for a project is the value for tasks on all its products. | ||
68 | 80 | |||
69 | 81 | >>> project = factory.makeProject() | ||
70 | 82 | >>> product.project = project | ||
71 | 83 | >>> bug.setHeat(123) | ||
72 | 84 | >>> print project.max_bug_heat | ||
73 | 85 | 123 | ||
74 | 86 | |||
75 | 87 | A DistributionSourcePackage has its own maximum heat. | ||
76 | 88 | |||
77 | 89 | >>> dsp = factory.makeDistributionSourcePackage() | ||
78 | 90 | >>> dsp_task = bug.addTask(bug.owner, dsp) | ||
79 | 91 | >>> print dsp.max_bug_heat | ||
80 | 92 | 123 | ||
81 | 93 | |||
82 | 94 | Transitioning from one target to another, calculates the value for the new | ||
83 | 95 | target. | ||
84 | 96 | |||
85 | 97 | >>> another_product = factory.makeProduct() | ||
86 | 98 | >>> bug.bugtasks[0].transitionToTarget(another_product) | ||
87 | 99 | >>> print another_product.max_bug_heat | ||
88 | 100 | 123 | ||
89 | 101 | |||
90 | 102 | ProductSeries and DistroSeries simply delegate to their corresponding Product | ||
91 | 103 | or Distribution. | ||
92 | 104 | |||
93 | 105 | >>> product_series = factory.makeProductSeries() | ||
94 | 106 | >>> ps_task = bug.addTask(bug.owner, product_series) | ||
95 | 107 | >>> print product_series.max_bug_heat | ||
96 | 108 | 123 | ||
97 | 109 | >>> print product_series.product.max_bug_heat | ||
98 | 110 | 123 | ||
99 | 111 | |||
100 | 112 | >>> distro_series = factory.makeDistroSeries() | ||
101 | 113 | >>> ds_task = bug.addTask(bug.owner, distro_series) | ||
102 | 114 | >>> print distro_series.max_bug_heat | ||
103 | 115 | 123 | ||
104 | 116 | >>> print distro_series.distribution.max_bug_heat | ||
105 | 117 | 123 | ||
106 | 118 | |||
107 | 63 | 119 | ||
108 | === modified file 'lib/lp/bugs/interfaces/bugtarget.py' | |||
109 | --- lib/lp/bugs/interfaces/bugtarget.py 2010-02-27 21:18:10 +0000 | |||
110 | +++ lib/lp/bugs/interfaces/bugtarget.py 2010-03-01 17:41:14 +0000 | |||
111 | @@ -207,6 +207,10 @@ | |||
112 | 207 | def setMaxBugHeat(heat): | 207 | def setMaxBugHeat(heat): |
113 | 208 | """Set the max_bug_heat for this context.""" | 208 | """Set the max_bug_heat for this context.""" |
114 | 209 | 209 | ||
115 | 210 | def recalculateMaxBugHeat(): | ||
116 | 211 | """Recalculate and set the max_bug_heat for this context.""" | ||
117 | 212 | |||
118 | 213 | |||
119 | 210 | 214 | ||
120 | 211 | class IBugTarget(IHasBugs): | 215 | class IBugTarget(IHasBugs): |
121 | 212 | """An entity on which a bug can be reported. | 216 | """An entity on which a bug can be reported. |
122 | 213 | 217 | ||
123 | === modified file 'lib/lp/bugs/model/bug.py' | |||
124 | --- lib/lp/bugs/model/bug.py 2010-02-26 05:13:11 +0000 | |||
125 | +++ lib/lp/bugs/model/bug.py 2010-03-01 17:41:14 +0000 | |||
126 | @@ -100,6 +100,7 @@ | |||
127 | 100 | from lp.registry.interfaces.person import validate_public_person | 100 | from lp.registry.interfaces.person import validate_public_person |
128 | 101 | from lp.registry.interfaces.product import IProduct | 101 | from lp.registry.interfaces.product import IProduct |
129 | 102 | from lp.registry.interfaces.productseries import IProductSeries | 102 | from lp.registry.interfaces.productseries import IProductSeries |
130 | 103 | from lp.registry.interfaces.projectgroup import IProjectGroup | ||
131 | 103 | from lp.registry.interfaces.sourcepackage import ISourcePackage | 104 | from lp.registry.interfaces.sourcepackage import ISourcePackage |
132 | 104 | from lp.registry.model.mentoringoffer import MentoringOffer | 105 | from lp.registry.model.mentoringoffer import MentoringOffer |
133 | 105 | from lp.registry.model.person import Person, ValidPersonCache | 106 | from lp.registry.model.person import Person, ValidPersonCache |
134 | @@ -876,6 +877,10 @@ | |||
135 | 876 | distroseries=distro_series, | 877 | distroseries=distro_series, |
136 | 877 | sourcepackagename=source_package_name) | 878 | sourcepackagename=source_package_name) |
137 | 878 | 879 | ||
138 | 880 | # When a new task is added the bug's heat becomes relevant to the | ||
139 | 881 | # target's max_bug_heat. | ||
140 | 882 | target.recalculateMaxBugHeat() | ||
141 | 883 | |||
142 | 879 | return new_task | 884 | return new_task |
143 | 880 | 885 | ||
144 | 881 | def addWatch(self, bugtracker, remotebug, owner): | 886 | def addWatch(self, bugtracker, remotebug, owner): |
145 | @@ -1529,6 +1534,8 @@ | |||
146 | 1529 | def setHeat(self, heat): | 1534 | def setHeat(self, heat): |
147 | 1530 | """See `IBug`.""" | 1535 | """See `IBug`.""" |
148 | 1531 | self.heat = heat | 1536 | self.heat = heat |
149 | 1537 | for task in self.bugtasks: | ||
150 | 1538 | task.target.recalculateMaxBugHeat() | ||
151 | 1532 | 1539 | ||
152 | 1533 | 1540 | ||
153 | 1534 | class BugSet: | 1541 | class BugSet: |
154 | 1535 | 1542 | ||
155 | === modified file 'lib/lp/bugs/model/bugtarget.py' | |||
156 | --- lib/lp/bugs/model/bugtarget.py 2010-02-26 05:45:47 +0000 | |||
157 | +++ lib/lp/bugs/model/bugtarget.py 2010-03-01 17:41:14 +0000 | |||
158 | @@ -25,10 +25,13 @@ | |||
159 | 25 | from canonical.launchpad.webapp.interfaces import ILaunchBag | 25 | from canonical.launchpad.webapp.interfaces import ILaunchBag |
160 | 26 | from lp.bugs.interfaces.bugtarget import IOfficialBugTag | 26 | from lp.bugs.interfaces.bugtarget import IOfficialBugTag |
161 | 27 | from lp.registry.interfaces.distribution import IDistribution | 27 | from lp.registry.interfaces.distribution import IDistribution |
162 | 28 | from lp.registry.interfaces.distroseries import IDistroSeries | ||
163 | 28 | from lp.registry.interfaces.distributionsourcepackage import ( | 29 | from lp.registry.interfaces.distributionsourcepackage import ( |
164 | 29 | IDistributionSourcePackage) | 30 | IDistributionSourcePackage) |
165 | 30 | from lp.registry.interfaces.product import IProduct | 31 | from lp.registry.interfaces.product import IProduct |
166 | 32 | from lp.registry.interfaces.productseries import IProductSeries | ||
167 | 31 | from lp.registry.interfaces.projectgroup import IProjectGroup | 33 | from lp.registry.interfaces.projectgroup import IProjectGroup |
168 | 34 | from lp.registry.interfaces.sourcepackage import ISourcePackage | ||
169 | 32 | from lp.bugs.interfaces.bugtask import ( | 35 | from lp.bugs.interfaces.bugtask import ( |
170 | 33 | BugTagsSearchCombinator, BugTaskImportance, BugTaskSearchParams, | 36 | BugTagsSearchCombinator, BugTaskImportance, BugTaskSearchParams, |
171 | 34 | BugTaskStatus, RESOLVED_BUGTASK_STATUSES, UNRESOLVED_BUGTASK_STATUSES) | 37 | BugTaskStatus, RESOLVED_BUGTASK_STATUSES, UNRESOLVED_BUGTASK_STATUSES) |
172 | @@ -170,6 +173,59 @@ | |||
173 | 170 | else: | 173 | else: |
174 | 171 | raise NotImplementedError | 174 | raise NotImplementedError |
175 | 172 | 175 | ||
176 | 176 | def recalculateMaxBugHeat(self): | ||
177 | 177 | """See `IHasBugs`.""" | ||
178 | 178 | if IProductSeries.providedBy(self): | ||
179 | 179 | return self.product.recalculateMaxBugHeat() | ||
180 | 180 | if IDistroSeries.providedBy(self): | ||
181 | 181 | return self.distribution.recalculateMaxBugHeat() | ||
182 | 182 | if ISourcePackage.providedBy(self): | ||
183 | 183 | # Should only happen for nominations, so we can safely skip | ||
184 | 184 | # recalculating max_heat. | ||
185 | 185 | return | ||
186 | 186 | |||
187 | 187 | if IDistribution.providedBy(self): | ||
188 | 188 | sql = """SELECT Bug.heat | ||
189 | 189 | FROM Bug, Bugtask, DistroSeries | ||
190 | 190 | WHERE Bugtask.bug = Bug.id | ||
191 | 191 | AND Bugtask.distroseries = DistroSeries.id | ||
192 | 192 | OR Bugtask.distribution = DistroSeries.distribution | ||
193 | 193 | AND Bugtask.distribution = %s | ||
194 | 194 | ORDER BY Bug.heat DESC LIMIT 1""" % sqlvalues(self) | ||
195 | 195 | elif IProduct.providedBy(self): | ||
196 | 196 | sql = """SELECT Bug.heat | ||
197 | 197 | FROM Bug, Bugtask, ProductSeries | ||
198 | 198 | WHERE Bugtask.bug = Bug.id | ||
199 | 199 | AND Bugtask.productseries = ProductSeries.id | ||
200 | 200 | OR Bugtask.product = ProductSeries.product | ||
201 | 201 | AND Bugtask.product = %s | ||
202 | 202 | ORDER BY Bug.heat DESC LIMIT 1""" % sqlvalues(self) | ||
203 | 203 | elif IProjectGroup.providedBy(self): | ||
204 | 204 | sql = """SELECT MAX(heat) | ||
205 | 205 | FROM Bug, Bugtask, Product | ||
206 | 206 | WHERE Bugtask.bug = Bug.id AND | ||
207 | 207 | Bugtask.product = Product.id AND | ||
208 | 208 | Product.project = %s""" % sqlvalues(self) | ||
209 | 209 | elif IDistributionSourcePackage.providedBy(self): | ||
210 | 210 | sql = """SELECT MAX(heat) | ||
211 | 211 | FROM Bug, Bugtask | ||
212 | 212 | WHERE Bugtask.bug = Bug.id AND | ||
213 | 213 | Bugtask.distribution = %s AND | ||
214 | 214 | Bugtask.sourcepackagename = %s""" % sqlvalues( | ||
215 | 215 | self.distribution, self.sourcepackagename) | ||
216 | 216 | else: | ||
217 | 217 | raise NotImplementedError | ||
218 | 218 | |||
219 | 219 | cur = cursor() | ||
220 | 220 | cur.execute(sql) | ||
221 | 221 | self.setMaxBugHeat(cur.fetchone()[0]) | ||
222 | 222 | |||
223 | 223 | # If the product is part of a project group we calculate the maximum | ||
224 | 224 | # heat for the project group too. | ||
225 | 225 | if IProduct.providedBy(self) and self.project is not None: | ||
226 | 226 | self.project.recalculateMaxBugHeat() | ||
227 | 227 | |||
228 | 228 | |||
229 | 173 | def getBugCounts(self, user, statuses=None): | 229 | def getBugCounts(self, user, statuses=None): |
230 | 174 | """See `IHasBugs`.""" | 230 | """See `IHasBugs`.""" |
231 | 175 | if statuses is None: | 231 | if statuses is None: |
232 | 176 | 232 | ||
233 | === modified file 'lib/lp/bugs/model/bugtask.py' | |||
234 | --- lib/lp/bugs/model/bugtask.py 2010-02-27 20:20:03 +0000 | |||
235 | +++ lib/lp/bugs/model/bugtask.py 2010-03-01 17:41:14 +0000 | |||
236 | @@ -969,6 +969,9 @@ | |||
237 | 969 | enforced implicitly by the code in | 969 | enforced implicitly by the code in |
238 | 970 | lib/canonical/launchpad/browser/bugtask.py#BugTaskEditView. | 970 | lib/canonical/launchpad/browser/bugtask.py#BugTaskEditView. |
239 | 971 | """ | 971 | """ |
240 | 972 | |||
241 | 973 | target_before_change = self.target | ||
242 | 974 | |||
243 | 972 | if (self.milestone is not None and | 975 | if (self.milestone is not None and |
244 | 973 | self.milestone.target != target): | 976 | self.milestone.target != target): |
245 | 974 | # If the milestone for this bugtask is set, we | 977 | # If the milestone for this bugtask is set, we |
246 | @@ -993,6 +996,12 @@ | |||
247 | 993 | "Distribution bug tasks may only be re-targeted " | 996 | "Distribution bug tasks may only be re-targeted " |
248 | 994 | "to a package in the same distribution.") | 997 | "to a package in the same distribution.") |
249 | 995 | 998 | ||
250 | 999 | # After the target has changed, we need to recalculate the maximum bug | ||
251 | 1000 | # heat for the new and old targets. | ||
252 | 1001 | if self.target != target_before_change: | ||
253 | 1002 | target_before_change.recalculateMaxBugHeat() | ||
254 | 1003 | self.target.recalculateMaxBugHeat() | ||
255 | 1004 | |||
256 | 996 | def updateTargetNameCache(self, newtarget=None): | 1005 | def updateTargetNameCache(self, newtarget=None): |
257 | 997 | """See `IBugTask`.""" | 1006 | """See `IBugTask`.""" |
258 | 998 | if newtarget is None: | 1007 | if newtarget is None: |
259 | 999 | 1008 | ||
260 | === modified file 'lib/lp/registry/configure.zcml' | |||
261 | --- lib/lp/registry/configure.zcml 2010-02-27 20:20:03 +0000 | |||
262 | +++ lib/lp/registry/configure.zcml 2010-03-01 17:41:14 +0000 | |||
263 | @@ -408,7 +408,8 @@ | |||
264 | 408 | findRelatedArchives | 408 | findRelatedArchives |
265 | 409 | findRelatedArchivePublications | 409 | findRelatedArchivePublications |
266 | 410 | userHasBugSubscriptions | 410 | userHasBugSubscriptions |
268 | 411 | max_bug_heat"/> | 411 | max_bug_heat |
269 | 412 | recalculateMaxBugHeat"/> | ||
270 | 412 | <require | 413 | <require |
271 | 413 | permission="launchpad.AnyPerson" | 414 | permission="launchpad.AnyPerson" |
272 | 414 | attributes=" | 415 | attributes=" |
This branch adds a step which calculates a target's max_bug_heat when a bug's heat is set, or when a change to a bugtask or the addition of a task is made.