Transaction Core Programmers Guide
TX-PG-3/31/06

Legal Notices
The information contained in this documentation is subject to change without notice.
JBoss Inc. makes no warranty of any kind with regard to this material, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. JBoss Inc. shall not be liable for errors contained herein or for incidental or consequential damages in connection with the furnishing, performance, or use of this material.
Java� and J2EE is a U.S. trademark of Sun Microsystems, Inc. Microsoft� and Windows NT� are registered trademarks of Microsoft Corporation. Oracle� is a registered U.S. trademark and Oracle9�, Oracle9 Server� Oracle9 Enterprise Edition� are trademarks of Oracle Corporation. Unix is used here as a generic term covering all versions of the UNIX� operating system. UNIX is a registered trademark in the United States and other countries, licensed exclusively through X/Open Company Limited.
Arjuna is a trademark of Hewlett-Packard Company and is used here under licence.
Copyright
JBoss, Home of Professional Open Source Copyright 2006, JBoss Inc., and individual contributors as indicated by the @authors tag.� All rights reserved.
See the copyright.txt in the distribution for a full listing of individual contributors. This copyrighted material is made available to anyone wishing to use, modify, copy, or redistribute it subject to the terms and conditions of the GNU General Public License, v. 2.0. This program is distributed in the hope that it will be useful, but WITHOUT A WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A� PARTICULAR PURPOSE.
See the GNU General Public License for more details. You should have received a copy of the GNU General Public License, v. 2.0 along with this distribution; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,� * MA� 02110-1301, USA.
Software Version
JBoss Transactions 4.2
Restricted Rights Legend
Use, duplication, or disclosure is subject to restrictions as set forth in contract subdivision (c)(1)(ii) of the Rights in Technical Data and Computer Software clause 52.227-FAR14.
� Copyright 2006 JBoss Inc.
Contents
TxCore � the transaction engine
The life-cycle of a Transactional Object for Java
The transaction protocol engine
Selecting an object store implementation
Lock management and concurrency control
Selecting a lock store implementation
Object construction and destruction
Advanced transaction issues with TxCore
Last resource commit optimisation
Independent top-level transactions
Transactions within save_state and restore_state
Using transactions in constructors
More on save_state and restore_state
Constructing a Transactional Objects for Java application
save_state, restore_state and type
The Transaction Core Programmers Guide contains information on how to use JBoss Transactions 4.2. This document provides a detailed look at the design and operation of the TxCore transaction engine and the Transactional Objects for Java toolkit.� It describes the architecture and the interaction of components within this architecture.
This guide is most relevant to engineers who are responsible for administering JBoss Transactions 4.2 installations. Although this guide is specifically intended for service developers, it will be useful to anyone who would like to gain an understanding of transactions and how they function.
This guide assumes a basic familiarity with Java service development and object-oriented programming. A fundamental level of understanding in the following areas will also be useful:
� General understanding of the APIs, components, and objects that are present in Java applications.
� A general understanding of the Windows and UNIX operating systems.
This guide contains the following chapters:
� Chapter 1, Overview: this chapter contains a description of the use of the TxCore transaction engine the Transactional Object for Java classes and facilities.
� Chapter 2, Using TxCore: gives details on interfaces and classes defined by TxCore and describes how they can be used to construct transactional applications.
� Chapter 3, General transactions issues: presents advanced issues with TxCore.
� Chapter 4, Hints and tips: illustrates some hints on the way to use TxCore
� Chapter 5, Tools: how to use the management tools shipped with TxCore.
� Chapter 6, Constructing a Transactional Object for Java application: this chapter describes a detailed implementation of an application to illustrate various mechanisms provided by TxCore.
� Chapter 7, Configuration options: shows configurations options of TxCore.
The following conventions are used in this guide:
|
Convention |
Description |
|
Italic |
In paragraph text, italic identifies the titles of documents that are being referenced.� When used in conjunction with the Code text described below, italics identify a variable that should be replaced by the user with an actual value. |
|
Bold |
Emphasizes items of particular importance. |
|
Code |
Text that represents programming code. |
|
Function | Function |
A path to a function or dialog box within an interface.� For example, �Select File | Open.� indicates that you should select the Open function from the File menu. |
|
( ) and | |
Parentheses enclose optional items in command syntax. The vertical bar separates syntax items in a list of choices. For example, any of the following three items can be entered in this syntax: persistPolicy (Never | OnTimer | OnUpdate | NoMoreOftenThan) |
|
Note: |
A note highlights important supplemental information. A caution highlights procedures or information that is necessary to avoid damage to equipment, damage to software, loss of data, or invalid test results. |
Table 1 ����� Formatting Conventions
In addition to this guide, the following guides are available in the JBoss Transactions 4.2 documentation set:
� JBoss Transactions 4.2 Release Notes:� Provides late-breaking information about JBoss Transactions 4.2.
� JBoss Transactions 4.2 Installation Guide:� This guide provides instructions for installing JBoss Transactions 4.2.
� JBoss Transactions 4.2 Failure Recovery Guide:� Provides guidance for administering the system.
� JBoss Transactions 4.2 Transactions API Guide:� Provides guidance for administering the system.
� JBoss Transactions 4.2 Web Services Transactions Programmers Guide:� Provides guidance for administering the system.
� JBoss Transactions 4.2 Administration Guide:� Provides guidance for administering the system.
Questions or comments about JBoss Transactions 4.2 should be directed to our support team.
This chapter contains a description of the use of the TxCore transaction engine and the Transactional Objects for Java classes and facilities. The classes mentioned in this chapter are the key to writing fault-tolerant applications using transactions. Thus, after describing them we shall apply them in the construction of a simple application. The classes to be described in this chapter can be found in the com.arjuna.ats.txoj and com.arjuna.ats.arjuna packages.
In keeping with the object-oriented view, the mechanisms needed to construct reliable distributed applications are presented to programmers in an object-oriented manner. Some mechanisms need to be inherited, for example, concurrency control and state management; while other mechanisms, such as object storage and transactions, are implemented as TxCore objects that are created and manipulated like any other object.
Note: When the manual talks about using persistence and concurrency control facilities it assumes that the Transactional Objects for Java (TXOJ) classes are being used. If this is not the case then the programmer is responsible for all of these issues.
TxCore exploits object-oriented techniques to present programmers with a toolkit of Java classes from which application classes can inherit to obtain desired properties, such as persistence and concurrency control. These classes form a hierarchy, part of which is shown below and which will be described later in this document.

