Performing XA Transaction Operations

Once an XA Session is established, an XA Resource for that XA Session must be obtained to create and manage transaction branches (refer to Obtaining XA Resources).

The XA Resource interface defines the contract between a Resource Manager and a Transaction Manager in a distributed transaction processing (DTP) environment and the methods it offers allows the Transaction Manager to manage a transaction branch and control its state.

The event broker, acting as the Resource Manager, will perform the work that is requested for a transaction branch on behalf of the Transaction Manager. The Resource Manager is responsible for associating all work performed on its data between the start and end method invocations with the global transaction.

Xids

The XA Resource uses Xids to identify each transaction branch. These Xids must be unique within a Message VPN.

An Xid is comprised of a global transaction ID (an array of 1 to 64 bytes) that identifies the global transaction that the transaction will be a part of, and a global transaction format ID (an array of 4 bytes), and a branch qualifier ID (an array of 1 to 64 bytes) that uniquely identifies the transaction branch. The Xid consists of all three fields separated by a “-” characters:

<format-id>-<global-transaction-id>-<branch-qualifier>

Each field is displayed in ASCII hex format with two ASCII characters per byte in the array. The number of ASCII hex characters implies the length of the array. The XID can be up to 266 characters long.

The following are examples of Xids that may display in the Solace CLI output:

01020304-0123456789ABCDEF-01
00020304-01-02
02030405-00-03
09ABCDEF-0000-04
01020304-000000-05

The combination of the global transaction identifier and branch qualifier must be globally unique for each Xid, although the format ID is often zero, which indicates that the OSI CCR (Open Systems Interconnection Commitment, Concurrency, and Recovery) standard is used for naming.

The javax.transaction.xa.Xid interface is used by Java applications using XA transactions. Typically, the Xid interface is used by a Transaction Manager to coordinate with a Resource Manager (the event broker acts as a Resource Manager). However, an implementation of this interface (com.solacesystems.common.xa.SolXid) is provided with the Solace JMS package for the convenience of programmers who may be developing XA applications without an application server.

Transaction States

The operations that can be performed through the XAResource for a transaction, and the sequence in which those operations can occur, is determined by the current state of the transaction branch. The table below lists the states that a transaction branch may have depending on the XA requests that were performed on it.

Possible Transaction States

Transaction State Description

Active

The transaction is associated to an XA session. In all states other than Active, the transaction is not associated to an XA Session. A transaction has an active state after it is successfully created through a call to XAResource.start(...). A transaction with an active state will persist as long as the XA Session is open.

Idle

The transaction is not associated to the XA session and will be rolled back if not prepared, committed, or rolled back within the idle timeout period. A transaction has an Idle state after it has been successfully ended through a call to XAResource.end(...).

Prepared

The transaction is prepared and ready for a commit or roll back request. A transaction has a prepared state of a transaction after it is successfully prepared through a call to XAResource.prepare(...).

Heuristically Completed

The transaction is heuristically completed and either successfully committed or rolled back. A transaction has a Heuristically Completed state after an administrator has successfully heuristically committed or rolled back the transaction. A Heuristically Completed transaction will persist until it is deleted through a call to XAResource.forget(...) or the transaction is heuristically deleted by an administrator through the Solace CLI or SolAdmin.

Free

The transaction is not allocated.

The table below indicates the state that a transaction must have when a particular XAResource request is made and the state that the transaction will have after the request is made.

A transaction state will only change when all of the required processing is complete. For example, when an XA Prepare request is made, the transaction state will remain in the Idle state until all of the operations required in the transaction are performed and the prepare request is completed successfully. Alternatively, if the prepare fails, the transaction is rolled back and thus never transitions into the Prepared state. For more information, refer to Preparing Transactions.

XA Requests and Related Transaction States

XA request Can be invoked when transaction has a state of Transaction state after successful Invocation...

XAResource.start with TMNOFLAG

Free

Active

XAResource.start with TMNORESUME

Idle (suspended)

Active

XAResource.end with TMFAIL

Active or Idle

Idle (rollback only)

XAResource.end with TMSUCCESS

Active or Idle

Idle

XAResource.end with TMSUSPEND

Active

Idle (suspended)

XAResource.prepare

Idle

Prepared

XAResource.commit

Prepared

Free

XAResource.commit with onePhase

Idle

Free

XAResource.rollback

Active, Idle, or Prepared

Free

Obtaining XA Resources

To obtain an XA Resource to use for an XA Session, call XASession.getXAResource().

By default, the transaction timeout value used by the Resource Manager for XA Resources is 180 seconds. To set a transaction timeout value (in seconds) for the obtained XAResource instance, call XAResource.setTransactionTimeout(int seconds) and pass in a value for the number of seconds. To reset the timeout value to the default value used by the resource manager, set the value to zero.

