XA Proposal

Proposal: Replace section A.2 in the Transaction Service specification by the A.2 section below.
 
 

Resolution for issue #3157 (need interoperable XA support):

This proposal defines a standard XA integration and its (quite limited) requirements on PropagationContexts (see A.2.2). Two XA-capable Transaction Service implementations can interoperate and, as the same time, use XA resource managers.

Resolution for issue #3536: OTS interoperability - need for unique branch ids

A.2.2 ensures that the otids/XIDs generated by different XA-capable Transaction Service implementations are distinct.
 
 
 

A.2.1 Introduction

In order to use a transactional system, such as a database system, with the Transaction Service, it is necessary to "hook" the transactions provided by this system and the distributed transactions managed by the Transaction Service.

With the Transaction Service, this is achieved by implementing CosTransactions::Resource objects -- each resource represents a local transaction in the transactional system -- and registering these Resource objects with the distributed transactions.

Since many systems provide a standard interface to their transactional capabilities -- the XA interface -- it is possible to implement CosTransactions::Resource objects on top of the XA interface, and provide an easy to use integration with the Transaction Service. The same integration (with the same interfaces and behavior) may also be provided through proprietary interfaces provided by a given Transaction Service implementation, without the creation and registration of CosTransactions::Resource objects. See Figure 1.
 

Figure 1

The Java Transaction API Specification [JTA] defines the Java equivalent of the XA interface (javax.transaction.xa.XAResource) and a set of local Java interfaces that provide a "higher level" API to the Transaction Service (the interfaces are defined in the javax.transaction package). JTA also specifies the standard integration between the Transaction Service and Resource Managers that implement the Java XAResource interface.

For implementations in Java, JTA when available, is the preferred standard integration API between the Transaction Service and XA Resource Managers. Note, JTA is the standard Transaction Service/XA Resource Manager integration API for implementations in Java compatible with the J2EE platform [J2EE].

This section specifies the interfaces for the standard integration between the Transaction Service and C XA resource managers [1]. Unlike JTA, this section does not define a higher level API to the Transaction Service: it relies directly on the Transaction Service types defined in the CosTransactions module.

This XA integration can be implemented using the standard Transaction Service interfaces; as a result, it may be provided by a Transaction Service vendor, a Resource Manager vendor, or any other third party. Likewise the integration with Resource Managers that implement the Java XAResource interface can be provided by a Transaction Service vendor, a Resource Manager vendor, or any other third party. A compliant Transaction Service implementation may, but does not need to, provide any or both of these standard integrations.
 

A.2.2 XA-compatible Transaction Service

An implementation of the Transaction Service is XA-compatible if it satisfies the following requirements: The standard XA integration described below requires an XA-compatible implementation of the Transaction Service.

A.2.3 XA Overview

XA [XA] specifies a standard C API provided by transactional systems (called Resource Managers in the XA specification) that want to participate in distributed transactions managed by transaction managers developed by other vendors.

XA defines a set of C-function pointers, and a C-struct that holds these function pointers, xa_switch_t:

/*
 *  From Appendix A of the XA specification:
 */

struct xa_switch_t {
 char name[RMNAMESZ];          /* name of resource manager */
 long flags;                   /* resource manager specific options */
 long version;                 /* must be 0 */
 int (*xa_open_entry)          /* xa_open function pointer */
     (char *, int, long);
 int (*xa_close_entry)         /* xa_close function pointer */
     (char *, int, long);
 int (*xa_start_entry)         /* xa_start function pointer */
     (XID *, int, long);
 int (*xa_end_entry)           /* xa_end function pointer */
     (XID *, int, long);
 int (*xa_rollback_entry)      /* xa_rollback function pointer */
     (XID *, int, long);
 int (*xa_prepare_entry)       /* xa_prepare function pointer */
     (XID *, int, long);
 int (*xa_commit_entry)        /* xa_commit function pointer */
     (XID *, int, long);
 int (*xa_recover_entry)       /* xa_recover function pointer */
     (XID *, long, int, long);
 int (*xa_forget_entry)        /* xa_forget function pointer */
     (XID *, int, long);
 int (*xa_complete_entry)      /* xa_complete function pointer */
     (int *, int *, int, long);
};

