6 Distributed Transaction Processing: XA

This chapter describes the TimesTen implementation of the X/Open XA standard.

The TimesTen implementation of the XA interfaces is intended for use by transaction managers in distributed transaction processing (DTP) environments. You can use these interfaces to write a new transaction manager or to adapt an existing transaction manager, such as Oracle Tuxedo, to operate with TimesTen resource managers.

The purpose of this chapter is to provide information specific to the TimesTen implementation of XA and is intended to be used with the following documents:

This chapter includes the following topics:

Important:

  • The TimesTen XA implementation does not work with TimesTen Cache. The start of any XA transaction fails if the cache agent is running.

  • You cannot execute an XA transaction if replication is enabled.

  • Do not execute DDL statements within an XA transaction.

Overview of XA

This section provides a brief overview of the following XA concepts:

X/Open DTP model

Figure 6-1 that follows illustrates the interfaces defined by the X/Open DTP model.

Figure 6-1 Distributed transaction processing model

Description of Figure 6-1 follows
Description of "Figure 6-1 Distributed transaction processing model"

The TX interface is what applications use to communicate with a transaction manager. The figure shows an application communicating global transactions to the transaction manager. In the DTP model, the transaction manager breaks each global transaction down into multiple branches and distributes them to separate resource managers for service. It uses the XA interface to coordinate each transaction branch with the appropriate resource manager.

In the context of TimesTen XA, the resource managers can be a collection of TimesTen databases, or databases in combination with other commercial databases that support XA.

Global transaction control provided by the TX and XA interfaces is distinct from local transaction control provided by the native ODBC interface. It is generally best to maintain separate connections for local and global transactions. Applications can obtain a connection handle to a TimesTen resource manager in order to initiate both local and global transactions over the same connection. See "TimesTen tt_xa_context function to obtain ODBC handle from XA connection" for more information.

Two-phase commit

In an XA implementation, the transaction manager commits the distributed branches of a global transaction by using a two-phase commit protocol.

  1. In phase one, the transaction manager directs each resource manager to prepare to commit, which is to verify and guarantee it can commit its respective branch of the global transaction. If a resource manager cannot commit its branch, the transaction manager rolls back the entire transaction in phase two.

  2. In phase two, the transaction manager either directs each resource manager to commit its branch or, if a resource manager reported it was unable to commit in phase one, rolls back the global transaction.

Note the following optimizations:

  • If a global transaction is determined by the transaction manager to have involved only one branch, it skips phase one and commits the transaction in phase two.

  • If a global transaction branch is read-only, where it does not generate any transaction log records, the transaction manager commits the branch in phase one and skips phase two for that branch.

Note:

The transaction manager considers the global transaction committed if and only if all branches successfully commit.

Using XA in TimesTen

The TimesTen implementation of XA provides an API that is consistent with the API specified in Distributed Transaction Processing: The XA Specification. This section describes what you should know when using the TimesTen implementation of XA, covering the following topics:

TimesTen database requirements for XA

To guarantee global transaction consistency, TimesTen XA transaction branches must be durable. The TimesTen implementation of the xa_prepare(), xa_rollback(), and xa_commit() functions log their actions to disk, regardless of the value set in the DurableCommits general connection attribute or by the ttDurableCommit built-in procedure. (The behavior is equivalent to what occurs with a setting of DurableCommits=1. See "DurableCommits" in Oracle TimesTen In-Memory Database Reference for related information.) If you must recover from a failure, both the resource manager and the TimesTen transaction manager have a consistent view of which transaction branches were active in a prepared state at the time of failure.

Global transaction recovery in TimesTen

When a database is loaded from disk to recover after a failure or unexpected termination, any global transactions that were prepared but not committed are left pending, or in doubt. Normal processing is not enabled until the disposition of all in-doubt transactions has been resolved.

After connection and recovery are complete, TimesTen checks for in-doubt transactions. If there are no in-doubt transactions, operation proceeds as normal. If there are in-doubt transactions, other connections may be created, but virtually all operations are prohibited on those connections until the in-doubt transactions are resolved. Any other ODBC or JDBC calls result in the following error:

Error 11035 - "In-doubt transactions awaiting resolution in recovery must be 
resolved first"

The list of in-doubt transactions can be retrieved through the XA implementation of xa_recover(), then dealt with through the XA call xa_commit(), xa_rollback(), or xa_forget(), as appropriate. After all of the in-doubt transactions are cleared, operation proceeds normally.

This scheme should be adequate for systems that operate strictly under control of the transaction manager, since the first thing the transaction manager should do after connect is to call xa_recover().

