[ZODB-Dev] question

Christian Reis kiko at async.com.br
Wed Sep 10 21:32:42 EDT 2003


On Wed, Sep 10, 2003 at 03:02:42PM -0400, Shane Hathaway wrote:
> Christian Reis wrote:
> >On Wed, Sep 10, 2003 at 02:12:10PM -0400, Shane Hathaway wrote:
> >>Use a trivial deep copy.  (Although copy.deepcopy() doesn't like 
> >>ExtensionClass, so if you're using ZODB 3.2 or below, you need to use 
> >>cPickle to make the deep copy.  I can show you how if you're need it.)
> >
> >
> >Please do, that's something I've often wondered about.
> 
> Here is the simplest version:
> 
> import cPickle
> 
> def deepcopy(obj):
>     return cPickle.loads(cPickle.dumps(obj))
> 
> This will ignore ZODB record boundaries and make a copy of the whole 
> subtree.  The copy will have its _p_jar and _p_oid attributes unset.  It 
> will be disconnected entirely from the database until you store it.

Well, that's half the equation. How do I update the "real" object with
changes done to its clone, one I've decided to commit() the changes? The
situation I have is that N different objects may refer to the cloned
object, and I need to update the "real" one, not the clone.

Apart from updating __dict__ recursively down the subtree, is there a
good way to do this?

> Unfortunately, I'm pretty sure it's naive with ghosts (it may pickle 
> ghosts as objects with no attributes) and it fails for ZClasses.  So a 
> fully-elaborated version of the above is in the Ape product. 
> Unfortunately, it's far more complex, but fortunately, it's known to work.
> 
> http://cvs.zope.org/Products/Ape/lib/apelib/zodb3/utils.py?rev=1.1&content-type=text/vnd.viewcvs-markup

I've got time reserved now to take a good look at Ape; let's use that
time to learn something useful.

> >>Splitting up transactions would open major holes.  You'd need something 
> >>quite unlike ZODB to get it right.  Making temporary copies is much 
> >>simpler.
> >
> >
> >Okay, okay -- if only because you said so ;-)
> 
> Oh man, don't let me put down your idea.  I like it, but it's hard to 
> generalize to all ZODB users.  So now I'll switch to your side for a moment.
> 
> I'll let you in on a secret: previously, the transaction was directly 
> notified of every object change, but today, the _p_jar gets the 
> notification instead through its register() method.  The standard _p_jar 

Hmm, did you mean s/gets/emits/ here? I thought the Connection notified
the transaction, right?

> (a Connection object) always passes the notification to the transaction, 
> but you could make a subclass of Connection that does something 
> different.  For example, you could collect the notifications in a group 
> and choose to commit them separately.

Sounds interesting, very interesting.
 
> By subclassing Connection and overriding the register() method, you can 
> try out your idea without changing ZODB.  You might get into crazy 
> situations if some object gets modified by multiple groups, or by a 
> group as well as the transaction, but you can structure your application 
> in such a way to prevent that from happening.

The way I see it (which is probably wrong X-) an object would *either*
be in a group, or in the transaction's implicit "main group".

Or are you referring to problems with consistency that derive from
multiple ZEO clients simultaneously performing "writes"?

> I've overridden register() a few times for my own nefarious purposes and 
> it works like magic.  It gives you a whole new insight into ZODB.

I honestly think this is the "correct" solution, rather than copying the
object and then somehow restoring the modified state to the original
object -- deep down, it feels like we're just reimplementing the
database transaction mechanism, albeit in a much simpler way. 

Take care,
--
Christian Reis, Senior Engineer, Async Open Source, Brazil.
http://async.com.br/~kiko/ | [+55 16] 261 2331 | NMFL



More information about the ZODB-Dev mailing list