Each XA-capable system must provide a global instance of xa_switch_t.

The function pointers provided by this xa_switch_t instances can be divided in four categories:

xa_complete() is only used for asynchronous XA, an optional part of XA which is not supported by any popular XA implementation.
 

A.2.4 XA and Multi-Threading

In the XA specification, the scope of an XA connection is called thread of control: each thread-of-control can only use the connections that it has established (using xa_open()).
The XA specification maps thread-of-control to operating system process (see paragraph 2.2.8 in the XA specification), so one would expect that each thread in a process has access to all the XA connections established by this process. This is however not the case: most vendors implement the following: Sun's Java Transaction API  provides a very different thread model: with JTA, every thread can use any connection (XAResource object).

The main drawback of tying connections and threads is flexibility since it prevents the application from managing connections independently of threads, which limits a lot the kind of connection pooling that can be implemented. Also, a CORBA server typically dispatches different requests to different threads: the thread of control equal thread model prevents the use of xa_end(TMSUSPEND) at the end of a request and xa_start(TMRESUME) at the beginning of the next request in the same transaction, since an association must be resumed by the thread of control by which it was suspended.
 

A.2.5 The Standard Integration with C XA Resource Managers

An implementation of the standard Transaction/Service XA integration implements the following three interfaces, defined in the XA module: The XA module defines a fourth interface, BeforeCompletionCallback: it is implemented by applications that want to be notified before the completion of any transaction branch (CosTransactions::Resource) managed by a given ResourceManager.
 

A.2.6 CurrentConnection

The CurrentConnection local interface is defined in the XA module as follows:

typedef short ThreadModel;
const ThreadModel PROCESS = 0;
const ThreadModel THREAD  = 1;

local interface CurrentConnection
{
    void
    start(                                   // xa_start(TMNOFLAGS) or xa_start(TMJOIN)
        in CosTransactions::Coordinator tx,
        in CosTransactions::otid_t      otid
     );

    void
    suspend(                                 // xa_end(TMSUSPEND)
        in CosTransactions::Coordinator tx,
        in CosTransactions::otid_t      otid
    );

    void resume(                             // xa_start(TMRESUME)
        in CosTransactions::Coordinator tx,
        in CosTransactions::otid_t      otid
    );

    void end(                                // xa_end(TMSUCCESS) or xa_end(TMFAIL)
        in CosTransactions::Coordinator tx,
        in CosTransactions::otid_t      otid,
        in boolean                      success
    );

   ThreadModel thread_model();
   long        rmid();

};

The otid_t value cannot be simply extracted from the tx parameter because that would limit the users ability to optimize the calls under some circumstances (for example when using explicit propagation). It also allows to perform some operations (e.g. end) when the coordinator for a transaction is unreachable.

In addition, the user may wish to alter the branch qualifier of the otid to either share the same transaction branch between different processes (tightly-coupled model) or use different transaction branches in processes using the same resource manager within the same distributed transaction (loosely-coupled model).

Figure 2 shows the components involved when the application creates a new association by calling start on a CurrentConnection object:

  1. The application calls start on a CurrentConnection object.
  2. The XA integration calls xa_start(TMNOFLAGS) to create a new transaction branch.
  3. The XA integration creates a Resource object representing this branch, and registers this resource with the transaction coordinator.


Figure 2: Creating a new Association

A.2.7 Association State Diagram

Figure 3 shows the state diagram of an association between a transaction and a XA connection. In this diagram all start, suspend, resume, and end calls are successful (they do not raise any exception).


Figure 3: Association State Diagram

When start, suspend, resume or end raises CORBA::INTERNAL with the minor code (TBD -- XAER_RMFAIL), the new state is "non existent".
When resume, suspend or end raises CORBA::TRANSACTION_ROLLEDBACK with the minor code (TBD -- XA_RB), the new state is "non existent".
When end raises CORBA::TRANSACTION_ROLLEDBACK with the minor code (TBD -- deferred rollback), the new state is "non existent".

