Merge lp:~wgrant/launchpad/bugtaskflat-garbo into lp:launchpad

Proposed by William Grant
Status: Merged
Approved by: William Grant
Approved revision: no longer in the source branch.
Merged at revision: 15055
Proposed branch: lp:~wgrant/launchpad/bugtaskflat-garbo
Merge into: lp:launchpad
Prerequisite: lp:launchpad/db-devel
Diff against target: 116 lines (+67/-0)
2 files modified
lib/lp/scripts/garbo.py (+37/-0)
lib/lp/scripts/tests/test_garbo.py (+30/-0)
To merge this branch: bzr merge lp:~wgrant/launchpad/bugtaskflat-garbo
Reviewer Review Type Date Requested Status
Steve Kowalik (community) code Approve
Review via email: mp+100363@code.launchpad.net

Commit message

Add a garbo job to populate BugTaskFlat.

Description of the change

BugTaskFlat will soon exist on production, but it needs to be populated. This is a garbo job to do that, pretty much the same as the bug legacy access mirrorer that I removed a couple of weeks back.

To post a comment you must log in.
Revision history for this message
Steve Kowalik (stevenk) wrote :

Looks good.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/scripts/garbo.py'
--- lib/lp/scripts/garbo.py 2012-03-26 22:47:47 +0000
+++ lib/lp/scripts/garbo.py 2012-04-02 07:16:34 +0000
@@ -44,6 +44,7 @@
44from lp.bugs.model.bug import Bug44from lp.bugs.model.bug import Bug
45from lp.bugs.model.bugattachment import BugAttachment45from lp.bugs.model.bugattachment import BugAttachment
46from lp.bugs.model.bugnotification import BugNotification46from lp.bugs.model.bugnotification import BugNotification
47from lp.bugs.model.bugtask import BugTask
47from lp.bugs.model.bugwatch import BugWatchActivity48from lp.bugs.model.bugwatch import BugWatchActivity
48from lp.bugs.scripts.checkwatches.scheduler import (49from lp.bugs.scripts.checkwatches.scheduler import (
49 BugWatchScheduler,50 BugWatchScheduler,
@@ -81,6 +82,7 @@
81from lp.services.librarian.model import TimeLimitedToken82from lp.services.librarian.model import TimeLimitedToken
82from lp.services.log.logger import PrefixFilter83from lp.services.log.logger import PrefixFilter
83from lp.services.looptuner import TunableLoop84from lp.services.looptuner import TunableLoop
85from lp.services.memcache.interfaces import IMemcacheClient
84from lp.services.oauth.model import OAuthNonce86from lp.services.oauth.model import OAuthNonce
85from lp.services.openid.model.openidconsumer import OpenIDConsumerNonce87from lp.services.openid.model.openidconsumer import OpenIDConsumerNonce
86from lp.services.propertycache import cachedproperty88from lp.services.propertycache import cachedproperty
@@ -1091,6 +1093,40 @@
1091 self.offset += chunk_size1093 self.offset += chunk_size
10921094
10931095
1096class BugTaskFlattener(TunableLoop):
1097 """A `TunableLoop` to populate BugTaskFlat for all bugtasks."""
1098
1099 maximum_chunk_size = 5000
1100
1101 def __init__(self, log, abort_time=None):
1102 super(BugTaskFlattener, self).__init__(log, abort_time)
1103 watermark = getUtility(IMemcacheClient).get(
1104 '%s:bugtask-flattener' % config.instance_name)
1105 self.start_at = watermark or 0
1106
1107 def findTaskIDs(self):
1108 return IMasterStore(BugTask).find(
1109 (BugTask.id,), BugTask.id >= self.start_at).order_by(BugTask.id)
1110
1111 def isDone(self):
1112 return self.findTaskIDs().is_empty()
1113
1114 def __call__(self, chunk_size):
1115 ids = [row[0] for row in self.findTaskIDs()[:chunk_size]]
1116 list(IMasterStore(BugTask).using(BugTask).find(
1117 SQL('bugtask_flatten(BugTask.id, false)'),
1118 BugTask.id.is_in(ids)))
1119
1120 self.start_at = ids[-1] + 1
1121 result = getUtility(IMemcacheClient).set(
1122 '%s:bugtask-flattener' % config.instance_name,
1123 self.start_at)
1124 if not result:
1125 self.log.warning('Failed to set start_at in memcache.')
1126
1127 transaction.commit()
1128
1129
1094class BaseDatabaseGarbageCollector(LaunchpadCronScript):1130class BaseDatabaseGarbageCollector(LaunchpadCronScript):
1095 """Abstract base class to run a collection of TunableLoops."""1131 """Abstract base class to run a collection of TunableLoops."""
1096 script_name = None # Script name for locking and database user. Override.1132 script_name = None # Script name for locking and database user. Override.
@@ -1342,6 +1378,7 @@
1342 UnusedSessionPruner,1378 UnusedSessionPruner,
1343 DuplicateSessionPruner,1379 DuplicateSessionPruner,
1344 BugHeatUpdater,1380 BugHeatUpdater,
1381 BugTaskFlattener,
1345 ]1382 ]
1346 experimental_tunable_loops = []1383 experimental_tunable_loops = []
13471384
13481385
=== modified file 'lib/lp/scripts/tests/test_garbo.py'
--- lib/lp/scripts/tests/test_garbo.py 2012-03-26 22:47:47 +0000
+++ lib/lp/scripts/tests/test_garbo.py 2012-04-02 07:16:34 +0000
@@ -42,6 +42,7 @@
42 BugNotification,42 BugNotification,
43 BugNotificationRecipient,43 BugNotificationRecipient,
44 )44 )
45from lp.bugs.model.bugtask import BugTask
45from lp.code.bzr import (46from lp.code.bzr import (
46 BranchFormat,47 BranchFormat,
47 RepositoryFormat,48 RepositoryFormat,
@@ -1104,6 +1105,35 @@
1104 self.assertEqual(whiteboard, spec.whiteboard)1105 self.assertEqual(whiteboard, spec.whiteboard)
1105 self.assertEqual(0, spec.work_items.count())1106 self.assertEqual(0, spec.work_items.count())
11061107
1108 def test_BugTaskFlattener(self):
1109 # Private bugs without corresponding data in the access policy
1110 # schema get mirrored.
1111 switch_dbuser('testadmin')
1112 task = self.factory.makeBugTask()
1113 # Remove the existing mirrored data.
1114 IMasterStore(BugTask).execute(
1115 'DELETE FROM BugTaskFlat WHERE bugtask = ?', (task.id,))
1116 transaction.commit()
1117 self.runHourly()
1118 # Check that there's a record again, and delete it.
1119 switch_dbuser('testadmin')
1120 self.assertEqual(
1121 (task.id,),
1122 IMasterStore(BugTask).execute(
1123 'SELECT bugtask FROM BugTaskFlat WHERE bugtask = ?',
1124 (task.id,)).get_one())
1125 IMasterStore(BugTask).execute(
1126 'DELETE FROM BugTaskFlat WHERE bugtask = ?', (task.id,))
1127 transaction.commit()
1128 self.runHourly()
1129 # A watermark is kept in memcache, so a second run doesn't
1130 # consider the same task.
1131 self.assertIs(
1132 None,
1133 IMasterStore(BugTask).execute(
1134 'SELECT bugtask FROM BugTaskFlat WHERE bugtask = ?',
1135 (task.id,)).get_one())
1136
11071137
1108class TestGarboTasks(TestCaseWithFactory):1138class TestGarboTasks(TestCaseWithFactory):
1109 layer = LaunchpadZopelessLayer1139 layer = LaunchpadZopelessLayer