Figure 1: TxCore class hierarchy.
Apart from specifying the scopes of transactions, and setting appropriate locks within objects, the application programmer does not have any other responsibilities: TxCore and Transactional Objects for Java (TXOJ) guarantee that transactional objects will be registered with, and be driven by, the appropriate transactions, and crash recovery mechanisms are invoked automatically in the event of failures.
TxCore needs to be able to remember the state of an object for several purposes, including recovery (the state represents some past state of the object) and persistence (the state represents the final state of an object at application termination). Since these requirements have common functionality they are all implemented using the same mechanism: the classes InputObjectState and OutputObjectState. The classes maintain an internal array into which instances of the standard types can be contiguously packed (unpacked) using appropriate pack (unpack) operations. This buffer is automatically resized as required should it have insufficient space. The instances are all stored in the buffer in a standard form (so-called network byte order) to make them machine independent. Any other architecture independent format (such as XDR or ASN.1) could be implemented simply by replacing the operations with ones appropriate to the encoding required.
Implementations of persistence can be affected by restrictions imposed by the Java SecurityManager. Therefore, the object store provided with TxCore is implemented using the techniques of interface/implementation. The current distribution has implementations which write object states to the local file system or database, and remote implementations, where the interface uses a client stub (proxy) to remote services.
Persistent objects are assigned unique identifiers (instances of the Uid class), when they are created, and this is used to identify them within the object store. States are read using the read_committed operation and written by the write_(un)committed operations.
At the root of the class hierarchy is the class StateManager. This class is responsible for object activation and deactivation and object recovery. The simplified signature of the class is:
public abstract class StateManager
{
public boolean activate ();
public boolean deactivate (boolean commit);
public Uid get_uid (); // object�s identifier.
// methods to be provided by a derived class
public boolean restore_state (InputObjectState os);
public boolean save_state (OutputObjectState os);
protected StateManager ();
protected StateManager (Uid id);
};
Objects are assumed to be of three possible flavours. They may simply be recoverable, in which case StateManager will attempt to generate and maintain appropriate recovery information for the object. Such objects have lifetimes that do not exceed the application program that creates them. Objects may be recoverable and persistent, in which case the lifetime of the object is assumed to be greater than that of the creating or accessing application, so that in addition to maintaining recovery information StateManager will attempt to automatically load (unload) any existing persistent state for the object by calling the activate (deactivate) operation at appropriate times. Finally, objects may possess none of these capabilities, in which case no recovery information is ever kept nor is object activation/deactivation ever automatically attempted.
If an object is recoverable or recoverable and persistent then StateManager will invoke the operations save_state (while performing deactivate), and restore_state (while performing activate) at various points during the execution of the application. These operations must be implemented by the programmer since StateManager cannot detect user level state changes. (We are examining the automatic generation of default save_state and restore_state operations, allowing the programmer to override this when application specific knowledge can be used to improve efficiency.) This gives the programmer the ability to decide which parts of an object�s state should be made persistent. For example, for a spreadsheet it may not be necessary to save all entries if some values can simply be recomputed. The save_state implementation for a class Example that has integer member variables called A, B and C could simply be:
public boolean save_state(OutputObjectState o)
{
��� if (!super.save_state(o))
������� return false;
��� try
��� {
������� o.packInt(A);
������� o.packInt(B);
������� o.packInt(C));
��� }
��� catch (Exception e)
��� {
������� return false;
��� }
��� return true;
}
Note: it is necessary for all save_state and restore_state methods to call super.save_state and super.restore_state. This is to cater for improvements in the crash recovery mechanisms.
The life-cycle of a Transactional Object for Java
A persistent object not in use is assumed to be held in a passive state with its state residing in an object store and activated on demand. The fundamental life cycle of a persistent object in TXOJ is shown in Figure 2.

