10.3.2. LockManager
The concurrency controller is implemented by the class
LockManager
, which provides sensible default behavior that you can override if necessary. The setlock
method is the primary interface to the concurrency controller. By default, the JBoss Transaction Service runtime system enforces strict two-phase locking, following a multiple reader, single writer policy on a per-object basis. You, as the programmer, control lock acquisition, since the LockManager
class cannot predict whether an operation needs a read or write lock. Lock release, however, is normally under control of the system, requiring no action by the programmer.
The
LockManager
class manages requests to set a lock on an object or to release a lock. However, since it is derived from StateManager
, it can also control invocation of some of the inherited facilities. For example, if a request to set a write lock is granted, then LockManager
invokes the modified
method directly, since setting a write lock implies that the invoking method is about to modify the object. This may cause recovery information to be saved, if the object is recoverable. Successful lock acquisition also triggers invocation of the activate
.
Therefore,
LockManager
activates and deactivates persistent objects, and also registers Resources
used for managing concurrency control. By driving the StateManager
class, it also registers Resources
for persistent and recoverable state manipulation and object recovery. You only set the appropriate locks, start and end transactions, and extend the save_state
and restore_state
methods of the StateManager
class.
Example 10.9. LockResult Example
public class LockResult { public static final int GRANTED; public static final int REFUSED; public static final int RELEASED; }; public class ConflictType { public static final int CONFLICT; public static final int COMPATIBLE; public static final int PRESENT; }; public abstract class LockManager extends StateManager { public static final int defaultTimeout; public static final int defaultRetry; public static final int waitTotalTimeout; public synchronized int setlock (Lock l); public synchronized int setlock (Lock l, int retry); public synchronized int setlock (Lock l, int retry, int sleepTime); public synchronized boolean releaselock (Uid uid); /* abstract methods inherited from StateManager */ public boolean restore_state (InputObjectState os, int ObjectType); public boolean save_state (OutputObjectState os, int ObjectType); public String type (); protected LockManager (); protected LockManager (int ObjectType, ObjectName attr); protected LockManager (Uid storeUid); protected LockManager (Uid storeUid, int ObjectType, ObjectName attr); . . . };
You need to pass the type of lock required and the number of retries to acquire the lock,as parameters to the
setlock
method. The type is either READ
or WRITE
. If a lock conflict occurs, one of the following scenarios will take place:
- If the retry value is equal to
LockManager.waitTotalTimeout
, the thread which called thesetlock
method is blocked until the lock is released, or the total timeout specified has elapsed. In the case of a time-out, a value ofREFUSED
is returned. - If the lock cannot be obtained initially,
LockManager
retries the specified number of times, waiting for the specified timeout value between each failed attempt. The default is 100 attempts, each attempt being separated by a 0.25 seconds delay.
If a lock conflict occurs, the lock request is timed out, to prevent deadlocks. A full deadlock detection scheme is not provided. If the requested lock is obtained, the
setlock
method returns a value of GRANTED
. Otherwise, a value of REFUSED
is returned. You need to ensure that the remainder of the code for an operation is only executed if a lock request is granted. Refer to Example 10.10, “setlock
Example” for a working example.
Example 10.10. setlock
Example
res = setlock(new Lock(WRITE), 10); // Attempts to set a write // lock 11 times (10 retries) // before giving up. res = setlock(new Lock(READ), 0); // Attempts to set a read lock // 1 time (no retries) before // giving up. res = setlock(new Lock(WRITE); // Attempts to set a write lock // 101 times (default of 100 // retries) before giving up.
The concurrency control mechanism is integrated into the atomic action mechanism to ensure that as locks are granted on an object, appropriate information is registered with the currently running atomic action. This guarantees that the locks are released at the correct time, and removes the need to explicitly free locks which were acquired within atomic actions. However, if locks are acquired on an object outside of the scope of an atomic action, you must use the
releaselock
method to release the locks.