[ZODB-Dev] multi-level undo on a single object

Arthur Peters amp at singingwizard.org
Tue Aug 30 17:31:10 EDT 2005


Thanks you very much. I'm still having issues but I'll investigant it
myself before I ask anything else. I think I came across as pushy and
demanding and I'm sorry. I didn't mean to. I just ment this as
questions and ideas.

You know ZODB much better than I and I'll go for a app-level
implementation of undo unless I happen across a nice way to use ZODB for
it.

Thanks and sorry.
-Arthur

On 8/30/2005, "Tim Peters" <tim at zope.com> wrote:

>[Arthur Peters]
>> I want to do the following: commit a change to an object, then commit
>> another. Now I want to undo the second change. Easy: get the tid using
>> undoLog and call undo(tid, transaction.get()). Now the following
>> transactions are in the DB:
>>
>> - Change 1
>> - Change 2
>> - Undo change 2
>>
>> Now I want to take the DB back to the state before any of the three
>> transactions were commited. I can find no way to do this because all the
>> transactions change the same object and therefor I can never undo more
>> than the most resent one.
>
>It might help if you showed a specific way you tried.  The "obvious" way is
>to undo the last 3 transactions at this point.  For example:
>
>"""
>import ZODB
>import transaction
>from ZODB.FileStorage import FileStorage
>
>st = FileStorage("Temp.fs")
>db = ZODB.DB(st)
>cn = db.open()
>rt = cn.root()
>
>rt['state'] = 'start'
>transaction.commit()
>
>rt['state'] = 'two'
>transaction.commit()
>
>rt['state'] = 'three'
>transaction.commit()
>print "current state %r" % rt['state'] # prints 'three'
>
>undoable = st.undoLog()
>db.undo(undoable[0]['id'])
>transaction.commit()
>print "after undoing: %r" % rt['state'] # prints 'two'
>
># Undo the last three (the undo, setting 'three', and
># setting 'two').  Should get back to 'start' then.
>undoable = st.undoLog()
>for i, desc in enumerate(undoable):
>    if i > 2:
>        break
>    db.undo(desc['id'])
>transaction.commit()
>print "after undoing 3: %r" % rt['state'] # prints 'start'
>"""
>
>Output from running that:
>
>    current state 'three'
>    after undoing: 'two'
>    after undoing 3: 'start'
>
>> It seems to me reasonable that with this state ZODB should be able to
>> undo "Change 1" because it is actually in the same state as it was
>> between change 1 and change 2.
>>
>> I tried undoing them all in one transaction in hopes that the system
>> would smart enough to know that it would not cause a conflict, but no
>> luck.
>
>As above, it worked for me.  BTW, I was using ZODB 3.4 there, but it
>shouldn't matter except for spelling details.
>
>> The reason for all this is that I want to implement standard GUI-style
>> undo/redo features in a ZODB application.
>>
>> Probably the easiest way to provide this functionality would be to
>> implement a kind of undo that undoes all transactions back to a given
>> point.
>
>My advice is to implement undo/redo in your application, not to rely on ZODB
>for it.  Some storages don't support undo at all, while those that do lose
>old state after packing (or lose old state all by themselves).  In addition,
>it's very easy to create inconsistent database state by mucking with
>DB-level undo unless undos are treated strictly in stack-like fashion.
>
>> Also in the back of my mind is the idea of being able to configure a
>> connection to give me a non-current view of the DB (using MVCC). This
>> would allow me to implement suffisticated diff'ing algorithms between
>> states of the DB. This seems like it would be very easy to implement.
>> With MVCC in place and all.
>
>It's not an intended use case for MVCC, and there's no direct support for
>that now.  Don't know how hard it would be to add; there are no current
>plans to do so.
>
>> And would allow applications to implement much more suffisticates undo
>> than could be implemented in the current system. Thoughts?
>
>ZODB isn't intended to be a version control system <0.6 wink>.  Some
>storages support undo(), but it's intended to be used lightly at worst --
>the implementation isn't warped toward doing undo efficiently.  Seems to me
>it's been treated as a necessary convenience, but no more than that.
>
>> and is this what custom conflict resolution is for?
>
>Not specifically, no.  There is no general conflict resolution, BTW:  all
>conflict resolution is "custom".  A type can choose to implement conflict
>resolution if the author judges that it's OK for two (or more) transactions
>to mutate the same piece of state simultaneously.  Whether that makes any
>sense at all, and the precise sense it may make, are entirely up to the
>conflict resolution method's author.  Undo isn't special here, it's just
>another way of mutating state.
>


More information about the ZODB-Dev mailing list