[ZODB-Dev] Old transaction records with bad pickle data preventing packing

2010-06-14 Thread Jens Vagelpohl
Hi all,

In a system using Zope 2.11 and ZODB 3.7.0b3 I'm having a problem with
old transaction records containing pickle data that fails on
cPickle.Unpickler.noload as employed by ZODB.serialize.referencesf, I
get an AttributeError from inside the cPickle module:

def referencesf(p, oids=None):
Return a list of object ids found in a pickle

A list may be passed in, in which case, information is
appended to it.

Weak references are not included.


refs = []
u = cPickle.Unpickler(cStringIO.StringIO(p))
u.persistent_load = refs
u.noload()
u.noload()

# Now we have a list of referencs.  Need to convert to list of
# oids:
snip

The noload failure means I cannot pack the database right now. Since
only historical transactions contain the problematic attribute and I
don't care about those anymore I have introduced a simple change locally
that ignores the failure:

def referencesf(p, oids=None):
Return a list of object ids found in a pickle

A list may be passed in, in which case, information is
appended to it.

Weak references are not included.


refs = []
u = cPickle.Unpickler(cStringIO.StringIO(p))
u.persistent_load = refs
try:
u.noload()
u.noload()
except AttributeError:
pass

# Now we have a list of referencs.  Need to convert to list of
# oids:
snip

With this change I can pack the database and a few simple check
(fsrefs.py etc) indicate the database is consistent after the pack.

My question: Is there any risk associated with ignoring the failure
during packing? The latest object versions for the persistent objects in
question do not have the problematic attribute anymore, so the latest
records are safe and will not cause the AttributeError, anyway.

jens

___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

ZODB-Dev mailing list  -  ZODB-Dev@zope.org
https://mail.zope.org/mailman/listinfo/zodb-dev


Re: [ZODB-Dev] Old transaction records with bad pickle data preventing packing

2010-06-14 Thread Shane Hathaway
On 06/14/2010 01:43 AM, Jens Vagelpohl wrote:
 My question: Is there any risk associated with ignoring the failure
 during packing? The latest object versions for the persistent objects in
 question do not have the problematic attribute anymore, so the latest
 records are safe and will not cause the AttributeError, anyway.

In the general case, a failure to unpickle could be caused by some 
temporary condition, so we can't ignore it.  For example, a broken 
__setstate__ method could be involved.  Ignoring unpickling errors could 
cause the pack to not discover all references and possibly delete more 
objects than it should.

In your case, you have already determined that this specific pickle is 
permanently broken, so the references from it don't matter and packing 
is probably safe.  However, can you be certain that the rest of your 
database is free of temporarily broken pickles?  If I were you, I would 
add some logging to ensure the exception handler is triggered only once, 
pack, and then revert the ZODB code change.

Shane
___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

ZODB-Dev mailing list  -  ZODB-Dev@zope.org
https://mail.zope.org/mailman/listinfo/zodb-dev


Re: [ZODB-Dev] Old transaction records with bad pickle data preventing packing

2010-06-14 Thread Jens Vagelpohl
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

On 6/14/10 10:19 , Shane Hathaway wrote:
 On 06/14/2010 01:43 AM, Jens Vagelpohl wrote:
 My question: Is there any risk associated with ignoring the failure
 during packing? The latest object versions for the persistent objects in
 question do not have the problematic attribute anymore, so the latest
 records are safe and will not cause the AttributeError, anyway.
 
 In the general case, a failure to unpickle could be caused by some
 temporary condition, so we can't ignore it.  For example, a broken
 __setstate__ method could be involved.  Ignoring unpickling errors could
 cause the pack to not discover all references and possibly delete more
 objects than it should.
 
 In your case, you have already determined that this specific pickle is
 permanently broken, so the references from it don't matter and packing
 is probably safe.  However, can you be certain that the rest of your
 database is free of temporarily broken pickles?  If I were you, I would
 add some logging to ensure the exception handler is triggered only once,
 pack, and then revert the ZODB code change.

Hi Shane,

The exception handler is triggered once for every broken pickle, I'm
guessing that's what you mean by once. The broken pickle represents a
very simple persistent object that does not have any further persistent
subobjects itself, and even its absence won't break the application. The
plan was indeed to patch the code just for packing and then restart
without the change.

jens
-BEGIN PGP SIGNATURE-
Version: GnuPG v1.4.8 (Darwin)

iEYEARECAAYFAkwV6CIACgkQRAx5nvEhZLJu1ACeLjyg/3yhc8SkGG6rdLxY4jz5
J6gAn0eLwla203gIzzPfAHy+fEhZUWQV
=7smq
-END PGP SIGNATURE-
___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

ZODB-Dev mailing list  -  ZODB-Dev@zope.org
https://mail.zope.org/mailman/listinfo/zodb-dev


Re: [ZODB-Dev] Old transaction records with bad pickle data preventing packing

2010-06-14 Thread Jim Fulton
On Mon, Jun 14, 2010 at 3:43 AM, Jens Vagelpohl j...@dataflake.org wrote:
 Hi all,

 In a system using Zope 2.11 and ZODB 3.7.0b3 I'm having a problem with
 old transaction records containing pickle data that fails on
 cPickle.Unpickler.noload as employed by ZODB.serialize.referencesf, I
 get an AttributeError from inside the cPickle module:

It would be interesting to see the traceback.

 def referencesf(p, oids=None):
    Return a list of object ids found in a pickle

    A list may be passed in, in which case, information is
    appended to it.

    Weak references are not included.
    

    refs = []
    u = cPickle.Unpickler(cStringIO.StringIO(p))
    u.persistent_load = refs
    u.noload()
    u.noload()

    # Now we have a list of referencs.  Need to convert to list of
    # oids:
 snip

 The noload failure means I cannot pack the database right now. Since
 only historical transactions contain the problematic attribute and I
 don't care about those anymore

Note that:

- in ZODB 3.9, there's an option top pack without doing GC, and
- ZODB 3.9 ZEO servers can be used with older clients.


 I have introduced a simple change locally
 that ignores the failure:

 def referencesf(p, oids=None):
    Return a list of object ids found in a pickle

    A list may be passed in, in which case, information is
    appended to it.

    Weak references are not included.
    

    refs = []
    u = cPickle.Unpickler(cStringIO.StringIO(p))
    u.persistent_load = refs
    try:
        u.noload()
        u.noload()
    except AttributeError:
        pass

    # Now we have a list of referencs.  Need to convert to list of
    # oids:
 snip

That's a bad idea.


 With this change I can pack the database and a few simple check
 (fsrefs.py etc) indicate the database is consistent after the pack.

Cool. You got lucky. :)

 My question: Is there any risk associated with ignoring the failure
 during packing?

Yes.  You might ignore references to objects causing them to be
removed while still used.

 The latest object versions for the persistent objects in
 question do not have the problematic attribute anymore, so the latest
 records are safe and will not cause the AttributeError, anyway.

Right, it worked out for your DB.

Jim


-- 
Jim Fulton
___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

ZODB-Dev mailing list  -  ZODB-Dev@zope.org
https://mail.zope.org/mailman/listinfo/zodb-dev