[ZODB-Dev] problems w/ Pickle based deep-copy of Blob objects
Rob Miller
ra at burningman.com
Wed Sep 10 14:37:14 EDT 2008
i'm assuming from the lack of response that nobody has a problem w/ this
change... if i don't hear differently within the next 24 hours or so, i'll
commit the change to the 3.8 branch and the trunk.
here's the patch:
Index: src/ZODB/blob.py
===================================================================
--- src/ZODB/blob.py (revision 91033)
+++ src/ZODB/blob.py (working copy)
@@ -93,7 +93,7 @@
# XXX should we warn of this? Maybe?
if self._p_changed is None:
return
- for ref in self.readers+self.writers:
+ for ref in (self.readers or [])+(self.writers or []):
f = ref()
if f is not None:
f.close()
-r
Rob Miller wrote:
> hi all,
>
> i've been experimenting w/ getting ZODB 3.8's blob storage support to work w/
> the openplans.org stack, and have hit a snag about which i could use some
> feedback.
>
> the problem is that CMFEditions, which we use to version our content, uses
> Pickler.dump() and Unpickler.load() to create deep copies of objects, which
> then get stored as historical versions of those objects. the heart of the
> issue is probably best illustrated by an interactive session:
>
> >>> blob
> <ZODB.blob.Blob object at 0xa0c1230>
> >>> blob.readers
> []
> >>> blob.writers
> []
> >>> stream = StringIO()
> >>> p = Pickler(stream, 1)
> >>> p.dump(blob)
> <cPickle.Pickler object at 0x9fb9cc8>
> >>> u = Unpickler(stream)
> >>> stream.seek(0)
> >>> copy = u.load()
> >>> copy
> <ZODB.blob.Blob object at 0xa0c12a8>
> >>> copy.readers
> >>> copy.writers
>
> 'readers' and 'writers' are defined as None on the Blob class, but they get
> initialized as empty list instance variables by the __init__ and __setstate__
> methods. neither of these are triggered by the deep copy process, however,
> and apparently the __getstate__ and __setstate__ implementations prevent these
> instance variables from propagating to the pickled copy.
>
> this seems okay, at first, but if anything is done w/ the transaction that
> triggers the copy's _p_invalidate method to be called, it blows up with a
> TypeError on the following:
>
> for ref in self.readers+self.writers:
>
> the problem seems to go away w/ a simple change:
>
> for ref in (self.readers or []) + (self.writers or []):
>
> this seems safe to me; it's not actually changing the state of any objects,
> and it's only going to have an impact when an object w/ no readers and writers
> is trying to be invalidated. but i don't know enough about what's going on
> here to feel confident that this is the right solution, that i'm not
> introducing some subtle ZODB bug that's going to bite me (or someone else)
> down the road.
>
> can anyone tell me whether or not this seems safe? if this isn't the right
> approach, what would you suggest? (my second guess would be to fix the
> __getstate__ and __setstate__ implementation so that these instance variables
> make it through the pickling process in the first place...)
>
> any help very appreciated, thanks!
>
> -r
More information about the ZODB-Dev
mailing list