The following primary operations can be performed with an obtained XA Resource:

Starting Transactions

To associate a transaction branch with the resource, and start work on behalf of a transaction branch specified in Xid, the XAResource.start(Xid xid, int flags) method must be called.

Up to 256 messages can be tracked within a transaction branch. These include published messages to be added to endpoints, and/or messages spooled on endpoints that are to be consumed and removed from those endpoints.

To start a transaction, call the following method:

XAResource.start(Xid xid, int flags)

Where:

xid is the Xid for the transaction.

flags is one of the following:

  • TMNOFLAGS—indicates that the transaction is a new transaction that is to be started. The XID must be unique in the Message VPN and the transaction must not already be associated with an XA Session, otherwise the request is rejected.
  • TMRESUME—indicates that the transaction is a suspended transaction that is to be resumed. The XID must be in the association suspended state, otherwise the request is rejected.

The Solace JMS implementation does not support the TMJOIN flag, which indicates that the work to be performed is to be added to another, pre‑existing transaction.

When start(...) is successfully invoked, an association is created between the XA Session and the transaction branch, and the transaction branch has an Active state.

Only one distributed transaction can be associated with an XA Session at a time.

Ending Transactions

An XA End request is used to end or suspend the work being performed for a transaction branch that has an Active state. When this method is invoked, an XA End request is sent to the Resource Manager (that is, the event broker) to:

  • associate the published and consumed messages with the transaction branch identified by the given Xid;
  • disassociate the XA resource from that transaction branch;
  • then let the transaction complete.

To end or suspend the work being performed for a transaction branch that has an Active state, call the following method:

XAResource.end(Xid xid,int flags)

Where:

xid is the Xid for the transaction.

flags is one of the following:

  • TMSUCCESS—indicates that the portion of work in the transaction is completed successfully
  • TMSUSPEND—indicates that the transaction is temporarily suspended in an incomplete state
  • TMFAIL—indicates that the portion of work in the transaction has failed

When end(...) is successfully invoked on an active transaction branch, the result depends on the flag that was set for the method:

  • TMSUCCESS flag—The transaction’s state is changed to Idle (if the transaction remains idle for longer than the idle-timeout value set for the XAResource, the transaction is automatically rolled back). The transaction can then be prepared for a two-phase commit, rolled back, or committed through a one-phase commit.
  • TMSUSPEND flag—The transaction’s state is changed to Idle. The association between the transaction branch and the XA Session is changed from Associated to Association-Suspended.
  • TMFAIL flag—The transaction’s state is changed to Idle, marked as rollback only, and can only be rolled back to be freed.

When the TMSUCCESS and TMSUSPEND flags are set, if the endpoint for subscriber messages is shutdown or deleted, or if the messages to be consumed have already been consumed or re-delivered on a different flow, before the XA End request was made, the request will fail. When an XA End request fails, the transaction is put into an Idle state and marked as Rollback‑only—it can only be rolled back to be freed.

When end(...) is not successfully invoked, the transaction is automatically rolled back, and an XA_RBROLLBACK response is returned to the client API.

Preparing Transactions

A transaction branch that has been ended and has an Idle state must be prepared before it can be committed through a two-phase commit.

To prepare an idle transaction for a commit, call the following method:

XAResource.prepare (Xid xid)

Where:

xid is the Xid for the transaction.

When the XA prepare call is made, the event broker validates the request and then processes the list of messages assigned to the transaction, and the result of the request is sent to the client in a response message (for example, XA_OK or XA_RBROLLBACK).

When prepare(...) is successfully invoked, the transaction’s state is changed to Prepared, and the XA Session and the transaction are no longer associated. A transaction that is successfully prepared has a high probability of being successfully committed.

When prepare(...) is not successfully invoked, an XAException is thrown, and the transaction is automatically rolled back and freed.

For a scenario where there are no other resources involved in the distributed transaction, only a one-phase commit is required and the client does not have to call XAResource.prepare(...). In such a case, the client can just call commit(...) with the onePhase flag set to true.

When an XA prepare is performed and an endpoint that messages in the transaction branch are to be consumed from or published to has been shut down, is over its message quota, or has been deleted, the following occurs:

  • If an endpoint that messages in the transaction branch are to be consumed from is shutdown, deleted, or over its message quota when an XA prepare call is made, the transaction will fail and be rolled back.
  • If an endpoint that messages in the transaction branch are to published to or consumed from has been deleted before an XA prepare call is made, the prepare will fail and the transaction is rolled back.
  • If an endpoint that messages in the transaction branch are to published to is shutdown or over its message quota when an XA prepare call is made, the following occurs:
    • If the reject‑to‑sender‑on‑discard parameter is enabled for the endpoint (this is the default setting), transaction will fail and be rolled back.
    • If the reject‑to‑sender‑on‑discard parameter is not enabled for the endpoint, the prepare will succeed, but when commit is called, the messages will not be added to the endpoint.

