Merge lp:~jcsackett/launchpad/i-hate-storm-base-storm-705197 into lp:launchpad

Proposed by j.c.sackett
Status: Merged
Approved by: Aaron Bentley
Approved revision: no longer in the source branch.
Merged at revision: 12262
Proposed branch: lp:~jcsackett/launchpad/i-hate-storm-base-storm-705197
Merge into: lp:launchpad
Diff against target: 523 lines (+88/-63)
16 files modified
lib/canonical/launchpad/database/librarian.py (+2/-2)
lib/lp/bugs/model/apportjob.py (+6/-10)
lib/lp/bugs/model/bugjob.py (+5/-6)
lib/lp/bugs/model/bugsubscription.py (+4/-4)
lib/lp/bugs/model/bugsubscriptionfilter.py (+4/-4)
lib/lp/bugs/model/bugsubscriptionfilterimportance.py (+4/-4)
lib/lp/bugs/model/bugsubscriptionfilterstatus.py (+4/-4)
lib/lp/bugs/model/bugsubscriptionfiltertag.py (+4/-3)
lib/lp/bugs/model/bugtracker.py (+3/-3)
lib/lp/bugs/model/bugwatch.py (+2/-2)
lib/lp/code/model/branchmergeproposaljob.py (+4/-5)
lib/lp/registry/model/nameblacklist.py (+4/-4)
lib/lp/registry/model/persontransferjob.py (+4/-5)
lib/lp/services/database/stormbase.py (+31/-0)
lib/lp/soyuz/model/archivejob.py (+3/-3)
lib/lp/soyuz/model/distributionjob.py (+4/-4)
To merge this branch: bzr merge lp:~jcsackett/launchpad/i-hate-storm-base-storm-705197
Reviewer Review Type Date Requested Status
Aaron Bentley (community) Approve
Review via email: mp+47269@code.launchpad.net

Commit message

[r=abentley][ui=none][bug=705197] Replaces use of storm.base.Storm with a new class, Stormbase, which descends from base.Storm but adds SQLObject's __storm methods.

Description of the change

Summary
=======

Several models uses storm.base.Storm as their parent class. These classes end up introducing cache errors as they don't have the necessary storm hooks to clear/invalidate caches (as other classes e.g. SQLBase do).

This branch introduces a new class, descended from storm.base.Storm, that adds the same storm hook functionality as in SQLBase.

Preimplementation
=================

Spoke with Robert Collins, Curtis Hovey, and William Grant about what exactly was needed.

Proposed Fix
============

Create a new class, StormBase, that descends from storm.base.Storm and adds the hooks needed (borrowed from SQLBase).

Implementation
==============

lib/lp/service/database/stormbase.py
------------------------------------

Adds the new StormBase class.

All other files
---------------

Updates uses of storm.base.Storm to lp.services.database.StormBase

Tests
=====

Basically you have to run ec2. You can try:

bin/test -m lp.bugs
bin/test -m lp.codehosting
bin/test -m lp.registry

But that's not guaranteed to test all areas changed. I've had to ec2 test to track down any breaks.

Demo & QA
=========

Not terribly qa-able. Make sure bugtracking and bugtasks work--they were heaviest effected. But honestly, if this weren't working, lp.dev will just crash all over the place.

Lint
====

= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:

lib/canonical/launchpad/database/librarian.py
lib/lp/bugs/model/apportjob.py
lib/lp/bugs/model/bugjob.py
lib/lp/bugs/model/bugsubscription.py
lib/lp/bugs/model/bugsubscriptionfilter.py lib/lp/bugs/model/bugsubscriptionfilterimportance.py lib/lp/bugs/model/bugsubscriptionfilterstatus.py lib/lp/bugs/model/bugsubscriptionfiltertag.py
lib/lp/bugs/model/bugtracker.py
lib/lp/bugs/model/bugwatch.py
lib/lp/code/model/branchmergeproposaljob.py
lib/lp/registry/model/nameblacklist.py
lib/lp/registry/model/persontransferjob.py
lib/lp/services/database/stormbase.py
lib/lp/soyuz/model/archivejob.py
lib/lp/soyuz/model/distributionjob.py

