Undo

Peter Selinger selinger at mathstat.dal.ca
Wed Feb 28 22:39:06 EST 2007


Here is how I think undo can be done in a distributed environment.  I
think the undo history should be kept locally in the client (no global
list in the server). The server, however, can keep track of who the
last user (or last several users) were that edited a given
transaction, purely for informational purposes.

The undo state in the client should be a sequence of "undo items" like
this:

(guid1, pre-state1, post-state1)
(guid2, pre-state2, post-state2)
(guid3, pre-state3, post-state3)
(guid4, pre-state4, post-state4)

Here, each pre-state or post-state is a snapshot of the single
transaction as it existed before or after the edit, or one of them can
be <empty> (if a transaction was created or deleted).  It is important
to store the pre- and post-states, and not just the diff.

When the user requests to undo item number N, the client should: 

(1) lock the transaction guid(N)
(2) check if the transaction's current state equals post-state(N)
(2a) - if yes, change the state to pre-state, commit
(2b) - if not, a pop-up menu (or similar) informs the user of something
       like the following:

   CONFLICT_MENU:
   * you are attempting to undo the change pre-state(N) ->
     post-state(N) of transaction guid(N). However, the transaction
     has since been modified by user USER at TIMESTAMP (and USER at
     TIMESTAMP...) to current-state(). You have the following choices:

    (A) cancel the "undo",
    (B) undo the transaction anyway - warning: this will revert USER's
        more recent changes.
    (C) (if the changes pre-state(N) -> post-state(N) and
        post-state(N) -> current-state() do not overlap, i.e., they
        changed non-overlapping fields) - undo your part of the
        changes without undoing USER's changes.
  
Complex undo's such as "undo import" can be easily handled by storing
them as a list of atomic undo items. These will be treated as a single
operation by the user interface, but will be treated as a sequence of
atomic undo's internally (except that all transactions should be
locked at the beginning of the compound transaction.  For example:

(guid1, pre-state1, post-state1)
(guid2, pre-state2, post-state2)
BEGIN_IMPORT
 (guid3, pre-state3, post-state3)
 (guid4, pre-state4, post-state4)
 (guid5, pre-state5, post-state5)
END_IMPORT
(guid6, pre-state6, post-state6)
(guid7, pre-state7, post-state7)
(guid8, pre-state8, post-state8)

It is then up to the client to figure out whether to present
CONFLICT_MENU for individual transactions, or first check for
conflicts as a whole before undoing any part of a complex
transaction. 

For adding and deleting an empty account, there should be another kind
of atomic undo item; ditto for renaming an account. These items need
their own specific method for checking for conflicts (e.g., another
account of the same name has been created since this one was deleted,
etc). 

Deleting a non-empty account should be stored as a compound undo item
that first deletes all the transactions, then deletes the empty
account.

"Redo" is handled symmetrically, via a second list of "redo" items.
When undoing an item, it is moved from the undo stack to the redo
stack. When redoing an item, it is moved from the redo stack to the
undo stack. When committing an edit, the redo stack is deleted and the
edit is added to the top of the undo stack. 

-- Peter

Derek Atkins wrote:
> 
> I dont think you can depend on a single global log..  It would require
> extending the QofBackend API to do something like that.
> 
> So, what DOES "undo" mean in a multi-user environment?  That's a hard
> problem to solve, I think.
> 
> -derek
> 
> Karl Chen <quarl at cs.berkeley.edu> writes:
> 
> > Good point; I didn't know about this concurrent editing process.
> > If there is a single global log I guess one could have the ability
> > to undo other's transactions after confirmation, though this would
> > be tricky and for now I would say only allow undo if no one else
> > has committed in the meantime.
> >
> >>>>>> On 2007-02-23 08:53 PST, Peter Selinger writes:
> >
> >     Peter> As I understand it, in a large GnuCash installation,
> >     Peter> multiple users could access the same backend
> >     Peter> database. The lock-edit-commit mechanism prevents
> >     Peter> conflicts.
> >
> >     Peter> So what should be the default behavior of U2 and U3
> >     Peter> (undo or redo) if, for example, the transaction has
> >     Peter> meanwhile been edited by another user?
> >
> > -- 
> > Karl 2007-02-26 15:35
> > _______________________________________________
> > gnucash-devel mailing list
> > gnucash-devel at gnucash.org
> > https://lists.gnucash.org/mailman/listinfo/gnucash-devel
> >
> >
> 
> -- 
>        Derek Atkins, SB '93 MIT EE, SM '95 MIT Media Laboratory
>        Member, MIT Student Information Processing Board  (SIPB)
>        URL: http://web.mit.edu/warlord/    PP-ASEL-IA     N1NWH
>        warlord at MIT.EDU                        PGP key available
> 



More information about the gnucash-devel mailing list