TX.3. Default Transaction Semantics

The two-phase commit protocol defines how a transaction is created and later driven to completion by either committing or aborting. It is neutral with respect to the semantics of locking under the transaction or other behaviors that impart semantics to the use of the transaction. Specific clients and servers, however, must be written to expect specific transaction semantics. This model is to separate the completion protocol from transaction semantics, where transaction semantics are represented in the parameters and return values of methods by which clients and participants interact.

This chapter defines the default transaction semantics of services. These semantics preserve the traditional ACID properties (you will find a brief description of the ACID properties in Section TX.1.2 “Distributed Transactions and ACID Properties”). The semantics are represented by the Transaction and NestableTransaction interfaces and their implementation classes ServerTransaction and NestableServerTransaction. Any participant that accepts as a parameter or returns any of these types is promising to abide by the following definition of semantics for any activities performed under that transaction.

TX.3.1. Transaction and NestableTransaction Interfaces

The client’s view of transactions is through two interfaces: Transaction for top-level transactions and NestableTransaction for transactions under which nested transactions can be created. First, the Transaction interface:

package net.jini.core.transaction; 

public interface Transaction {
    public static class Created implements Serializable {
        public final Transaction transaction; 
        public final Lease lease; 
        Created(Transaction transaction, Lease lease) {...} 
    } 
    void commit() // §TX.2.5 
        throws UnknownTransactionException, 
               CannotCommitException, 
               RemoteException; 
    void commit(long waitFor) // §TX.2.5 
        throws UnknownTransactionException, 
               CannotCommitException, 
               TimeoutExpiredException, RemoteException; 
    void abort() // §TX.2.5 
        throws UnknownTransactionException, 
               CannotAbortException, 
               RemoteException; 
    void abort(long waitFor) // §TX.2.5 
        throws UnknownTransactionException, 
               CannotAbortException, 
               TimeoutExpiredException, RemoteException; 
} 

The Created nested class is used in a factory create method for top-level transactions (defined in the next section) to hold two return values: the newly created Transaction object and the transaction’s lease, which is the lease granted by the transaction manager. The commit and abort methods have the same semantics as discussed in Section TX.2.5 “Completing a Transaction: The Client’s View”.

Nested transactions are created using NestableTransaction methods:

package net.jini.core.transaction; 

public interface NestableTransaction extends Transaction {
    public static class Created implements Serializable {
        public final NestableTransaction transaction; 
        public final Lease lease; 
        Created(NestableTransaction transaction, Lease lease) 
            {...} 
    } 
    Created create(long leaseFor) // §TX.2.2 
        throws UnknownTransactionException, 
               CannotJoinException, LeaseDeniedException, 
               RemoteException; 
    Created create(NestableTransactionManager mgr, 
                   long leaseFor) // §TX.2.2 
        throws UnknownTransactionException, 
        CannotJoinException, LeaseDeniedException, 
        RemoteException; 
} 

The Created nested class is used to hold two return values: the newly created Transaction object and the transaction’s lease, which is the lease granted by the transaction manager. In both create methods, leaseFor is the requested lease time in milliseconds. In the one-parameter create method the nested transaction is created with the same transaction manager as the transaction on which the method is invoked. The other create method can be used to specify a different transaction manager to use for the nested transaction.

TX.3.2. TransactionFactory Class

The TransactionFactory class is used to create top-level transactions.

package net.jini.core.transaction; 

public class TransactionFactory {
    public static Transaction.Created 
        create(TransactionManager mgr, long leaseFor) 
                                                 // §TX.2.1 
        throws LeaseDeniedException, RemoteException {...} 
    public static NestableTransaction.Created 
        create(NestableTransactionManager mgr, long leaseFor) 
                                                 // §TX.2.2 
        throws LeaseDeniedException, RemoteException {...} 
} 

The first create method is usually used when nested transactions are not required. However, if the manager that is passed to this method is in fact a NestableTransactionManager, then the returned Transaction can in fact be cast to a NestableTransaction. The second create method is used when it is known that nested transactions need to be created. In both cases, a Created instance is used to hold two return values: the newly created transaction object and the granted lease.

TX.3.3. ServerTransaction and NestableServerTransaction Classes

The ServerTransaction class exposes functionality necessary for writing participants that support top-level transactions. Participants can cast a Transaction to a ServerTransaction to obtain access to this functionality.

public class ServerTransaction 
    implements Transaction, Serializable 
{
    public final TransactionManager mgr; 
    public final long id; 
    public ServerTransaction(TransactionManager mgr, long id) 
        {...} 
    public void join(TransactionParticipant part, 
                     long crashCount) // §TX.2.3 
        throws UnknownTransactionException, 
               CannotJoinException, CrashCountException, 
               RemoteException {...} 
    public int getState() // §TX.2.7 
        throws UnknownTransactionException, RemoteException 
        {...} 
    public boolean isNested() {...} // §TX.3.3 
} 

The mgr field is a reference to the transaction manager that created the transaction. The id field is the transaction identifier returned by the transaction manager’s create method.

The constructor should not be used directly; it is intended for use by the TransactionFactory implementation.

The methods join, commit, abort, and getState invoke the corresponding methods on the manager, passing the transaction identifier. They are provided as a convenience to the programmer, primarily to eliminate the possibility of passing an identifier to the wrong manager. For example, given a ServerTransaction object tr, the invocation

    tr.join(participant, crashCount); 