Figure 2: The life cycle of a persistent object.
� The object is initially passive, and is stored in the object store as an instance of the class OutputObjectState.
� When required by an application the object is automatically activated by reading it from the store using a read_committed operation and is then converted from an InputObjectState instance into a fully-fledged object by the restore_state operation of the object.
� When the application has finished with the object it is deactivated by converting it back into an OutputObjectState instance using the save_state operation, and is then stored back into the object store as a shadow copy using write_uncommitted. This shadow copy can be committed, overwriting the previous version, using the commit_state operation. The existence of shadow copies is normally hidden from the programmer by the transaction system. Object de-activation normally only occurs when the top-level transaction within which the object was activated commits.
Note: During its life time, a persistent object may be made active then passive many times.
The concurrency controller is implemented by the class LockManager which provides sensible default behaviour while allowing the programmer to override it if deemed necessary by the particular semantics of the class being programmed. As with StateManager and persistence, concurrency control implementations are accessed through interfaces. As well as providing access to remote services, the current implementations of concurrency control available to interfaces include:
� local disk/database implementation, where locks are made persistent by being written to the local file system or database.
� a purely local implementation, where locks are maintained within the memory of the virtual machine which created them; this implementation has better performance than when writing locks to the local disk, but objects cannot be shared between virtual machines. Importantly, it is a basic Java object with no requirements which can be affected by the SecurityManager.
The primary programmer interface to the concurrency controller is via the setlock operation. By default, the runtime system enforces strict two-phase locking following a multiple reader, single writer policy on a per object basis. However, as shown in Figure 1, by inheriting from the Lock class it is possible for programmers to provide their own lock implementations with different lock conflict rules to enable type specific concurrency control.
Lock acquisition is (of necessity) under programmer control, since just as StateManager cannot determine if an operation modifies an object, LockManager cannot determine if an operation requires a read or write lock. Lock release, however, is under control of the system and requires no further intervention by the programmer. This ensures that the two-phase property can be correctly maintained.
public abstract class LockManager extends StateManager
{
public LockResult setlock (Lock toSet, int retry, int timeout);
};
The LockManager class is primarily responsible for managing requests to set a lock on an object or to release a lock as appropriate. However, since it is derived from StateManager, it can also control when some of the inherited facilities are invoked. For example, LockManager assumes that the setting of a write lock implies that the invoking operation must be about to modify the object. This may in turn cause recovery information to be saved if the object is recoverable. In a similar fashion, successful lock acquisition causes activate to be invoked.
The code below shows how we may try to obtain a write lock on an object:
public class Example extends LockManager
{
public boolean foobar ()
{
� AtomicAction A = new AtomicAction;
� boolean result = false;
� A.begin();
� if (setlock(new Lock(LockMode.WRITE), 0) == Lock.GRANTED)
� {
��� /*
���� * Do some work, and TXOJ will
���� * guarantee ACID properties.
���� */
��� // automatically aborts if fails
��� if (A.commit() == AtomicAction.COMMITTED)
��� {
����� result = true;
��� }
� }
� else
��� A.rollback();
� return result;
}
}
The transaction protocol engine
The transaction protocol engine is represented by the AtomicAction class, which uses StateManager in order to record sufficient information for crash recovery mechanisms to complete the transaction in the event of failures. It has methods for starting and terminating the transaction, and, for those situations where programmers require to implement their own resources, methods for registering them with the current transaction. Because TxCore supports subtransactions, if a transaction is begun within the scope of an already executing transaction it will automatically be nested.
Note: TxCore is multi-threaded aware, allowing each thread within an application to share a transaction or execute within its own transaction. Therefore, all TxCore classes are also thread safe.
The simple example below illustrates the relationships between activation, termination and commitment:
{
. . .
O1 objct1 = new objct1(Name-A);/* (i) bind to "old" persistent object
A */
O2 objct2 = new objct2();��� /* create a "new" persistent object */
OTS.current().begin();������ /* (ii) start of atomic action */
objct1.op(...);�� ����� /* (iii) object activation and invocations */
objct2.op(...);
. . .
OTS.current().commit(true); /* (iv) tx commits & objects deactivated */
} ������������ /* (v) */
The execution of the above code involves the following sequence of activities:
1. Creation of bindings to persistent objects; this could involve the creation of stub objects and a call to remote objects. In the above example we re-bind to an existing persistent object identified by Name-A, and a new persistent object. A naming system for remote objects maintains the mapping between object names and locations and is described in a later chapter.
2. Start of the atomic transaction.
3. Operation invocations: as a part of a given invocation the object implementation is responsible to ensure that it is locked in read or write mode (assuming no lock conflict), and initialised, if necessary, with the latest committed state from the object store. The first time a lock is acquired on an object within a transaction the object�s state is acquired, if possible, from the object store.
4. Commit of the top-level action. This includes updating of the state of any modified objects in the object store.
5. Breaking of the previously created bindings.
The principal classes which make up the class hierarchy of TxCore are depicted below.
StateManager�� // Basic naming,
persistence and recovery control
� LockManager���� // Basic two-phase locking concurrency control service
��� User-Defined Classes
� Lock������ // Standard lock type for multiple readers/single writer
��� User-Defined Lock Classes
� AbstractRecord���� // Important utility class, similar to Resource
��� RecoveryRecord�� // handles object recovery
��� LockRecord��� // handles object locking
��� RecordList��� // Intentions list
��� other management record types
AtomicAction�� // Implements transaction control abstraction
� TopLevelTransaction
Input/OutputBuffer // Architecture neutral representation of an objects� state
� Input/OutputObjectState��� // Convenient interface to Buffer
ObjectStore������ // Interface to the object storage services
Figure 3: TXOJ class hierarchy.
Programmers of fault-tolerant applications will be primarily concerned with the classes LockManager, Lock and AtomicAction. Other classes important to a programmer are Uid, and ObjectState. Most TxCore classes are derived from the base class StateManager, which provides primitive facilities necessary for managing persistent and recoverable objects. These facilities include support for the activation and de-activation of objects, and state-based object recovery. The class LockManager uses the facilities of StateManager and Lock to provide the concurrency control (two-phase locking in the current implementation) required for implementing the serialisability property of atomic actions. The implementation of atomic action facilities is supported by AtomicAction and TopLevelTransaction.
Most TxCore system classes are derived from the base class StateManager, which provides primitive facilities necessary for managing persistent and recoverable objects. These facilities include support for the activation and de-activation of objects, and state-based object recovery. The class LockManager uses the facilities of StateManager and provides the concurrency control required for implementing the serialisability property of atomic actions.
Consider a simple example. Assume that Example is a user-defined persistent class suitably derived from the LockManager. An application containing an atomic transaction Trans accesses an object (called O) of type Example by invoking the operation op1 which involves state changes to O. The serialisability property requires that a write lock must be acquired on O before it is modified; thus the body of op1 should contain a call to the setlock operation of the concurrency controller:
public boolean op1 (...)
{
� if (setlock (new Lock(LockMode.WRITE) == LockResult.GRANTED)
� {
���� // actual state change operations follow
���� ...
� }
}
Program 1: Simple Concurrency Control.
The operation setlock, provided by the LockManager class, performs the following functions in this case:
1. Check write lock compatibility with the currently held locks, and if allowed:
2. Call the StateManager operation activate that will load, if not done already, the latest persistent state of O from the object store. Then call the StateManager operation modified which has the effect of creating an instance of either RecoveryRecord or PersistenceRecord for O depending upon whether O was persistent or not (the Lock is a WRITE lock so the old state of the object must be retained prior to modification) and inserting it into the RecordList of Trans.
3. Create and insert a LockRecord instance in the RecordList of Trans.
Now suppose that action Trans is aborted sometime after the lock has been acquired. Then the rollback operation of AtomicAction will process the RecordList instance associated with Trans by invoking an appropriate Abort operation on the various records. The implementation of this operation by the LockRecord class will release the WRITE lock while that of RecoveryRecord/PersistenceRecord �will restore the prior state of O.
It is important to realise that all of the above work is automatically being performed by TxCore on behalf of the application programmer. The programmer need only start the transaction and set an appropriate lock; TxCore and Transactional Objects for Java take care of participant registration, persistence, concurrency control and recovery.
In this section we shall describe TxCore and Transactional Objects for Java in more detail, and show how it can be used to construct transactional applications.
TxCore needs to be able to remember the state of an object for several purposes, including recovery (the state represents some past state of the object), and for persistence (the state represents the final state of an object at application termination). Since all of these requirements require common functionality they are all implemented using the same mechanism - the classes Input/OutputObjectState and Input/OutputBuffer.
OutputBuffer
public class OutputBuffer
{
public OutputBuffer ();
public final synchronized boolean valid ();
public synchronized byte[] buffer();
public synchronized int length ();
� /* pack operations for standard Java types */
public synchronized void packByte (byte b) throws IOException;
public synchronized void packBytes (byte[] b) throws IOException;
public synchronized void packBoolean (boolean b) throws IOException;
public synchronized void packChar (char c) throws IOException;
public synchronized void packShort (short s) throws IOException;
public synchronized void packInt (int i) throws IOExceptio