[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