RE: [Objectbridge-developers] Reader/Writer Locks and other such stuff
Brought to you by:
thma
From: Dixon-Peugh, D. <Dav...@tp...> - 2000-12-05 14:22:36
|
If we have multiple strategies for locking, then should we have different strategies for different classes? If a class requires a higher level of isolation, it doesn't seem like too much trouble to give it to them. (Perhaps the class is suceptable to race conditions?) -----Original Message----- From: obj...@li... [mailto:obj...@li...]On Behalf Of Mahler Thomas Sent: Tuesday, December 05, 2000 4:56 AM To: dp...@mi... Cc: Dixon-Peugh, David; obj...@li... Subject: AW: [Objectbridge-developers] Reader/Writer Locks and other such stuff David Dixon-Peugh wrote: > > > > > > ojb.server.ReaderWriterLock - > > > > > As for MROW, you end up with an isolation problem. If you are in > the process of > reading an object which is being written to, you end up with the > wrong data. (I > believe > Oracle calls it dirty reads.) exactly! But sometimes it's better to have dirty reads than beeing locked out for a long time. That's why most DB-Vendors (OODBMS as well as RDBMS) provide the user with a choice of several tx isolation levels. Of course your scheme (I guess it is called TRANSACTION_SERIALIZABLE in java.sql.Connection and EJB) provides a maximum level of transactional isolation. But this maximum isolation level can decrease performance of concurrent application by an enormous factor. Generally speaking there is a tradeoff between tx isolation level and performance for concurrent applications. As far as I know ODMG does not specify anything regarding isolation level. My suggestion: Let's apply the strategy pattern here. There is an abstract class AbstractLockingStrategy with concrete implementations. Your implementation could be called TxSerializableLockingStrategy. This strategy might be used as default. There could be other implementations (which we don't have to implement right now): TxReadUncommitedLockingStrategy : the tx can read uncommited data (i.e. changed by a different tx that is still in progress. I guess this is Objectivities MROW) TxReadCommitedLockingStrategy : data that is being changed by a different tx cannot be read. TxRepeatableReadLockingStrategy : the tx cannot change data that is being read by a different tx. > > The problem here though, is that the user of ObJectBridge is > writing the classes > themselves. The code required to keep the reads and writes > seperate needs to > happen in the class. We cannot provide it within ObJectBridge. > In the case of your TxSerializableLockingStrategy he user has to handle LockNotGrantedExceptions that occur due to lockouts from other transactions that have read or write locks on a given Object. In the case of MROW the user will have to handle LockNotGrantedExceptions when a different tx has already a write lock. If the client tries to upgrade from read- to write lock a different tx might have invalidated the given Object. Then ojb has to fire an other Exception and the client has to re-read the object. So the user has always to handle possible Exceptions thrown from the TxManager. > This brings up an interesting flaw, that I can't see any way to > get around. We > cannot > enforce the READ/WRITE locks on objects that ObJectBridge serves > up. So, if you > have a read lock, you can still modify the object. (Opens the > door for many a > race > condition for poorly written code.) That's why I suggest to use implicit locking. Thus the user only has to work with one single programming concept: tx handling and not to bother with aquiring locks etc. > > > > > > > > > > ojb.server.ObjectTransactionWrapper - > > > > > > This class maintains the state of a persistent object at the > begining and > > > end of a transaction. When the wrapper is aborted, the > persistent fields > > > of the object are restored to what they were at the begining of the > > > transaction. > > > > > > > Wow, you are reusing my ClassDescriptor / FieldDescriptor > stuff! looks great. > > > > > > > > ojb.server.TransactionImpl - > > > > > > This class has been modified to use the Reader/Writer locks > as apropriate. > > > It has also been modified to build ObjectTransactionWrapper around all > > > objects > > > that a WRITE lock is acquired on. > > > > When I get your code right, you want the user to explicitely > aquire read and > > write locks ? > > My suggestion: use TransactionImpl::markModified() to aquire a > write lock > > implicitely. Thus the user has not to care about locking but > can just call a > > setter. Of course the possible LockNotGrantedExceptions have to > be reached > > back to the user. > > What do you think? > > > > Getting implicit read locks maybe not so easy? Perhaps we have > to place a > > Transaction::lock(ObjectToRead, Transaction.READ) in all getters? > > > > I would like the user to explicitely get WRITE locks. READ locks > can be granted > when we serve up the object. (Maybe we can serve up the READ locks in the > implementation of DList or such.) > > From what I've seen of the ODMG spec, we need to provide explicit locking > capabilities anyways, so getting a WRITE lock like that isn't > such a big deal. > I have no objections regarding getting manual locks. But if you have an object locked with a read lock and you call a setter method it is obvious that you implicitely intend to get a write lock on the object. As we call markModified() in each setter it would be a courtesy for our user to acquire the write-lock form him if he did not acquired it already. > > > > > > > > > > > > It has been modified to have ObjectTransactionWrapper > commit/abort where > > > apropriate. > > > > Your ObjectTransactionWrapper::comit() is still empty, do you > want to reuse my > > ObjectModification / ModificationState stuff or do you have > other ideas for > > triggering the adequate PersistenceBroker calls? > > > > At this point, ObjectTransactionWrapper is only responsible for > the in memory > version > of the object. The Object is in its commited form when the transaction is > commited, > hense no code. > > I'm not sure if putting the storage stuff into the > ObjectTransactionWrapper is > necessarily > a good idea. Ultimately, all objects from the same database need > to be committed > within > the same database transaction, and it seems unlilkely that the > ObjectTransactionWrapper > can identify which transaction to commit it in without some big ugly hack. > This is clear to me. But I was asking because you removed all calls to PersistenceBroker.store(...) I am definitely open to suggestions on how we can merge these operations though. I'm not sure, but why not call PersistenceBroker.store() from within TransactionImpl.commit() immediately after your ObjectTransactionWrapper.commit() ? best regards , Thomas _______________________________________________ Objectbridge-developers mailing list Obj...@li... http://lists.sourceforge.net/mailman/listinfo/objectbridge-developers |