launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #10208
[Merge] lp:~wgrant/launchpad/faster-checkCanBeDeleted into lp:launchpad
William Grant has proposed merging lp:~wgrant/launchpad/faster-checkCanBeDeleted into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1028256 in Launchpad itself: "BugTask.canBeDeleted issues a query for every call"
https://bugs.launchpad.net/launchpad/+bug/1028256
For more details, see:
https://code.launchpad.net/~wgrant/launchpad/faster-checkCanBeDeleted/+merge/116404
This branch fixes bug #1028256 by making BugTask.canBeDeleted work off the bug's cached list of tasks, rather than calculating a fresh count. This fixes the leading cause of O(tasks) queries on BugTask:+index.
--
https://code.launchpad.net/~wgrant/launchpad/faster-checkCanBeDeleted/+merge/116404
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/faster-checkCanBeDeleted into lp:launchpad.
=== modified file 'lib/lp/bugs/model/bugtask.py'
--- lib/lp/bugs/model/bugtask.py 2012-07-17 06:34:59 +0000
+++ lib/lp/bugs/model/bugtask.py 2012-07-24 05:30:27 +0000
@@ -622,10 +622,9 @@
return True
def checkCanBeDeleted(self):
- num_bugtasks = Store.of(self).find(
- BugTask, bug=self.bug).count()
-
- if num_bugtasks < 2:
+ # Bug.bugtasks is a cachedproperty, so this is pretty much free
+ # to call. Better than a manual count query, at any rate.
+ if len(self.bug.bugtasks) < 2:
raise CannotDeleteBugtask(
"Cannot delete only bugtask affecting: %s."
% self.target.bugtargetdisplayname)
=== modified file 'lib/lp/bugs/model/tests/test_bugtask.py'
--- lib/lp/bugs/model/tests/test_bugtask.py 2012-07-24 04:04:07 +0000
+++ lib/lp/bugs/model/tests/test_bugtask.py 2012-07-24 05:30:27 +0000
@@ -13,6 +13,7 @@
from lazr.lifecycle.snapshot import Snapshot
from lazr.restfulclient.errors import Unauthorized
from storm.store import Store
+from testtools.matchers import Equals
from testtools.testcase import ExpectedException
import transaction
from zope.component import getUtility
@@ -97,6 +98,7 @@
logout,
person_logged_in,
set_feature_flag,
+ StormStatementRecorder,
TestCase,
TestCaseWithFactory,
ws_object,
@@ -108,6 +110,7 @@
CeleryJobLayer,
DatabaseFunctionalLayer,
)
+from lp.testing.matchers import HasQueryCount
BugData = namedtuple("BugData", ['owner', 'distro', 'distro_release',
@@ -1476,7 +1479,7 @@
bug = self.factory.makeBug()
login_celebrity('admin')
self.assertTrue(
- check_permission('launchpad.Admin', bug.default_bugtask))
+ check_permission('launchpad.Delete', bug.default_bugtask))
def test_pillar_owner_can_delete(self):
# With the feature flag on, the pillar owner can delete a bug task.
@@ -1508,6 +1511,18 @@
login_person(bugtask.owner)
self.assertRaises(CannotDeleteBugtask, bugtask.delete)
+ def test_canBeDeleted_is_free(self):
+ # BugTask.canBeDeleted uses cached data, so repeated execution
+ # on a single bug is free.
+ bug = self.factory.makeBug()
+ task1 = self.factory.makeBugTask(bug=bug)
+ task2 = self.factory.makeBugTask(bug=bug)
+ self.assertEqual(True, bug.default_bugtask.canBeDeleted())
+ with StormStatementRecorder() as recorder:
+ self.assertEqual(True, task1.canBeDeleted())
+ self.assertEqual(True, task2.canBeDeleted())
+ self.assertThat(recorder, HasQueryCount(Equals(0)))
+
def test_delete_bugtask(self):
# A bugtask can be deleted and after deletion, re-nominated.
owner = self.factory.makePerson()
Follow ups