The Artima Developer Community
Sponsored Link

Survival of the Fittest Jini Services, Part III
Implement Transactional Jini Services
by Frank Sommers
First Published in JavaWorld, October 19, 2001

<<  Page 5 of 8  >>

Advertisement

The Two-Phase Locking (2PL) Protocol

The most common technique in isolating a transaction's execution is for a service to lock data that the transaction reads or writes. Before each read operation, the service places a read lock on an object, and before each write operation, it places a write lock on an object. This way, the read and write operations are covered by locks.

There are a few simple rules for managing locks on objects. First, locks must be held until the transaction commits or aborts. Recall that an abort corresponds to a write operation, replacing the new value with the old one. In case of an abort, therefore, after that final write restores the old value, the write lock releases on the modified object. A transaction is well formed if each of its operations is covered by locks, and if all locks release at the transaction's completion.

Second, since an object with a read lock is not modified by a transaction, other transactions can read that object, even if the first transaction is still in progress. For this reason, read locks on an object can be shared between transactions -- they are shared locks.

On the other hand, if an object has a write lock, that implies that the lock-owning transaction modified the object. A write lock is exclusive to a transaction that owns it -- other transactions cannot share it. If an object has an exclusive lock on an object, other transactions must wait before they can either read or write that object. In addition, a transaction cannot lock an object if it does not intend to perform a subsequent read or write on that object.

And finally, a transaction can upgrade a shared lock to an exclusive lock, but cannot downgrade an exclusive lock to a shared lock. Doing so would allow other transactions to read dirty data.

Figure 5 shows two transactions, TBuyBook and TPayUtility, performing lock-covered read and write actions.


Figure 5. Two transactions ensure that their read and write operations are covered by, respectively, shared and exclusive locks.

Because a distributed transaction can abort even after its write operations complete in a service, that service must hold on to all locks associated with a given transaction until that transaction either commits or aborts. In addition, after a transaction releases any lock, it should never acquire new locks on any object it reads or writes.

In other words, your Jini service goes through two distinct steps to manage locks: When it receives a transactional method invocation and joins the transaction, it acquires locks on objects the transaction reads or writes. Then, when the transaction's commitment or abort is called, it starts releasing all those locks. Once the release phase starts, your service cannot acquire new locks on that transaction's behalf. This lock-management strategy is called the two-phase locking protocol (2PL). Figure 6 illustrates this protocol.


Figure 6. The two-phase locking protocol. In the first stage, a service acquires all the locks on a transaction's behalf; in the second, it releases the transaction's locks.

The 2PL protocol (see Jini Transaction Specification, Section 3.5) provides the default transaction semantics for Jini services, preserving the transaction's ACID properties:

Transaction semantics for objects are defined in terms of strict two-phase locking. Every transactional operation is described in terms of acquiring locks on objects; these locks are held until the transaction completes. The most typical locks are read and write locks, but others are possible. Whatever the lock types are, conflict rules are defined such that if two operations do not commute, then they acquire conflicting locks. For objects using standard read and write locks, read locks do not conflict with other read locks, but write locks conflict with both read locks and other write locks. A transaction can acquire a lock if the only conflicting locks are those held by ancestor transactions (or itself). If a necessary lock cannot be acquired and the operation is defined to proceed without waiting for that lock, then serializability might be violated.

Intuitively, you can easily see that transactions with participants that obey the 2PL rule prevent dirty or unrepeatable reads, as well as lost updates; therefore, they execute in isolation from other concurrently running transactions. In other words, well-formed transactions with the 2PL protocol guarantee isolation. Several mathematical proofs exist to show that this rule is true for any transaction (see Jim Gray's Transaction Processing: Concepts and Techniques). Isolation, in turn, is a prerequisite for preserving data consistency (the C in ACID).

Although in an abstract sense a transaction owns locks on objects, your service manages those locks. Managing locks, and associating them with transactions, is a transactional Jini service's main task.

<<  Page 5 of 8  >>


Sponsored Links



Google
  Web Artima.com   
Copyright © 1996-2017 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us