JBoss.orgCommunity Documentation
Atomic actions (transactions) can be used by both application programmers and class developers. Thus entire operations (or parts of operations) can be made atomic as required by the semantics of a particular operation. This chapter will describe some of the more subtle issues involved with using transactions in general and TxCore in particular.
In a multi-threaded application, multiple threads may be associated with a transaction during its lifetime, sharing the context. In addition, it is possible that if one thread terminates a transaction, other threads may still be active within it. In a distributed environment, it can be difficult to guarantee that all threads have finished with a transaction when it is terminated. By default, TxCore will issue a warning if a thread terminates a transaction when other threads are still active within it. However, it will allow the transaction termination to continue.
Other solutions to this problem are possible. One example would be to block the thread which
is terminating the
transaction until all other threads have disassociated themselves from the
transaction context. Therefore, TxCore
provides the
com.arjuna.ats.arjuna.coordinator.CheckedAction
class, which allows the thread
or transaction termination policy to be overridden. Each
transaction has an instance of this class associated with
it, and application programmers can
provide their own implementations on a per transaction basis.
Example 4.1.
Class
CheckedAction
public class CheckedAction
{
public synchronized void check (boolean isCommit, Uid actUid,
BasicList list);
};
When a thread attempts to terminate the transaction and there are active threads within it,
the system will invoke
the
check
method on the transaction’s
CheckedAction
object. The
parameters to the check method are:
Indicates whether the transaction is in the process of committing or rolling back.
The transaction identifier.
A list of all of the threads currently marked as active within this transaction.
When
check
returns, the transaction termination will continue. Obviously the state of the
transaction at
this point may be different from that when
check
was called, e.g., the
transaction may subsequently have been committed.
A
CheckedAction
instance is created for each transaction. As mentioned above, the default
implementation
simply
issues warnings in the presence of multiple threads active on the transaction when it
is
terminated. However, a different instance can be provided to each transaction in one of
the
following ways:
Use the
setCheckedAction
method on the
BasicAction
instance.
Define an implementation of the
CheckedActionFactory
interface, which has a
single method
getCheckedAction
(
final Uid
txId
,
final String
actionType
) that returns a
CheckedAction
. The factory class name can then be provided to the Transaction Service
at runtime by
setting the
CoordinatorEnvironmentBean.checkedActionFactory
property.
By default, the Transaction Service does not maintain any history information about
transactions. However, by
setting the
CoordinatorEnvironmentBean.enableStatistics
property variable to
YES
, the transaction service will maintain information about the number of transactions
created,
and their outcomes. This information can be obtained during the execution of a
transactional
application
via the
com.arjuna.ats.arjuna.coordinator.TxStats
class.
Example 4.2.
Class
TxStats
public class TxStats
{
/**
* @return the number of transactions (top-level and nested) created so far.
*/
public static int numberOfTransactions();
/**
* @return the number of nested (sub) transactions created so far.
*
public static int numberOfNestedTransactions();
/**
* @return the number of transactions which have terminated with heuristic
* outcomes.
*/
public static int numberOfHeuristics();
/**
* @return the number of committed transactions.
*/
public static int numberOfCommittedTransactions();
/**
* @return the total number of transactions which have rolled back.
*/
public static int numberOfAbortedTransactions();
/**
* @return total number of inflight (active) transactions.
*/
public static int numberOfInflightTransactions ();
/**
* @return total number of transactions rolled back due to timeout.
*/
public static int numberOfTimedOutTransactions ();
/**
* @return the number of transactions rolled back by the application.
*/
public static int numberOfApplicationRollbacks ();
/**
* @return number of transactions rolled back by participants.
*/
public static int numberOfResourceRollbacks ();
/**
* Print the current information.
*/
public static void printStatus(java.io.PrintWriter pw);
}
The class
ActionManager
gives further information about specific active transactions
through the classes
getTimeAdded
, which returns the time (in milliseconds) when the
transaction was created, and
inflightTransactions
, which returns the list of currently
active transactions.
By default, the Transaction Service executes the
commit
protocol of a top-level
transaction in a synchronous manner. All registered resources will be
told to prepare in order by a single thread,
and then they will be told to commit or
rollback.
This has several possible disadvantages:
In the case of many registered resources, the
prepare
operating can logically be
invoked in parallel on each resource. The disadvantage is that
if an “early” resource in the list of
registered resource forces a rollback during
prepare
, possibly many prepare
operations will have been made needlessly.
In the case where heuristic reporting is not required by the application, the second phase of the commit protocol can be done asynchronously, since its success or failure is not important.
Therefore, JBoss Transactions provides runtime options to enable possible threading
optimizations. By
setting the
CoordinatorEnvironmentBean.asyncPrepare
environment variable to
YES
, during the
prepare
phase a separate thread will be created for
each registered participant within the
transaction.
By setting
CoordinatorEnvironmentBean.asyncCommit
to
YES
, a separate thread will be
created to complete the second phase of the transaction if
knowledge about heuristics outcomes is not required.
JBoss Transactions supports a number of different transaction log implementations. They are outlined below.
This is the original version of the transaction log as provided in prior releases. It is simple but slow. Each transaction has an instance of its own log and they are all written to the same location in the file system
This implementation is based on the ActionStore but the individual logs are striped across a number of sub-directories to improve performance. Check the Configuration Options table for how to configure the HashedActionStore.
This implementation is based on a traditional transaction log. All transaction states within the same process (VM instance) are written to the same log (file), which is an append-only entity. When transaction data would normally be deleted, e.g., at the end of the transaction, a delete record is added to the log instead. Therefore, the log just keeps growing. Periodically a thread runs to prune the log of entries that have been deleted.
A log is initially given a maximum capacity beyond which it cannot grow. Once this is reached the system will create a new log for transactions that could not be accommodated in the original log. The new log and the old log are pruned as usual. During the normal execution of the transaction system there may be an arbitrary number of log instances. These should be garbage collected by the system (or the recovery sub-system) eventually.
Check the Configuration Options table for how to configure the LogStore.