For every other exceptions raised by start, suspend, resume and end, there is no state transition.

Note:
The PSS TransactionalSession interface has no resume operation: with PSS, when start is called on a suspended association, the association is resumed. Like PSS, JTA combines start and resume in a single method, Transaction.enlistResource().
Because of the CurrentConnection::resume operation, and implementation of the CurrentConnection local interface does not need to maintain information about the state of the underlying XA connection(s).
 

A.2.8 ResourceManager

The BeforeCompletionCallback and the ResourceManager interfaces are defined in the XA module as follows:

interface BeforeCompletionCallback
{
     void
     before_completion(
         in CosTransactions::Coordinator tx,
         in CosTransactions::otid_t      otid,
         in boolean                      success
     );
};

interface ResourceManager
{
     unsigned long
     register_before_completion_callback(in BeforeCompletionCallback bcc);

     void
     unregister_before_completion_callback(in unsigned long key);
};

A Resource Manager object manages transaction branches. An application can register any number (up to 2^31 -1) of BeforeCompletionCallback objects with a resource manager, to get notified each time a non-preprared transaction branch is about to be prepared, committed-in-one-phase or rolled back.

The only operation on BeforeCompletionCallback, before_completion, accepts the following parameters:

If success is TRUE and before_completion raises any exception, the transaction branch is rolled back.

A typical use of a BeforeCompletionCallback object is to end a suspended association in a single-threaded server, as shown on Figure 4.

An application uses the operation register_before_completion_callback to registers a BeforeCompletionCallback with a ResourceManager. register_before_completion_callback returns an unsigned long that the application uses to unregister a BeforeCompletionCallback object.

Figure 4: Using a BeforeCompletionCallback to End a Suspended Association

Note 1:  The primary advantage of BeforeCompletionCallback objects over CosTransactions::Synchronization objects is the number of  CORBA requests per transaction: three for a synchronization (registration, before_completion, after_completion) versus only one for a BeforeCompletionCallback object.

Note 2: When starting and ending an association for each request, there is no need for any BeforeCompletionCallback object.

Note 3: The interfaces between the CurrentConnection objects, the ResourceManager object and the Resource objects (if there is any) are not specified. The diagram above illustrates a possible implementation. Other implementations are possible: for example a Resource object could register itself with the Transaction Coordinator in its constructor.

A.2.9 Connector

A connector local object is used to create CurrentConnection and ResourceManager objects. The connector itself is obtained by calling resolve_initial_references() on an ORB instance, with the "XAConnector" parameter.

The Connector local interface is defined in the XA module as follows:

native XASwitch;

local interface Connector
{
    ResourceManager
    create_resource_manager(
        in string                      resource_manager_name,
        in XASwitch                    xa_switch,
        in string                      open_string,
        in string                      close_string,
        in ThreadModel                 thread_model,
        in boolean                     automatic_association,
        in boolean                     dynamic_registration_optimization,
        out CurrentConnection          current_connection
    );

    CurrentConnection
    connect_to_resource_manager(
        in ResourceManager          rm,
        in XASwitch                 xa_switch,
        in string                   open_string,
        in string                   close_string,
        in ThreadModel              thread_model,
        in boolean                  automatic_association,
        in boolean                  dynamic_registration_optimization
     );
};
 

A.2.10 Exceptions and Minor Codes

