This package provides a generic interface and an implementation of a Hierarchical Locking Manager.
Hierarchical Locking Manager (further referred to as HLM), is an object, or a service implementing a fine-grained, hierarchical locking concept. In general three types of locks are allowed:
Because of these assumptions, it may be impossible to grant some locks in the presence of others. The rules of granting or denying a lock are usually gathered in a form of lock compatibility matrix. Such matrix for the two types of locks above looks like this:
Requested lock (by another process) | |||
---|---|---|---|
Present lock: | A Shared Lock? | An Exclusive Lock? | An Upgrade Lock? |
A Shared Lock |
Yes |
No |
Yes |
An Exclusive Lock |
No |
No |
No |
An Upgrade Lock |
Yes |
No |
No |
The compatibility matrix gets more complicated, when a hierarchy of objects is to be locked. When organized in a proper tree, locks set on higher level of the hierarchy may significantly speed-up the performance of an application (no need for locking sub-elements). This, however requires two new types of lock to be introduced: intention read lock and intention write locks. The compatibility matrix grows bigger and a more complex protocol of setting and releasing locks is required in order to keep the locking mechanism correct. See below for an in-depth book on the subject of hierarchical locking in database systems.
This package contains a generic implementation of a hierarchical locking manager. Generic, in terms of objects being locked within the hierarchy and objects locking them (locks are associated to a specific object, not to the calling thread).
In order to use the HLM in this package, several steps must be fulfilled.
A sample implementation for XML-database hierarchies is included within the package and named CollectionPathIterator.
This example shows how locks for the "collection" type of hierarchy may be acquired.
HierarchicalLockManager hlm = new HierarchicalLockManagerImpl( new CollectionPathIterator() ); // Set a read lock for user "foo" on element "bar" of collection "test" hlm.readLock( "/test/bar", "foo" ); // Remove the read lock for user "foo" on element "bar" of collection "test" hlm.removeReadLock( "/test/bar", "foo" ); // Set a write lock for user "foo" on the entire collection "test" hlm.writeLock( "/test/", "foo" ); // Remove it. hlm.removeWriteLock( "/test/", "foo" );
This example shows how to cause a deadlock on the current thread.
HierarchicalLockManager hlm = new HierarchicalLockManagerImpl( new CollectionPathIterator() ); // Set a read lock for user "foo" on element "bar" of collection "test" hlm.readLock( "/test/bar", "foo" ); // Attempt to set a write lock on the entire hierarchy for some // different user than "foo". This // causes a deadlock because the same thread already acquired // a read lock in sub-hierarchy. In other words: this thread will // endlessly wait for release of read lock on '/test/bar' by 'foo'. hlm.writeLock( "/test/", "not-quite-foo" );
Philip A. Bernstein, Vassos Hadzilacos, Nathan Goodman: Concurrency Control and Recovery in Database Systems. Addison Wesley, 1987. [@:] http://www.cs.purdue.edu/homes/sunil/syllabi/542/book/images