Blog Stats
  • Posts - 99
  • Articles - 5
  • Comments - 59
  • Trackbacks - 108

 

Interesting discussion

This is just a copy/paste of a discussion I had with someone via email that I thought others may have some comments on ... to put things in context, it has to do with providing multi-step undo transactional type behaviors within an object graph.

 

Note: I dicuss my UnitOfWork here as if it is a single item, it is not. I use a stack as well to allow for nested transactions.

Note2: This is a rather naive implementation of a transactional graph.

 

Locking Memento Provider:

This is the bread and butter of my domain and it solves alot of things, it also provides the multi-step undo behaviors you mention. Here is a rather naive example.

 

ILockableObject {

    bool Acquire(int timeout) ;

    void Release();

}

 

IMementoProvider {

    IMemento GetState();   

    void SetState(IMemento);

}

 

ILockingMementoProvider : IMementoProvider, ILockableObject {}

 

 

now that we have this, imagine that all of our domain objects are LockingMementoProviders and we are using a thread scoped unit of work for our transaction management (i.e. a UnitOfWorkManager maps a call to a UnitOfWork based upon its thread id).

 

basically what happens is our domain objects automatically talk to our unit of work when they are dirtied (I do this through an aspect but it could be done manually as well; the register dirty happens immediately BEFORE the dirtying process) this is how I do it now though it could easily be just after as well.

The unit of work manager maps the register dirty to the proper UOW based upon our thread context. The UOW then asks the object for a memento representing its current state. The UOW hangs onto the memento, if the object is a lockableobject the UOW also tells the object it is now exclusively locked (it will stay in this state until it is released thus no other threads can manipulate it while we are). Eventually after a series of objects in the graph are dirtied the UOW is either told to commit or to rollback.

 

In the case of a commit() the information is persisted in the context of a transaction and providing there are no problems then the locks are released and the UOW is cleared. If there are problems it gets rolled back.

In the case of a rollback(), the UOW walks back through its list of dirtied objects returning the objects to their original states using the setstate method and the original memento it had from the object. Note that since these are just lists or hashes of objects one can do nested transactions easily by just adding a stack to the current list ( i.e. multiple begins = multiple push multiple commit = multiple pop and this can also provide scoping levels)

 

This helps a few things discussed:

 

1) I am using an indentity map and I have just screwed the pooch alterring my object (I have to force a cache invalidation). This isa particular example I really don't like because frankly I don't trust a 1st year programmer with having the brain power to remember the importance of this process (although I also have to admit I am often careless and forget such things, but no its them ... all them :))  Rollback, the graph will be in a known consistent state.

2) Transaction management - UOW including stepped/object graph rollback

3) Concurrency problems - rather naive locking but it is atleast automatic

 

not to say that there are not issues, because boy there can be if you screw up your locking :) but I think multi threading any significant domain is a very challenging affair.


Feedback

# re: Interesting discussion

Gravatar You should look into what Rocky Lhotka has built in CSLA. There's complete support for this sort of behavior. Check it out <a href="http://www.lhotka.net/ArticleIndex.aspx?area=CSLA%20.NET%2020">here</a> 3/15/2006 12:42 PM | Marc Brooks

Post a comment





 

Please add 7 and 3 and type the answer here:

 

 

Copyright © Greg Young