is equivalent to

    tr.mgr.join(tr.id, participant, crashCount); 

The isNested method returns true if the transaction is a nested transaction (that is, if it is a NestableServerTransaction with a nonnull parent) and false otherwise. It is provided as a method on ServerTransaction for the convenience of participants that do not support nested transactions.

The hashCode method returns the id cast to an int XORed with the result of mgr.hashCode(). The equals method returns true if the specified object is a ServerTransaction object with the same manager and transaction identifier as the object on which it is invoked.

The NestableServerTransaction class exposes functionality that is necessary for writing participants that support nested transactions. Participants can cast a NestableTransaction to a NestableServerTransaction to obtain access to this functionality.

package net.jini.core.transaction.server; 

public class NestableServerTransaction 
    extendsServerTransaction implements NestableTransaction 
{
    public final NestableServerTransaction parent; 
    public NestableServerTransaction(
           NestableTransactionManager mgr, long id, 
           NestableServerTransaction parent) {...} 
    public void promote(TransactionParticipant[] parts, 
                        long[] crashCounts, 
                        TransactionParticipant drop) 
                                                    // §TX.2.7 
        throws UnknownTransactionException, 
               CannotJoinException, CrashCountException, 
               RemoteException {...} 
    public boolean enclosedBy(NestableTransaction enclosing) 
        {...} 
} 

The parent field is a reference to the parent transaction if the transaction is nested (see Section TX.2.2 “Starting a Nested Transaction”) or null if it is a top-level transaction.

The constructor should not be used directly; it is intended for use by the TransactionFactory and NestableServerTransaction implementations.

Given a NestableServerTransaction object tr, the invocation

    tr.promote(parts, crashCounts, drop) 

is equivalent to

    ((NestableTransactionManager)tr.mgr).promote(tr.id, parts, 
                                            crashCounts, drop) 

The enclosedBy method returns true if the specified transaction is an enclosing transaction (parent, grandparent, etc.) of the transaction on which the method is invoked; otherwise it returns false.

TX.3.4. CannotNestException Class

If a service implements the default transaction semantics but does not support nested transactions, it usually needs to throw an exception if a nested transaction is passed to it. The CannotNestException is provided as a convenience for this purpose, although a service is not required to use this specific exception.

package net.jini.core.transaction; 

public class CannotNestException extends TransactionException 
{
    public CannotNestException() {...} 
    public CannotNestException(String desc) {...} 
} 

TX.3.5. Semantics

Activities that are performed as pure transactions (all access to shared mutable state is performed under transactional control) are subject to sequential ordering, meaning the overall effect of executing a set of sibling (all at the same level, whether top-level or nested) pure transactions concurrently is always equivalent to some sequential execution.

Ancestor transactions can execute concurrently with child transactions, subject to the locking rules below.

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. When a subtransaction commits, its locks are inherited by the parent transaction.

In addition to locks, transactional operations can be defined in terms of object creation and deletion visibility. If an object is defined to be created under a transaction, then the existence of the object is visible only within that transaction and its inferiors, but will disappear if the transaction aborts. If an object is defined to be deleted under a transaction, then the object is not visible to any transaction (including the deleting transaction) but will reappear if the transaction aborts. When a nested transaction commits, visibility state is inherited by the parent transaction.

Once a transaction reaches the VOTING stage, if all execution under the transaction (and its subtransactions) has finished, then the only reasons the transaction can abort are:

  • The manager crashes (or has crashed)

  • One or more participants crash (or have crashed)

  • There is an explicit abort

Transaction deadlocks are not guaranteed to be prevented or even detected, but managers and participants are permitted to break known deadlocks by aborting transactions.

An active transaction is an orphan if it or one of its ancestors is guaranteed to abort. This can occur because an ancestor has explicitly aborted or because some participant or manager of the transaction or an ancestor has crashed. Orphans are not guaranteed to be detected by the system, so programmers using transactions must be aware that orphans can see internally inconsistent state and take appropriate action.

Causal ordering information about transactions is not guaranteed to be propagated. First, given two sibling transactions (at any level), it is not possible to tell whether they were created concurrently or sequentially (or in what order). Second, if two transactions are causally ordered and the earlier transaction has completed, the outcome of the earlier transaction is not guaranteed to be known at every participant used by the later transaction, unless the client is successful in using the variant of commit or abort that takes a timeout parameter. Programmers using non-blocking forms of operations must take this into account.

As long as a transaction persists in attempting to acquire a lock that conflicts with another transaction, the participant will persist in attempting to resolve the outcome of the transaction that holds the conflicting lock. Attempts to acquire a lock include making a blocking call, continuing to make non-blocking calls, and registering for event notification under a transaction.

TX.3.6. Serialized Forms

Class serialVersionUID Serialized Fields
Transaction.Created –5199291723008952986L all public fields
NestableTransaction.Created –2979247545926318953L all public fields
TransactionManager.Created –4233846033773471113L all public fields
ServerTransaction 4552277137549765374L all public fields
NestableServerTransaction –3438419132543972925L all public fields
TransactionException –5009935764793203986L none
CannotAbortException 3597101646737510009L none
CannotCommitException –4497341152359563957L none
CannotJoinException 5568393043937204939L none
CannotNestException 3409604500491735434L none
TimeoutExpiredException 3918773760682958000L all public fields
UnknownTransactionException 443798629936327009L none
CrashCountException 4299226125245015671L none

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.15.100