If the transaction manager is unavailable or cannot resolve an in-doubt transaction, you can use the ttXactAdmin utility -HCommit or -HAbort option to independently commit or abort the individual transaction branches. Be aware, however, that these ttXactAdmin options require ADMIN privilege. See "ttXactAdmin" in Oracle TimesTen In-Memory Database Reference.

Considerations in using standard XA functions with TimesTen

This section describes some issues concerning the use of TimesTen XA functions, which are of interest if you are writing your own transaction manager.

xa_open()

The xa_info string used by xa_open() should be a connection string identical to that supplied to SQLDriverConnect, such as:

"DSN=DataStoreResource;UID=MyName"

XA limits the length of the string to 256 characters. See MAXINFOSIZE in the xa.h header file.

The xa_open() function automatically turns off autocommit when it opens an XA connection.

A connection opened with xa_open() must be closed with a call to xa_close().

Note:

Any user, other than the instance administrator, who wishes to connect to TimesTen must be granted the CREATE SESSION privilege. Refer to "Access control for connections".

xa_close()

The xa_info string used by xa_close() should be empty.

Transaction id (XID) parameter

XA uniquely identifies global transactions by using a transaction ID, referred to as an XID. The XID is a required parameter for XA functions that manipulate a transaction. Internally, TimesTen maps XIDs to its own transaction identifiers.

The XID defined by the XA standard has some of its members (such as formatID, gtrid_length, and bqual_length) defined as type long. Be aware that this can cause problems when 32-bit client applications connect to a 64-bit server, or 64-bit client applications connect to a 32-bit server. This is because long is a 32-bit integer on 32-bit platforms but a 64-bit integer on 64-bit platforms, other than 64-bit Windows. Hence, TimesTen internally uses only the 32 least significant bits of those XID members regardless of the platform type of client or server. TimesTen does not support any value in those XID members that does not fit in a 32-bit integer.

TimesTen tt_xa_context function to obtain ODBC handle from XA connection

TimesTen provides the function tt_xa_context(), which enables you to acquire the ODBC connection handle associated with an XA connection opened by xa_open().

Syntax

#include <tt_xa.h>
int tt_xa_context(int* rmid, SQLHENV* henv, SQLHDBC* hdbc);

Parameters

Parameter Type Description
rmid int The specified resource manager ID

If this is non-null, the function returns the handles associated with the rmid value.

If the specified rmid is null, the function returns the handles associated with the first connection on this thread. For example, specify a null value if the connection has been opened outside the scope of the user-written code, where rmid is unknown. This establishes context in the application environment.

henv out SQLHENV The environment handle associated with the current xa_open() context
hdbc out SQLHDBC The connection handle associated with the current xa_open() context

Return values

0: Success

1: rmid not found

-1: Invalid parameter

Example

In the following example, assume Tuxedo has used xa_open() and xa_start() to open a connection to the database and start a transaction. To do further ODBC processing on the connection, use the tt_xa_context() function to locate the SQLHENV and SQLHDBC handles allocated by xa_open().

Example 6-1 Using tt_xa_context() to locate handles

do_insert()
{

    SQLHENV henv;
    SQLHDBC hdbc;
    SQLHSTMT hstmt;

    /* retrieve the handles for the current connection */
    tt_xa_context(NULL, &henv, &hdbc);

    /* now we can do our ODBC programming as usual */
    SQLAllocStmt(hdbc, &hstmt);

    SQLExecDirect(hstmt, "insert into t1 values (1)", SQL_NTS);

    SQLFreeStmt(hstmt, SQL_DROP);
}

Considerations in calling ODBC functions over XA connections in TimesTen

This section describes some TimesTen issues to be aware of when calling ODBC functions using an ODBC handle associated with an XA connection opened by xa_open().

Autocommit

To simplify operation and prevent possible contradictions, xa_open() automatically turns off autocommit when it opens an XA connection.

Autocommit may subsequently be turned on or off during local transaction work, but must be turned off before xa_start() is called to begin work on a global transaction branch. If autocommit is on, a call to xa_start() returns the following error:

Error 11030 - "Autocommit must be turned off when working on global (XA) transactions"

Once xa_start() has been called to begin work on a global transaction branch, autocommit may not be turned on until such work has been completed through a call to xa_end(). Any attempt to turn on autocommit in this case results in the same error as above.

Local transaction COMMIT and ROLLBACK

Once work on a global transaction branch has commenced through a call to xa_start(), attempts to perform a local commit or rollback using SQLTransact results in the following error:

Error 11031 - "Illegal combination of local transaction and global (XA) transaction"

Closing open cursors

Any open statement cursors must be closed using SQLFreeStmt with a value of SQL_CLOSE before calling xa_end() to end work on a global transaction branch. Otherwise, the following error is returned:

Error 11032 - "XA request failed due to open cursors"

XA resource manager switch

Each resource manager defines a switch in its xa.h header file that provides the transaction manager with access to the XA functions in the resource managers. The transaction manager never directly calls an XA interface function. Instead, it calls the function in the switch table, which, in turn, points to the appropriate function in the resource manager. This enables resource managers to be added and removed without the requirement to recompile the applications.

In the TimesTen implementation of XA, the functions in the XA switch, xa_switch_t, point to their respective functions defined in a TimesTen switch, tt_xa_switch.

xa_switch_t

The xa_switch_t structure defined by the XA specification is as follows:

/* XA Switch Data Structure */
#define RMNAMESZ       32         /* length of resource manager name, */
                                  /* including the null terminator */
#define MAXINFOSIZE    256        /* maximum size in bytes of xa_info strings, */
                                  /* including the null terminator */

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)(char*, int, long);        /* xa_open function pointer */
int (*xa_close_entry)(char*, int, long);       /* xa_close function pointer*/
int (*xa_start_entry)(XID*, int, long);        /* xa_start function pointer */
int (*xa_end_entry)(XID*, int, long);          /* xa_end function pointer */
int (*xa_rollback_entry)(XID*, int, long);     /* xa_rollback function pointer */
int (*xa_prepare_entry)(XID*, int, long);      /* xa_prepare function pointer */
int (*xa_commit_entry)(XID*, int, long);       /* xa_commit function pointer */
int (*xa_recover_entry)(XID*, long, int, long); /* xa_recover function pointer*/
int (*xa_forget_entry)(XID*, int, long);        /* xa_forget function pointer */
int (*xa_complete_entry)(int*, int*, int, long); /* xa_complete function pointer */
};

typedef struct xa_switch_t xa_switch_t;
/*
 * Flag definitions for the RM switch
 */
#define TMNOFLAGS 0x00000000L     /* no resource manager features selected */
#define TMREGISTER 0x00000001L    /* resource manager dynamically registers */
#define TMNOMIGRATE 0x00000002L   /* RM does not support association migration */
#define TMUSEASYNC 0x00000004L    /* RM supports asynchronous operations */

tt_xa_switch

The tt_xa_switch names the actual functions implemented by a TimesTen resource manager. It also indicates explicitly that association migration is not supported. In addition, dynamic registration and asynchronous operations are not supported.

struct xa_switch_t
tt_xa_switch =
{
    "TimesTen", /* name of resource manager */
    TMNOMIGRATE, /* RM does not support association migration */
    0,
    tt_xa_open,
    tt_xa_close,
    tt_xa_start,
    tt_xa_end,
    tt_xa_rollback,
    tt_xa_prepare,
    tt_xa_commit,
    tt_xa_recover,
    tt_xa_forget,
    tt_xa_complete
};

XA error handling in TimesTen

The XA specification has a limited and strictly defined set of errors that can be returned from XA interface calls. The ODBC SQLError function returns XA-defined errors along with any additional information.

The TimesTen XA-related errors begin at number 11000. Errors 11002 through 11020 correspond to the errors defined by the XA standard.

See "Warnings and Errors" in Oracle TimesTen In-Memory Database Error Messages and SNMP Traps for the complete list of errors.

XA support through the Windows ODBC driver manager

This section discusses issues and procedures for using XA with the Windows ODBC driver manager. (UNIX ODBC driver managers are not considered.)

Issues to consider

XA support through the ODBC driver manager requires special handling. There are two fundamental problems:

  • The XA interface is not part of the defined ODBC interface. If the XA symbols are directly referenced in an application, it is not possible to link with only the driver manager library to resolve all the external references.

  • By design, the driver manager determines which driver .dll file to load at connect time, when you call SQLConnect or SQLDriverConnect. XA dictates that the connection should be opened through xa_open(). But the correct xa_open() entry point cannot be located until the .dll is loaded during the connect operation itself.

Note that the driver manager objective of database portability is generally not applicable here, since each XA implementation is essentially proprietary. The primary benefit of driver manager support for XA-enabled applications is to enable TimesTen-specific applications to run transparently with either the TimesTen direct driver or the TimesTen Client/Server driver.

Linking to the TimesTen ODBC XA driver manager extension library

On Windows installations, TimesTen provides a driver manager extension library, ttxadm1122.dll, for XA functions. Applications can make XA calls directly, but must link in the extension library.

To link with the ttxadm1122.dll library, applications must include ttxadm1122.lib before odbc32.lib in their link line. For example:

# Link with the ODBC driver manager
appldm.exe:appl.obj
       $(CC) /Feappldm.exe appl.obj ttxadm1122.lib odbc32.lib

Note:

The XA driver manager extension is implemented only for 32-bit Windows applications.

Configuring Tuxedo to use TimesTen XA

To configure Tuxedo to use the TimesTen resource managers, perform the following tasks.

Important:

Though TimesTen XA has been demonstrated to work with the Oracle Tuxedo transaction manager, TimesTen cannot guarantee the operation of DTP software beyond the TimesTen implementation of XA.

Notes:

  • The examples in this section use the direct driver. You can also use the client/server library or driver manager library with the XA extension library.

  • Information on configuring TimesTen for object-relational mapping frameworks and application servers, including Oracle WebLogic Application Server, is available in the TimesTen Quick Start. Click Java EE and OR Mapping under Configuration and Setup.

Update the $TUXDIR/udataobj/RM file

To integrate the TimesTen XA resource manager into the Oracle Tuxedo system, update the $TUXDIR/udataobj/RM file to identify the TimesTen resource manager, the name of the TimesTen resource manager switch (tt_xa_switch), and the name of the library for the resource manager.

On UNIX platforms, add the following:

TimesTen:tt_xa_switch:-Linstall_dir/lib -ltten

For example:

TimesTen:tt_xa_switch:-L/opt/TimesTen/giraffe/lib -ltten

On Windows platforms, add the following:

TimesTen;tt_xa_switch;install_dir\lib\ttdv1122.lib

For example:

TimesTen;tt_xa_switch;C:\TimesTen\giraffe\lib\ttdv1122.lib

Note:

The install_dir is the path to the TimesTen home directory.

Build the Tuxedo transaction manager server

Use the buildtms command to build a transaction manager server for the TimesTen resource manager. Then copy the TMS_TT file created by buildtms to the $TUXDIR/bin directory.

On UNIX platforms, the commands are the following:

buildtms -o TMS_TT -r TimesTen -v
cp TMS_TT $TUXDIR/bin

On Windows platforms, the commands are the following:

buildtms -o TMS_TT -r TimesTen -v
copy TMS_TT.exe %TUXDIR%\bin

Update the GROUPS section in the UBBCONFIG file

For TMSNAME, specify the TMS_TT file created by the buildtms command described in the preceding section.

TMSNAME=TMS_TT

Enter a line for each TimesTen resource manager that specifies a group name, followed by the LMID, GRPNO, and OPENINFO parameters. Your OPENINFO string should look like this:

OPENINFO="TimesTen:DSN=DSNname"

Where DSNname is the name of the database.

Note that on Windows, Tuxedo servers run as user SYSTEM. Add the UID general connection attribute to the OPENINFO string to specify a user other than SYSTEM:

OPENINFO="TimesTen:DSN=DSNname;UID=user"

Do not specify a CLOSEINFO parameter for any TimesTen resource manager.

Example 6-2 shows the portions of a UBBCONFIG file used to configure two TimesTen resource managers, GROUP1 and GROUP2.

Example 6-2 Configuring TimesTen resource managers

*RESOURCES
...
*MACHINES
...
ENGSERV LMID=simple
*GROUPS
DEFAULT: TMSNAME=TMS_TT TMSCOUNT=2
GROUP1
    LMID=simple GRPNO=1 OPENINFO="TimesTen:DSN=MyDSN1;UID=MyName"
GROUP2
    LMID=simple GRPNO=2 OPENINFO="TimesTen:DSN=MyDSN2;UID=MyName"
*SERVERS
DEFAULT:
    CLOPT="-A"
simpserv1 SRVGRP=GROUP1 SRVID=1
simpserv2 SRVGRP=GROUP2 SRVID=2

*SERVICES
TOUPPER
TOLOWER

Compile the servers

Set the CFLAGS environment variable to include the install_dir/include directory that contains the TimesTen include files. Then use the buildserver command to construct an Oracle Tuxedo ATMI server load module.

On UNIX platforms, enter the following.

export CFLAGS=-Iinstall_dir/
buildserver -o server -f server.c -r TimesTen -s SERVICE

On Windows platforms, enter the following.

set CFLAGS=-Iinstall_dir\
buildserver -o server -f server.c -r TimesTen -s SERVICE

Note:

The install_dir is the path to the TimesTen home directory.

Example 6-3 shows an example of how to use the buildclient command to construct the client module (simpcl) and the buildserver command to construct the two server modules described in the UBBCONFIG file in Example 6-2 above.

Example 6-3 Construct server modules

set CFLAGS=-IC:\TimesTen\giraffe\
buildclient -o simpcl -f simpcl.c
buildserver -v -t -o simpserv1 -f simpserv1.c -r TimesTen -s TOUPPER
buildserver -v -t -o simpserv2 -f simpserv2.c -r TimesTen -s TOLOWER