./lib/lp/bugs/model/apportjob.py
      35: 'ITemporaryStorageManager' imported but unused
     163: E222 multiple spaces after operator
     210: E202 whitespace before ')'
./lib/lp/bugs/model/bugjob.py
      26: 'removeSecurityProxy' imported but unused
     142: E222 multiple spaces after operator./lib/lp/bugs/model/bugsubscriptionfiltertag.py
      18: E302 expected 2 blank lines, found 1
./lib/lp/code/model/branchmergeproposaljob.py
       5: E303 too many blank lines (3)
     289: E202 whitespace before ')'
./lib/lp/registry/model/persontransferjob.py
      14: 'SQLObjectNotFound' imported but unused
./lib/lp/soyuz/model/archivejob.py
     136: E222 multiple spaces after operator

I'm going to fix lint after review; the diff has a lot of little one-off lines as it is, and I didn't want to clutter it up.

To post a comment you must log in.
Revision history for this message
Aaron Bentley (abentley) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/database/librarian.py'
2--- lib/canonical/launchpad/database/librarian.py 2010-12-20 17:42:47 +0000
3+++ lib/canonical/launchpad/database/librarian.py 2011-01-24 20:15:33 +0000
4@@ -30,7 +30,6 @@
5 SQLRelatedJoin,
6 StringCol,
7 )
8-import storm.base
9 from storm.locals import (
10 Date,
11 Desc,
12@@ -71,6 +70,7 @@
13 IRestrictedLibrarianClient,
14 LIBRARIAN_SERVER_DEFAULT_TIMEOUT,
15 )
16+from lp.services.database.stormbase import StormBase
17
18
19 class LibraryFileContent(SQLBase):
20@@ -305,7 +305,7 @@
21 country = Reference(country_id, 'Country.id')
22
23
24-class TimeLimitedToken(storm.base.Storm):
25+class TimeLimitedToken(StormBase):
26 """A time limited access token for accessing a private file."""
27
28 __storm_table__ = 'TimeLimitedToken'
29
30=== modified file 'lib/lp/bugs/model/apportjob.py'
31--- lib/lp/bugs/model/apportjob.py 2010-08-20 20:31:18 +0000
32+++ lib/lp/bugs/model/apportjob.py 2011-01-24 20:15:33 +0000
33@@ -14,7 +14,6 @@
34 from lazr.delegates import delegates
35 import simplejson
36 from sqlobject import SQLObjectNotFound
37-from storm.base import Storm
38 from storm.expr import And
39 from storm.locals import (
40 Int,
41@@ -33,9 +32,6 @@
42 )
43 from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet
44 from canonical.launchpad.interfaces.lpstorm import IStore
45-from canonical.launchpad.interfaces.temporaryblobstorage import (
46- ITemporaryStorageManager,
47- )
48 from canonical.launchpad.webapp.interfaces import (
49 DEFAULT_FLAVOR,
50 IStoreSelector,
51@@ -54,9 +50,10 @@
52 )
53 from lp.services.job.model.job import Job
54 from lp.services.job.runner import BaseRunnableJob
55-
56-
57-class ApportJob(Storm):
58+from lp.services.database.stormbase import StormBase
59+
60+
61+class ApportJob(StormBase):
62 """Base class for jobs related to Apport BLOBs."""
63
64 implements(IApportJob)
65@@ -160,7 +157,7 @@
66
67 def getOopsVars(self):
68 """See `IRunnableJob`."""
69- vars = BaseRunnableJob.getOopsVars(self)
70+ vars = BaseRunnableJob.getOopsVars(self)
71 vars.extend([
72 ('apport_blob_uuid', self.context.blob.uuid),
73 ('apport_blob_librarian_url',
74@@ -207,8 +204,7 @@
75 ApportJob.job == Job.id,
76 ApportJob.job_type == cls.class_job_type,
77 ApportJob.blob_id == TemporaryBlobStorage.id,
78- TemporaryBlobStorage.uuid == uuid
79- )
80+ TemporaryBlobStorage.uuid == uuid)
81
82 job_for_blob = jobs_for_blob.one()
83
84
85=== modified file 'lib/lp/bugs/model/bugjob.py'
86--- lib/lp/bugs/model/bugjob.py 2010-08-20 20:31:18 +0000
87+++ lib/lp/bugs/model/bugjob.py 2011-01-24 20:15:33 +0000
88@@ -12,7 +12,6 @@
89 from lazr.delegates import delegates
90 import simplejson
91 from sqlobject import SQLObjectNotFound
92-from storm.base import Storm
93 from storm.expr import And
94 from storm.locals import (
95 Int,
96@@ -24,7 +23,6 @@
97 classProvides,
98 implements,
99 )
100-from zope.security.proxy import removeSecurityProxy
101
102 from canonical.database.enumcol import EnumCol
103 from canonical.launchpad.webapp.interfaces import (
104@@ -41,9 +39,10 @@
105 from lp.bugs.model.bug import Bug
106 from lp.services.job.model.job import Job
107 from lp.services.job.runner import BaseRunnableJob
108-
109-
110-class BugJob(Storm):
111+from lp.services.database.stormbase import StormBase
112+
113+
114+class BugJob(StormBase):
115 """Base class for jobs related to Bugs."""
116
117 implements(IBugJob)
118@@ -139,7 +138,7 @@
119
120 def getOopsVars(self):
121 """See `IRunnableJob`."""
122- vars = BaseRunnableJob.getOopsVars(self)
123+ vars = BaseRunnableJob.getOopsVars(self)
124 vars.extend([
125 ('bug_id', self.context.bug.id),
126 ('bug_job_id', self.context.id),
127
128=== modified file 'lib/lp/bugs/model/bugsubscription.py'
129--- lib/lp/bugs/model/bugsubscription.py 2010-10-14 20:49:34 +0000
130+++ lib/lp/bugs/model/bugsubscription.py 2011-01-24 20:15:33 +0000
131@@ -7,7 +7,6 @@
132 __all__ = ['BugSubscription']
133
134 import pytz
135-from storm.base import Storm
136 from storm.locals import (
137 DateTime,
138 Int,
139@@ -20,9 +19,10 @@
140 from lp.bugs.interfaces.bugsubscription import IBugSubscription
141 from lp.registry.enum import BugNotificationLevel
142 from lp.registry.interfaces.person import validate_person
143-
144-
145-class BugSubscription(Storm):
146+from lp.services.database.stormbase import StormBase
147+
148+
149+class BugSubscription(StormBase):
150 """A relationship between a person and a bug."""
151
152 implements(IBugSubscription)
153
154=== modified file 'lib/lp/bugs/model/bugsubscriptionfilter.py'
155--- lib/lp/bugs/model/bugsubscriptionfilter.py 2010-10-04 13:31:12 +0000
156+++ lib/lp/bugs/model/bugsubscriptionfilter.py 2011-01-24 20:15:33 +0000
157@@ -8,7 +8,6 @@
158
159 from itertools import chain
160
161-from storm.base import Storm
162 from storm.locals import (
163 Bool,
164 Int,
165@@ -28,9 +27,10 @@
166 BugSubscriptionFilterStatus,
167 )
168 from lp.bugs.model.bugsubscriptionfiltertag import BugSubscriptionFilterTag
169-
170-
171-class BugSubscriptionFilter(Storm):
172+from lp.services.database.stormbase import StormBase
173+
174+
175+class BugSubscriptionFilter(StormBase):
176 """A filter to specialize a *structural* subscription."""
177
178 implements(IBugSubscriptionFilter)
179
180=== modified file 'lib/lp/bugs/model/bugsubscriptionfilterimportance.py'
181--- lib/lp/bugs/model/bugsubscriptionfilterimportance.py 2010-09-17 11:14:25 +0000
182+++ lib/lp/bugs/model/bugsubscriptionfilterimportance.py 2011-01-24 20:15:33 +0000
183@@ -6,7 +6,6 @@
184 __metaclass__ = type
185 __all__ = ['BugSubscriptionFilterImportance']
186
187-from storm.base import Storm
188 from storm.locals import (
189 Int,
190 Reference,
191@@ -14,9 +13,10 @@
192
193 from canonical.database.enumcol import DBEnum
194 from lp.bugs.interfaces.bugtask import BugTaskImportance
195-
196-
197-class BugSubscriptionFilterImportance(Storm):
198+from lp.services.database.stormbase import StormBase
199+
200+
201+class BugSubscriptionFilterImportance(StormBase):
202 """Importances to filter."""
203
204 __storm_table__ = "BugSubscriptionFilterImportance"
205
206=== modified file 'lib/lp/bugs/model/bugsubscriptionfilterstatus.py'
207--- lib/lp/bugs/model/bugsubscriptionfilterstatus.py 2010-09-17 11:14:25 +0000
208+++ lib/lp/bugs/model/bugsubscriptionfilterstatus.py 2011-01-24 20:15:33 +0000
209@@ -6,7 +6,6 @@
210 __metaclass__ = type
211 __all__ = ['BugSubscriptionFilterStatus']
212
213-from storm.base import Storm
214 from storm.locals import (
215 Int,
216 Reference,
217@@ -14,9 +13,10 @@
218
219 from canonical.database.enumcol import DBEnum
220 from lp.bugs.interfaces.bugtask import BugTaskStatus
221-
222-
223-class BugSubscriptionFilterStatus(Storm):
224+from lp.services.database.stormbase import StormBase
225+
226+
227+class BugSubscriptionFilterStatus(StormBase):
228 """Statuses to filter."""
229
230 __storm_table__ = "BugSubscriptionFilterStatus"
231
232=== modified file 'lib/lp/bugs/model/bugsubscriptionfiltertag.py'
233--- lib/lp/bugs/model/bugsubscriptionfiltertag.py 2010-10-01 11:06:05 +0000
234+++ lib/lp/bugs/model/bugsubscriptionfiltertag.py 2011-01-24 20:15:33 +0000
235@@ -6,7 +6,6 @@
236 __metaclass__ = type
237 __all__ = ['BugSubscriptionFilterTag']
238
239-from storm.base import Storm
240 from storm.locals import (
241 Bool,
242 Int,
243@@ -14,8 +13,10 @@
244 Unicode,
245 )
246
247-
248-class BugSubscriptionFilterTag(Storm):
249+from lp.services.database.stormbase import StormBase
250+
251+
252+class BugSubscriptionFilterTag(StormBase):
253 """Tags to filter."""
254
255 __storm_table__ = "BugSubscriptionFilterTag"
256
257=== modified file 'lib/lp/bugs/model/bugtracker.py'
258--- lib/lp/bugs/model/bugtracker.py 2010-11-04 02:32:16 +0000
259+++ lib/lp/bugs/model/bugtracker.py 2011-01-24 20:15:33 +0000
260@@ -24,7 +24,6 @@
261 splittype,
262 )
263
264-from storm.base import Storm
265 from storm.locals import (
266 Int,
267 Reference,
268@@ -86,6 +85,7 @@
269 IPersonSet,
270 validate_public_person,
271 )
272+from lp.services.database.stormbase import StormBase
273
274
275 def normalise_leading_slashes(rest):
276@@ -175,7 +175,7 @@
277 return base_uri.host + base_uri.path
278
279
280-class BugTrackerComponent(Storm):
281+class BugTrackerComponent(StormBase):
282 """The software component in the remote bug tracker.
283
284 Most bug trackers organize bug reports by the software 'component'
285@@ -229,7 +229,7 @@
286 """The distribution's source package for this component""")
287
288
289-class BugTrackerComponentGroup(Storm):
290+class BugTrackerComponentGroup(StormBase):
291 """A collection of components in a remote bug tracker.
292
293 Some bug trackers organize sets of components into higher level
294
295=== modified file 'lib/lp/bugs/model/bugwatch.py'
296--- lib/lp/bugs/model/bugwatch.py 2010-11-05 13:46:55 +0000
297+++ lib/lp/bugs/model/bugwatch.py 2011-01-24 20:15:33 +0000
298@@ -26,7 +26,6 @@
299 SQLObjectNotFound,
300 StringCol,
301 )
302-from storm.base import Storm
303 from storm.expr import (
304 Desc,
305 Not,
306@@ -79,6 +78,7 @@
307 from lp.bugs.model.bugset import BugSetBase
308 from lp.bugs.model.bugtask import BugTask
309 from lp.registry.interfaces.person import validate_public_person
310+from lp.services.database.stormbase import StormBase
311
312
313 BUG_TRACKER_URL_FORMATS = {
314@@ -751,7 +751,7 @@
315 result, message, oops_id, bug_watch_ids))
316
317
318-class BugWatchActivity(Storm):
319+class BugWatchActivity(StormBase):
320 """See `IBugWatchActivity`."""
321
322 implements(IBugWatchActivity)
323
324=== modified file 'lib/lp/code/model/branchmergeproposaljob.py'
325--- lib/lp/code/model/branchmergeproposaljob.py 2010-10-29 14:03:31 +0000
326+++ lib/lp/code/model/branchmergeproposaljob.py 2011-01-24 20:15:33 +0000
327@@ -42,7 +42,6 @@
328 import pytz
329 import simplejson
330 from sqlobject import SQLObjectNotFound
331-from storm.base import Storm
332 from storm.expr import (
333 And,
334 Desc,
335@@ -111,6 +110,7 @@
336 from lp.services.job.model.job import Job
337 from lp.services.job.runner import BaseRunnableJob
338 from lp.services.mail.sendmail import format_address_for_person
339+from lp.services.database.stormbase import StormBase
340
341
342 class BranchMergeProposalJobType(DBEnumeratedType):
343@@ -155,7 +155,7 @@
344 This job generates an incremental diff for a merge proposal.""")
345
346
347-class BranchMergeProposalJob(Storm):
348+class BranchMergeProposalJob(StormBase):
349 """Base class for jobs related to branch merge proposals."""
350
351 implements(IBranchMergeProposalJob)
352@@ -187,7 +187,7 @@
353 :param metadata: The type-specific variables, as a JSON-compatible
354 dict.
355 """
356- Storm.__init__(self)
357+ super(BranchMergeProposalJob, self).__init__()
358 json_data = simplejson.dumps(metadata)
359 self.job = Job()
360 self.branch_merge_proposal = branch_merge_proposal
361@@ -286,8 +286,7 @@
362 # or if it is hosted but pending a mirror.
363 Branch.revision_count > 0,
364 Or(Branch.next_mirror_time == None,
365- Branch.branch_type != BranchType.HOSTED)
366- ))
367+ Branch.branch_type != BranchType.HOSTED)))
368 return (klass(job) for job in jobs)
369
370 def getOopsVars(self):
371
372=== modified file 'lib/lp/registry/model/nameblacklist.py'
373--- lib/lp/registry/model/nameblacklist.py 2010-11-11 16:06:24 +0000
374+++ lib/lp/registry/model/nameblacklist.py 2011-01-24 20:15:33 +0000
375@@ -10,7 +10,6 @@
376 ]
377
378
379-from storm.base import Storm
380 from storm.locals import (
381 Int,
382 Unicode,
383@@ -22,9 +21,10 @@
384 INameBlacklist,
385 INameBlacklistSet,
386 )
387-
388-
389-class NameBlacklist(Storm):
390+from lp.services.database.stormbase import StormBase
391+
392+
393+class NameBlacklist(StormBase):
394 """Class for the NameBlacklist table."""
395
396 implements(INameBlacklist)
397
398=== modified file 'lib/lp/registry/model/persontransferjob.py'
399--- lib/lp/registry/model/persontransferjob.py 2010-09-30 21:29:11 +0000
400+++ lib/lp/registry/model/persontransferjob.py 2011-01-24 20:15:33 +0000
401@@ -11,8 +11,6 @@
402
403 from lazr.delegates import delegates
404 import simplejson
405-from sqlobject import SQLObjectNotFound
406-from storm.base import Storm
407 from storm.expr import And
408 from storm.locals import (
409 Int,
410@@ -54,9 +52,10 @@
411 from lp.registry.model.person import Person
412 from lp.services.job.model.job import Job
413 from lp.services.job.runner import BaseRunnableJob
414-
415-
416-class PersonTransferJob(Storm):
417+from lp.services.database.stormbase import StormBase
418+
419+
420+class PersonTransferJob(StormBase):
421 """Base class for team membership and person merge jobs."""
422
423 implements(IPersonTransferJob)
424
425=== added file 'lib/lp/services/database/stormbase.py'
426--- lib/lp/services/database/stormbase.py 1970-01-01 00:00:00 +0000
427+++ lib/lp/services/database/stormbase.py 2011-01-24 20:15:33 +0000
428@@ -0,0 +1,31 @@
429+# Copyright 2011 Canonical Ltd. This software is licensed under the
430+# GNU Affero General Public License version 3 (see the file LICENSE).
431+
432+__metaclass__ = type
433+__all__ = [
434+ 'StormBase',
435+ ]
436+
437+from lazr.restful.interfaces import IRepresentationCache
438+from storm.base import Storm
439+from zope.component import getUtility
440+
441+from lp.services.propertycache import clear_property_cache
442+
443+
444+class StormBase(Storm):
445+ """A safe version of storm.base.Storm to use in launchpad.
446+
447+ This class adds storm cache management functions to base.Storm.
448+ """
449+
450+ # XXX: jcsackett 2011-01-20 bug=622648: Much as with the SQLBase,
451+ # this is not tested.
452+ def __storm_flushed__(self):
453+ """Invalidate the web service cache."""
454+ cache = getUtility(IRepresentationCache)
455+ cache.delete(self)
456+
457+ def __storm_invalidated__(self):
458+ """Flush cached properties."""
459+ clear_property_cache(self)
460
461=== modified file 'lib/lp/soyuz/model/archivejob.py'
462--- lib/lp/soyuz/model/archivejob.py 2010-08-23 17:01:11 +0000
463+++ lib/lp/soyuz/model/archivejob.py 2011-01-24 20:15:33 +0000
464@@ -6,7 +6,6 @@
465 from lazr.delegates import delegates
466 import simplejson
467 from sqlobject import SQLObjectNotFound
468-from storm.base import Storm
469 from storm.expr import And
470 from storm.locals import (
471 Int,
472@@ -28,6 +27,7 @@
473 )
474 from lp.services.job.model.job import Job
475 from lp.services.job.runner import BaseRunnableJob
476+from lp.services.database.stormbase import StormBase
477 from lp.soyuz.enums import ArchiveJobType
478 from lp.soyuz.interfaces.archivejob import (
479 IArchiveJob,
480@@ -36,7 +36,7 @@
481 from lp.soyuz.model.archive import Archive
482
483
484-class ArchiveJob(Storm):
485+class ArchiveJob(StormBase):
486 """Base class for jobs related to Archives."""
487
488 implements(IArchiveJob)
489@@ -133,7 +133,7 @@
490
491 def getOopsVars(self):
492 """See `IRunnableJob`."""
493- vars = BaseRunnableJob.getOopsVars(self)
494+ vars = BaseRunnableJob.getOopsVars(self)
495 vars.extend([
496 ('archive_id', self.context.archive.id),
497 ('archive_job_id', self.context.id),
498
499=== modified file 'lib/lp/soyuz/model/distributionjob.py'
500--- lib/lp/soyuz/model/distributionjob.py 2010-09-16 01:38:42 +0000
501+++ lib/lp/soyuz/model/distributionjob.py 2011-01-24 20:15:33 +0000
502@@ -10,7 +10,6 @@
503
504 import simplejson
505
506-from storm.base import Storm
507 from storm.locals import And, Int, Reference, Unicode
508
509 from zope.interface import implements
510@@ -29,9 +28,10 @@
511 )
512 from lp.services.job.model.job import Job
513 from lp.services.job.runner import BaseRunnableJob
514-
515-
516-class DistributionJob(Storm):
517+from lp.services.database.stormbase import StormBase
518+
519+
520+class DistributionJob(StormBase):
521 """Base class for jobs related to Distributions."""
522
523 implements(IDistributionJob)