All the operations on the interfaces defined in the XA module can only raise standard exceptions. For portability, the table below defines which exceptions are raised in some circumstances, and the minor code of these exceptions.
 
 
Exception Minor Code Raised By When
BAD_PARAM (TBD) Connector::create_resource_manager,
Connector::connector_to_resource_manager
CurrentConnection::start,
CurrentConnection::suspend,
CurrentConnection::resume,
CurrentConnection::end
A xa_ call returns XAER_INVAL
BAD_INV_ORDER (TBD) CurrentConnection::start A xa_start() call returns XAER_OUTSIDE
BAD_INV_ORDER (TBD) CurrentConnection::start,
CurrentConnection::suspend,
CurrentConnection::resume,
CurrentConnection::end
A xa_ call returns XAER_PROTO
INTERNAL (TBD) Connector::create_resource_manager,
Connector::connector_to_resource_manager
CurrentConnection::start,
CurrentConnection::suspend,
CurrentConnection::resume,
CurrentConnection::end
A xa_ call returns XAER_RMERR
INTERNAL (TBD) CurrentConnection::start,
CurrentConnection::suspend,
CurrentConnection::resume,
CurrentConnection::end
A xa_ calls returns XAER_RMFAIL
TRANSACTION_ROLLEDBACK (TBD) CurrentConnection::start,
CurrentConnection::suspend,
CurrentConnection::resume,
CurrentConnection::end
A xa_ calls returns an XAER_RB error code.
TRANSACTION_ROLLEDBACK (TBD) CurrentConnection::start,
CurrentConnection::suspend,
CurrentConnection::resume,
CurrentConnection::end
A xa_ calls returns XAER_NOTA
TRANSACTION_ROLLEDBACK (TBD) CurrentConnection::end In some circumstances, the XA integration may defer the rollback of a transaction branch until an association with this branch is ended. When this occurs and end is called with success set to TRUE, end raises TRANSACTION_ROLLEDBACK with the (TBD -- deferred rollback) minor code.
Table 1: Exceptions and Minor Codes

A.2.11 Comparison with the Java Transaction API (JTA)

The following informational tables show the correspondance between the Transaction/XA integration IDL interfaces and some JTA interfaces, the XA C function pointers and JTA XAResource methods, and between the OMG Transaction Service IDL interfaces and JTA's transaction manager interfaces.
 
OTS/XA integration JTA
CurrentConnection::start(Coordinator, otid_t) Transaction.enlistResource(XAResource)
CurrentConnection::suspend(Coordinator, otid_t) Transaction.delistResource(XAResource, TMSUSPEND)
CurrentConnection::resume(Coordinator, otid_t) Transaction.enlistResource(XAResource)
CurrentConnection::end(Coordinator, otid_t, boolean) Transaction.delistResource(XAResource, TMSUCCESS)
or Transaction.delistResource(XAResource, TMFAIL)
ResourceManager no equivalent
BeforeCompletionCallback no equivalent
CurrentConnection no equivalent, although the notion of XA connection is the same in the OTS/XA integration and in JTA.
Connector no equivalent
Automatic association no equivalent
Table 2: Comparing the OTS/XA integration with JTA


XA JTA
A xa_switch_t object A transactional resource factory
An opened rmid A XAResource object
xa_open_entry(char *, int, long) no equivalent -- JTA does not standardize an API to open or close XA connections
xa_close_entry(char *, int, long) no equivalent
xa_start_entry(XID *, int, long) XAResource.start(Xid, int)
xa_end_entry(XID *, int, long) XAResource.end(Xid, int)
xa_rollback_entry(XID *, int, long) XAResource.rollback(Xid, int)
xa_prepare(XID *, int, long) XAResource.prepare(Xid, int)
xa_commit(XID *, int, long) XAResource.commit(Xid, int)
xa_recover(XID *, long, int, long) XAResource.recover(int)
xa_forget(XID *, int, long) XAResource.forget(Xid, int)
xa_complete(int *, int *, int, long); no equivalent
no equivalent XAResource.getTransactionTimeout()
no equivalent XAResource.isSameRM(XAResource)
no equivalent XAResource.setTransactionTimeout(int)

Table 3: Comparing XA with JTA