When doing the quota checking for an XA Prepare request, the checking accounts for all of the messages in the transaction, but it does not account for any messages in other prepared transactions.

Completing or Canceling Transactions

Messages that are published or received through an XA transaction are staged on the event broker. The transaction can either be:

  • completed through a commit operation.
  • canceled through a rollback operation

Committing Transactions

To commit a transaction, call the following method:

XAResource.commit(Xid xid, boolean onePhase)

Where:

xid is the Xid for the transaction.

onePhase is a flag that indicates whether the Resource Manager should use a one‑phase commit protocol to commit the work done on behalf of Xid. If true, the Resource Manager must use a one-phase commit protocol to commit the work done on behalf of the Xid. If false, the Resource Manager must use a two-phase commit protocol to commit the work done on behalf of the Xid.

A transaction branch can only be committed if it has an Idle state (a one-phase commit is required) or Prepared state (a two-phase commit is required).

When a transaction branch is successfully committed, the following occurs:

  • For publish operations, the staged messages are sent to their destination queue or topic (that is, a durable topic endpoint).
  • For receive operations, the received messages are acknowledged by the consumers and then removed from the endpoints they were spooled to.
  • The transaction’s state is changed to Free.

Commits are blocking operations. A new transaction cannot be started until the current transaction is freed through a successful commit or is rolled back or suspended.

The result of the commit is sent to the client API in a response message. If a commit fails for any reason, a rollback of the entire transaction occurs. An XAException is thrown to indicate the failure reason.

When a commit is performed and an endpoint that messages in the transaction branch are to be published to is shut down or deleted, the following occurs:

  • For a one-phase commit:
    • When an endpoint is shutdown: The transaction is rolled back if the endpoint is configured for reject-to-sender-on-discard. If reject‑to‑sender‑on‑discard is not enabled then the commit succeeds but the message is not added to the endpoint.
    • When an endpoint is deleted: The commit fails and the transaction is rolled back.
    • If the commit fails, the Resource Manager may throw an XA_RB* exception. In this case, the Resource Manager rolls back the branch’s work and releases all held resources.
  • For a two-phase commit:
    • When an endpoint is shutdown: The commit succeeds but the message is not added to the endpoint.
    • When an endpoint is deleted: The commit succeeds.

Rolling Back Transactions

Instead of completing an active transaction through a commit, a client can call XAResource.rollback() to rollback a transaction that has an Active, Idle, or Prepared state.

When a rollback is performed, staging information for the active transaction is removed, therefore:

  • for publish operations, the publisher messages are deleted from the message spool and are not spooled on the destination endpoints, and the transaction is freed.
  • for consume operations, the messages assigned to the transaction remain spooled on the endpoints, they are redelivered, and the transaction is freed.

Rollbacks are blocking operations.

When rollback(...) is successfully invoked, the transaction’s state is changed to Free.

If a transacted Session fails due to a network failure or an event broker reset, the client can immediately reconnect (this is automatic if the number of reconnect retries for the client connection is greater than zero), and, if possible, the API reestablishes the transaction that was in progress. If the Session and transaction are not reestablished within three minutes, the event broker automatically rolls back the transaction that was in progress. (For information on setting client reconnect properties, refer to Configuring Connection Time-Outs and Retries.)

Deleting Heuristically-Completed Transaction Branches

If you want to delete a transaction branch that was heuristically completed by an event broker administrator, an XAForget request can be performed. This request can only be performed successfully if the transaction has been heuristically committed or rolled back, and the transaction is freed.

To delete a heuristically-completed transaction branch, call the following method:

XAResource.forget(Xid xid)

Where:

xid is the Xid for the transaction.

For information on the heuristic operations available to event broker administrators, refer to Performing Heuristic Actions on Transactions.

Recovering Prepared Transactions

If an Application Server failure occurs, you can use the XAResource.recover(…) method to ask the event broker to return those transaction branches that are in a prepared or heuristically completed state.

XAResource.recover (int flags)

Where:

flags is one of the following:

  • TMSTARTRSCAN—starts a recovery scan.
  • TMENDRSCAN—ends a recovery scan.
  • TMNOFLAGS—indicates no flags value is selected. TMNOFLAGS must be used when no other flags are set in the parameter.