Transaction Service JTA
Current TransactionManager, UserTransaction
Synchronization Synchronization
Control/Coordinator/Terminator Transaction
Current::begin() TransactionManager.begin(), UserTransaction.begin()
Current::commit() TransactionManager.commit(), UserTransaction.commit()
Current::rollback() TransactionManager.rollback(), UserTransaction.rollback()
Current::rollback_only() TransactionManager.setRollbackOnly(), UserTransaction.setRollbackOnly()
Current::get_status() TransactionManager.getStatus(), UserTransaction.getStatus()
Current::get_transaction_name() TransactionManager.toString(), UserTransaction.toString()
Current::set_timeout() TransactionManager.setTransactionTimeout()
Current::get_control() TransactionManager.getTransaction()
Current::suspend() TransactionManager.suspend()
Current::resume() TransactionManager.resume()
Coordinator::get_status() Transaction.getStatus()
Coordinator::is_same_transaction() Transaction.equals() ?
Coordinator::hash_transaction() Transaction.hashCode() ?
Coordinator::register_synchronization() Transaction.registerSynchronization()
Coordinator::rollback_only() Transaction.setRollbackOnly()
Terminator::commit() Transaction.commit()
Terminator::rollback() Transaction.rollback()
Other Coordinator operations no equivalent

Table 4: Comparing the Transaction Service with JTA

A.2.12 XA Module

#ifndef _XA_IDL_
#define _XA_IDL_

#include <CosTransactions.idl>
#pragma prefix "omg.org"

module XA
{
    native XASwitch;

    typedef short ThreadModel;
    const ThreadModel PROCESS = 0;
    const ThreadModel THREAD  = 1;

    local interface CurrentConnection
    {
        void
        start(                                   // xa_start(TMNOFLAGS) or xa_start(TMJOIN)
             in CosTransactions::Coordinator tx,
             in CosTransactions::otid_t      otid
        );

        void
        suspend(                                 // xa_end(TMSUSPEND)
             in CosTransactions::Coordinator tx,
             in CosTransactions::otid_t      otid
        );

        void resume(                             // xa_start(TMRESUME)
             in CosTransactions::Coordinator tx,
             in CosTransactions::otid_t      otid
        );

        void end(                                // xa_end(TMSUCCESS) or xa_end(TMFAIL)
             in CosTransactions::Coordinator tx,
             in CosTransactions::otid_t      otid,
             in boolean                      success
        );

        ThreadModel thread_model();
        long        rmid();

    };

    interface BeforeCompletionCallback
    {
        void
        before_completion(
            in CosTransactions::Coordinator tx,
            in CosTransactions::otid_t      otid,
            in boolean                      success
        );
    };

    interface ResourceManager
    {
        unsigned long
        register_before_completion_callback(in BeforeCompletionCallback bcc);

        void
        unregister_before_completion_callback(in unsigned long key);
    };
 

    local interface Connector
    {
        ResourceManager
        create_resource_manager(
            in string                      resource_manager_name,
            in XASwitch                    xa_switch,
            in string                      open_string,
            in string                      close_string,
            in ThreadModel                 thread_model,
            in boolean                     automatic_association,
            in boolean                     dynamic_registration_optimization,
            out CurrentConnection          current_connection
        );

        CurrentConnection
        connect_to_resource_manager(
            in ResourceManager             rm,
            in XASwitch                    xa_switch,
            in string                      open_string,
            in string                      close_string,
            in ThreadModel                 thread_model,
            in boolean                     automatic_association,
            in boolean                     dynamic_registration_optimization
        );
    };
};

#endif  /*!_XA_IDL_*/
 
 

A.2.13 References

[J2EE]  Java 2 Platform Enterprise Edition (J2EE), Platform specification: http://java.sun.com/j2ee
[JTA]   Java Transaction API (JTA): http://java.sun.com/jta
[XA]    Open Group Technical Standard, Distributed TP: The XA Specification, February 1991, ISBN: 1 872630 24 3
 

Footnotes:

[1] This integration with C XA resource managers is briefly described in Sun's Java Transaction Service specification (http://java.sun.com/products/jts), "3.3 Support for pre-JTA Resource Managers".

[2] 0 is reserved for OSI CCR naming. -1 means the XID is null.

[3] Mappings for other languages that interface with C, for example Ada and Java, could be defined as well.
For Java, it is expected that JTA-compliant XAResource implementations will be much more common than C xa_switch_t structs wrapped using JNI.