Chapter 4. XA

Table of Contents

4.1. Distributed Transaction
4.1.1. Two-phase Commit
4.1.2. In-doubt Transaction
4.2. XA API
4.2.1. XA Functions
4.2.2. xa_open Function Fields
4.2.3. XA Application Programming
4.3. JDBC XA
4.3.1. XA Interface
4.3.2. XA Interface Programming
4.4. Integrating with TP-Monitor
4.4.1. Integrating with Tmax
4.4.2. Integrating with Tuxedo

This chapter describes how to use XA (Extended Architecture) to handle distributed transactions.

4.1. Distributed Transaction

Several SQL statements bound in a single transaction are committed or rolled back together in a single database instance.

There could be several SQL statements bound in a single transaction, in which several database instances are created from several databases that are connected over a network. These SQL statements should be committed or rolled back together.

A transaction, in which several nodes or databases participate in, is called a distributed transaction.

Note

For more information about distributed transactions, refer to Tibero Administrator's Guide.

4.1.1. Two-phase Commit

Tibero supports X/Open DTP (Distributed Transaction Processing) XA. XA handles distributed transactions using the two-phase commit protocol.

To ensure the integrity of a transaction in a distributed environment, the two-phase commit protocol is used.

When more than one node participates a single transaction, the node that receives a request from the user and starts the transaction first is the coordinator. In a system in which TP-Monitor exists, the TP-Monitor is the coordinator.

The following figure shows a basic example of the two-phase commit mechanism:

[Figure 4.1] Basic Two-phase Commit Example

Basic Two-phase Commit Example

The two-phase commit mechanism is performed in two phases. The previous figure is described as follows:

  1. First Phase (or prepare phase)

    In this phase, commitment is prepared.

    Detailed processes of the first phase:

    StepDescription
    send "prepare"Each node receives a message from a coordinator node, requesting to prepare commitment.
    reply "prepared"Each node checks whether a commitment is possible. If commitment is not possible, it rolls back independently. If commitment is possible, each node sends a message to the coordinator node indicating that commitment has been prepared.
  2. Second Phase (or commit phase)

    In this phase, commitment is performed.

    Detailed processes of the second phase:

    StepDescription
    send "commit"The coordinator node receives messages, that commitment has been prepared, from all nodes. After checking these messages, the coordinator node sends messages requesting to commit.
    reply "committed"Each node records logs of commitment, and then sends a message to the coordinator node indicating that commitment has been completed.

4.1.2. In-doubt Transaction

When a database receives the first message of the two-phase commit mechanism, it prepares commitment by locking necessary resources for distributed transactions or by logging them. However, the database may not receive the second message (commitment or rollback) in the process of completing the preparation due to network problems.

In this case, the database cannot decide whether to commit or rollback the transaction and just waits until the next message is delivered, while holding the lock on the prepared resources. This type of transaction, that is prepared but holds resources without receiving the next message, is called an In-doubt transaction.

For example, an in-doubt transaction occurs when a server of a certain node goes down, a coordinator node's message is not delivered to a node due to a network problem, or a coordinator node does not receive a reply from a node although the coordinator node sends a message requesting preparation.

In this case, because the coordinator node does not receive a reply from a node even though it receives replies from all the other nodes, it marks the transaction as an in-doubt transaction and sends a message to all the other nodes requesting a rollback.

The following figure shows an example of an in-doubt transaction:

[Figure 4.2] In-doubt Transaction Example

In-doubt Transaction Example

Although all nodes receive messages that commitment is prepared and send replies, if a node does not receive a message requesting commitment in the second phase, the transaction is an in-doubt transaction. If a coordinator node does not receive a reply that commitment is completed from a node, although the node completes requested commitment properly, the transaction is also an in-doubt transaction.

To resolve a transaction that is pending with locked resources, a coordinator node needs to rollback transactions of all the nodes, or a database administrator needs to extract the in-doubt transaction and handle it manually.

Data from VT_XA_BRANCH and DPV_2PC_PENDING can be used to extract an in-doubt transaction.

Note

VT_XA_BRANCH is a table that displays information about all XA transaction branches that operate in the current database server in real time. DPV_2PC_PENDING is a view that displays information of pending XA transaction branches. For more information, refer to Tibero RDBMS Reference Guide and Tibero RDBMS Administrator's Guide.

4.2. XA API

To handle distributed transactions using TP-Monitor, an XA API must be used.

Tibero enables the development of an XA application program that meets standards by supporting X/Open DTP XA.

4.2.1. XA Functions

Tibero provides XA functions, but they can only be used by C programming language.

The following table lists XA functions:

FunctionDescription
xa_openConnects to a resource manager. For more information, refer to “4.2.2. xa_open Function Fields”.
xa_closeDisconnects from a resource manager.
xa_startStarts a new transaction with a given global transaction identifier (XID) or associates current process with an existing transaction.
xa_endDisassociates current process from a given XID.
xa_rollbackRolls back a transaction associated with a given XID.
xa_prepare

Prepares a transaction associated with a given XID.

This is the first phase of the two-phase commit protocol.

xa_commit

Commits a transaction associated with a given XID.

This is the second phase of the two-phase commit protocol.

xa_recoverChecks a list of prepared transactions and then commits or rolls back according to the result.
xa_forgetRemoves logs when a transaction associated with a given XID has already been handled.

4.2.2. xa_open Function Fields

The following table shows the fields used to call the xa_open function:

FieldRequiredDescription
userO

User name with which to connect with.

(Example: user=tibero)

pwdO

Password of a user.

(Example: pwd=1234)

dbX

DSN name of the database to connect to (DSN name in the tbdsn.tbr file).

(Example: db=sample)

conn_idX

Name for the XA connection. The name can be used in the AT statement of ESQL.

(Example: conn_id=db1)

Loose_CouplingO

Determines whether several transaction branches, included in the same global transaction, share the same resources. (true/false)

In the case of loose coupling, two different branches in a global transaction use resources by allocating two different transactions, while in the case of tight coupling, all branches in a global transaction share resources with one transaction using lock handling.

(Example: Loose_Coupling=false)

sestmO

Inactive time limit for a transaction before it is aborted by a system.

Waiting time for the next request after sending a reply for a former request. If this time expires, it is assumed that the client has a problem, and the corresponding XA transaction branch (xtb) is rolled back.

(Example: sestm=10)

seswtX

Waiting time of a database server for a transaction before XA_RETRY is returned.

If the TMNOWAIT flag is not set, when a database cannot handle a request of a client immediately, it will send a reply to the client when the necessary resource becomes available. If the database cannot handle a request before the set seswt expires, XARETRY is returned.

(Example: seswt=30)

logdirX

Directory in which XA log is saved.

(Example: logdir=/home/test/log)

4.2.3. XA Application Programming

ESQL is used in general, when an application program is developed in C programming language.

The following is an example of an XA application program, using tbESQL provided in Tibero

#define XA_CONN_STR_TIGHT "TIBERO_XA:user=tibero, pwd=tmax," \
                          "db=sample, sestm=60, logdir=/home/path/to/xa_log"

/* When a global transaction is started in another branch by calling xa_start
* Tight-Coupling
*/
void test_xa_2branch_2pc_tight()
{
    int rc;
    XID xid1;
    XID xid2;
    struct xa_switch_t *tbxa = &XA_SWITCH_NAME;
    char *conn_str = XA_CONN_STR_TIGHT; /* tightly coupled */
    long gtrid = _GTRID_BASE;
    long bqual = 1;

    EXEC SQL BEGIN DECLARE SECTION;
        int cnt;
    EXEC SQL END DECLARE SECTION;

    /* xa_open */
    tbxa->xa_open_entry (conn_str, 0, TMNOFLAGS);
    xid1.formatID = 1;
    xid1.gtrid_length = sizeof(gtrid);
    xid1.bqual_length = sizeof(bqual);
    memcpy(&xid1.data[0], &gtrid, sizeof(gtrid));
    memcpy(&xid1.data[sizeof(gtrid)], &bqual, sizeof(bqual));

    bqual = 2;
    xid2.formatID = 1;
    xid2.gtrid_length = sizeof(gtrid);
    xid2.bqual_length = sizeof(bqual);
    memcpy(&xid2.data[0], &gtrid, sizeof(gtrid));
    memcpy(&xid2.data[sizeof(gtrid)], &bqual,
    sizeof(bqual));

    EXEC SQL DELETE FROM PERSON;
    EXEC SQL COMMIT WORK;

    /* (1, 1) start */
    /* xa_start -- sql statements starts */
    tbxa->xa_start_entry (&xid1, 0, TMNOFLAGS);
    EXEC SQL INSERT INTO PERSON VALUES ('1', 'LEE');
    EXEC SQL INSERT INTO PERSON VALUES ('2', 'KIM');

    /* xa_end -- */
    tbxa->xa_end_entry (&xid1, 0, TMSUCCESS);

    /* (1, 2) 시작 */
    /* xa_start -- sql statements starts */
    tbxa->xa_start_entry (&xid2, 0, TMNOFLAGS);
    EXEC SQL INSERT INTO PERSON VALUES ('2', 'PARK');
    EXEC SQL INSERT INTO PERSON VALUES ('3', 'JAKE');
    EXEC SQL INSERT INTO PERSON VALUES ('4', 'KID');
    EXEC SQL INSERT INTO PERSON VALUES ('5', 'CHANHO');

    /* xa_end -- */
    tbxa->xa_end_entry (&xid2, 0, TMSUCCESS);

    /* xa_prepare */
    tbxa->xa_prepare_entry (&xid1, 0, TMNOFLAGS);

    /* Tightly-Coupled assumed */
    /* xa_prepare */
    tbxa->xa_prepare_entry (&xid2, 0, TMNOFLAGS);

    /* xa_commit */
    tbxa->xa_commit_entry (&xid1, 0, TMNOFLAGS);

    /* xa_commit */
    tbxa->xa_commit_entry (&xid2, 0, TMNOFLAGS);
    EXEC SQL SELECT COUNT(*) into :cnt FROM PERSON;
    CuAssertIntEq(tc, cnt, 6);

    /* xa_close */
    tbxa->xa_close_entry ("", 0, TMNOFLAGS);
    return;
}

/* When xa_start is started through a different branch of the same Global Trasaction
* Loose-Coupling
*/
void test_xa_2branch_2pc_loose(CuTest *tc)
{
    int rc;
    XID xid1;
    XID xid2;
    struct xa_switch_t *tbxa = &XA_SWITCH_NAME;
    char *conn_str = XA_CONN_STR_LOOSE;
    long gtrid = _GTRID_BASE;
    long bqual = 1;

    EXEC SQL BEGIN DECLARE SECTION;
        int cnt;
    EXEC SQL END DECLARE SECTION;

    /* xa_open */
    tbxa->xa_open_entry (conn_str, 0, TMNOFLAGS);
    xid1.formatID = 1;
    xid1.gtrid_length = sizeof(gtrid);
    xid1.bqual_length = sizeof(bqual);
    memcpy(&xid1.data[0], &gtrid, sizeof(gtrid));
    memcpy(&xid1.data[sizeof(gtrid)], &bqual, sizeof(bqual));

    bqual = 2;
    xid2.formatID = 1;
    xid2.gtrid_length = sizeof(gtrid);
    xid2.bqual_length = sizeof(bqual);
    memcpy(&xid2.data[0], &gtrid, sizeof(gtrid));
    memcpy(&xid2.data[sizeof(gtrid)], &bqual,
    sizeof(bqual));

    EXEC SQL DELETE FROM PERSON;
    EXEC SQL COMMIT WORK;

    /* (1, 1) start */
    /* xa_start -- sql statements starts */
    tbxa->xa_start_entry (&xid1, 0, TMNOFLAGS);
    EXEC SQL INSERT INTO PERSON VALUES ('1', 'LEE');
    EXEC SQL INSERT INTO PERSON VALUES ('2', 'KIM');

    /* xa_end -- */
    tbxa->xa_end_entry (&xid1, 0, TMSUCCESS);

    /* (1, 2) start */
    /* xa_start -- sql statements starts */
    tbxa->xa_start_entry (&xid2, 0, TMNOFLAGS);
    EXEC SQL INSERT INTO PERSON VALUES ('2', 'PARK');
    EXEC SQL INSERT INTO PERSON VALUES ('3', 'JAKE');
    EXEC SQL INSERT INTO PERSON VALUES ('4', 'KID');
    EXEC SQL INSERT INTO PERSON VALUES ('5', 'CHANHO');

    /* xa_end -- */
    tbxa->xa_end_entry (&xid2, 0, TMSUCCESS);

    /* xa_prepare */
    tbxa->xa_prepare_entry (&xid1, 0, TMNOFLAGS);

    /* Loosely-Coupled assumed */
    /* xa_prepare */
    tbxa->xa_prepare_entry (&xid2, 0, TMNOFLAGS);

    /* xa_commit */
    tbxa->xa_commit_entry (&xid1, 0, TMNOFLAGS);

    /* xa_commit */
    tbxa->xa_commit_entry (&xid2, 0, TMNOFLAGS);
    EXEC SQL SELECT COUNT(*) into :cnt FROM PERSON;
    CuAssertIntEq(tc, cnt, 6);

    /* xa_close */
    tbxa->xa_close_entry ("", 0, TMNOFLAGS);
    return;
}

4.3. JDBC XA

This section describes XA interfaces and an example program using the interfaces.

4.3.1. XA Interface

The JDBC XA interfaces supported in Tibero are:

  • XA Datasource Interface

  • XA Connection Interface

  • XA Exception Interface

  • XA XID Interface

The following is a list of XA interfaces implemented in Tibero.

Standard XA Interface (JDK 1.3)Tibero XA Interface
javax.sql.XADataSourcecom.tmax.tibero.jdbc.ext.TbXADataSource
javax.sql.XAConnectioncom.tmax.tibero.jdbc.ext.TbXAConnection
javax.transaction.xa.XAExceptioncom.tmax.tibero.jdbc.ext.TbXAException
javax.transaction.xa.Xidcom.tmax.tibero.jdbc.ext.TbXid

4.3.2. XA Interface Programming

The following is an example program using XA interfaces in a tbJDBC environment.

package test.com.tmax.tibero.cases;
import com.tmax.tibero.jdbc.ext.*;
import test.com.tmax.tibero.AbstractBase;
import javax.sql.XAConnection;
import javax.transaction.xa.XAResource;
import java.sql.*;

public class TestXATwoBranch extends AbstractBase{
    int formatID = 1;
    int row_count = 0;
    int pre1 , pre2 = 0;

    byte[] gtid1 = new byte[1];
    byte[] bq1 = new byte[1];
    byte[] gtid2 = new byte[1];
    byte[] bq2 = new byte[1];

    public TestXATwoBranch (String name) {
    super(name);
    }

    /* When tightly coupled */
    public void test_xa_2branch_2pc_tight () throws Exception {
        debug("test_xa_2branch_2pc_tight " + this._getClassName());

        create_table_for_xa();

        gtid1[0] = (byte)1; bq1[0] = (byte)1;
        gtid2[0] = (byte)1; bq2[0] = (byte)2;

        TbXADataSource xads1 = new TbXADataSource();
        xads1.setUrl(getXAurl());
        xads1.setUser(getXAuser());
        xads1.setPassword(getXApasswd());

        TbXADataSource xads2 = new TbXADataSource();
        xads2.setUrl(getXAurl());
        xads2.setUser(getXAuser());
        xads2.setPassword(getXApasswd());

        XAConnection xacon1 = xads1.getXAConnection();
        XAConnection xacon2 = xads2.getXAConnection();

        Connection conn1 = xacon1.getConnection();
        Connection conn2 = xacon2.getConnection();

        XAResource xars1 = xacon1.getXAResource();
        XAResource xars2 = xacon2.getXAResource();

        /* XID (1.1) creation */
        TbXid xid1 = new TbXid(formatID, gtid1,bq1 );

        /* XID (1.2) creation */
        TbXid xid2 = new TbXid(formatID, gtid2, bq2);
        try {
            /* (1.1) start */
            xars1.start(xid1, XAResource.TMNOFLAGS);

            PreparedStatement pstmt1;
            pstmt1 = conn1.prepareStatement("insert into author values (?,?)");

            pstmt1.setInt(1, 1);
            pstmt1.setString(2, "FOSCHIA");
            pstmt1.executeUpdate();

            pstmt1.setInt(1,2);
            pstmt1.setString(2, "AGNOS");
            pstmt1.executeUpdate();

            /* (1.1) end */
            xars1.end(xid1, XAResource.TMSUCCESS);

            /* (1.2) start */
            xars2.start(xid2, XAResource.TMNOFLAGS);
            PreparedStatement pstmt2;
            pstmt2 = conn2.prepareStatement("insert into author values (?,?)");

            pstmt2.setInt(1, 3);
            pstmt2.setString(2, "JELLA");
            pstmt2.executeUpdate();

            pstmt2.setInt(1,4);
            pstmt2.setString(2, "THIPHILO");
            pstmt2.executeUpdate();

            /* (1.2) end */
            xars2.end(xid2, XAResource.TMSUCCESS);

            /* (1,1) prepare */
            pre1= xars1.prepare(xid1);
            assertEquals(pre1, XAResource.XA_RDONLY);

            /* (1,2) prepare */
            pre2 = xars2.prepare(xid2);
            assertEquals(pre2, XAResource.XA_OK);

            /* (1.1) commit */
            try {
                xars1.commit(xid1, false);
            } catch(TbXAException e) {}

            /* (1.2) commit */
            try {
                xars2.commit(xid2, false);
            } catch(TbXAException e) {}

            Statement stmt1 = conn1.createStatement();
            ResultSet rs1 = stmt1.executeQuery("select * from author");

            while (rs1.next())
                row_count ++;

            assertEquals(4, row_count);

            rs1.close(); rs1 = null;
            stmt1.close(); stmt1 = null;

            pstmt1.close(); conn1.close(); xacon1.close();
            pstmt2.close(); conn2.close(); xacon2.close();

            pstmt1= null; conn1= null; xacon1=null;
            pstmt2= null; conn2= null; xacon2=null;
        } catch (TbXAException e) {}
    }

    /* When loosely coupled */
    public void test_xa_2branch_2pc_loose () throws Exception {
        debug("test_xa_2branch_2pc_loose " + this._getClassName());

        create_table_for_xa();

        gtid1[0] = (byte)1; bq1[0] = (byte)1;
        gtid2[0] = (byte)1; bq2[0] = (byte)2;

        TbXADataSource xads1 = new TbXADataSource();

        xads1.setUrl(getXAurl());
        xads1.setUser(getXAuser());
        xads1.setPassword(getXApasswd());

        TbXADataSource xads2 = new TbXADataSource();

        xads2.setUrl(getXAurl());
        xads2.setUser(getXAuser());
        xads2.setPassword(getXApasswd());

        XAConnection xacon1 = xads1.getXAConnection();
        XAConnection xacon2 = xads2.getXAConnection();

        Connection conn1 = xacon1.getConnection();
        Connection conn2 = xacon2.getConnection();

        XAResource xars1 = xacon1.getXAResource();
        XAResource xars2 = xacon2.getXAResource();

        TbXid xid1 = new TbXid(formatID, gtid1,bq1 );
        TbXid xid2 = new TbXid(formatID, gtid2, bq2);

        try {
            xars1.start(xid1, TbXAResource.TBRTRANSLOOSE);

            PreparedStatement pstmt1;
            pstmt1 = conn1.prepareStatement("insert into author values (?,?)");

            pstmt1.setInt(1, 1);
            pstmt1.setString(2, "FOSCHIA");
            pstmt1.executeUpdate();

            pstmt1.setInt(1,2);
            pstmt1.setString(2, "AGNOS");
            pstmt1.executeUpdate();

            xars1.end(xid1, XAResource.TMSUCCESS);

            xars2.start(xid2, TbXAResource.TBRTRANSLOOSE);

            PreparedStatement pstmt2;
            pstmt2 = conn2.prepareStatement("insert into author values (?,?)");

            pstmt2.setInt(1, 3);
            pstmt2.setString(2, "JELLA");
            pstmt2.executeUpdate();

            pstmt2.setInt(1,4);
            pstmt2.setString(2, "THIPHILO");
            pstmt2.executeUpdate();

            xars2.end(xid2, XAResource.TMSUCCESS);

            pre1= xars1.prepare(xid1);
            assertEquals(pre1, XAResource.XA_OK);

            pre2 = xars2.prepare(xid2);
            assertEquals(pre2, XAResource.XA_OK);

            xars1.commit(xid1, false);
            xars2.commit(xid2, false);

            Statement stmt1 = conn1.createStatement();
            ResultSet rs1 = stmt1.executeQuery("select * from author");

            while (rs1.next())
            row_count ++;

            assertEquals(4, row_count);

            rs1.close(); rs1 = null;
            stmt1.close(); stmt1 = null;

            pstmt1.close(); conn1.close(); xacon1.close();
            pstmt2.close(); conn2.close(); xacon2.close();

            pstmt1= null; conn1= null; xacon1=null;
            pstmt2= null; conn2= null; xacon2=null;
        } catch (TbXAException e) {}
    }
}

4.4. Integrating with TP-Monitor

TP-Monitor (Transaction Processing Monitor) is a middleware for managing transactions. It consistently keeps and maintains transactions by monitoring each transaction, which is the minimum handling unit for sessions, systems, and databases that use various protocols.

This section describes Tmax and Tuxedo, which are superior commercial TP-monitors, and example programs that integrate them with Tibero.

4.4.1. Integrating with Tmax

Tmax stands for Transaction Maximization. As a TP-Monitor, it not only guarantees that transactions are perfectly handled between heterogeneous systems, but it also distributes loads and handles errors. Furthermore, it supports various characteristics of transactions, offers optimal development environment to the users, provides best solutions in the client/server environment with high performance, and handles all types of failures.

Tmax complies with the X/Open DTP (Distributed Transaction Processing) model which is the international standard for distributed transaction processing. It has been developed according to APIs for the OSI(Open Systems Interconnection group) DTP services and system interface definitions. In addition, it supports transparent business handling between heterogeneous systems in the distributed environment and OLTP (On-Line Transaction Processing), and meets the ACID (Atomic, Consistent, Isolated, Durable: transaction properties) characteristics for transaction handling.

To test the following example program integrating Tmax with Tibero, Tmax and Tibero should first be properly installed.

Note

1. If Tmax and Tibero to be integrated, are installed in separate machines, Tibero client must be installed in the machine in which Tmax is installed. The client also needs to be able to access the Tibero server.

2. For detailed information on how to install and manage Tmax, refer to Tmax Installation Guide and Tmax Administrator's Guide. For detailed information on how to install and manage Tibero, refer to Tibero Installation Guide and Tibero Administrator's Guide.

The following example program is provided by the Tmax installer, by default. The program illustrates how a client accesses Tibero DB to search, add, modify, and delete data in a certain table via Tmax server. Descriptions for the test environment and each file used by the program are as follows:

  • Test environment

    ClassificationDescription
    OSUbuntu Linux 2.6.32-24-server x86-64
    Shellbash
    $TMAXDIRTmax installation directory
  • Files

    FileDescription
    sample.mTmax configuration file ($TMAXDIR/config)
    tms_tbr.mkTMS makefile for Tibero ($TMAXDIR/sample/server)
    tbrtest.tbcServer program's tbESQL/C file ($TMAXDIR/sample/server)
    tbrtest.hServer program's header file ($TMAXDIR/sample/server)
    Makefile.tbrServer program's makefile ($TMAXDIR/sample/server)
    compileServer program's build script ($TMAXDIR/sample/server)
    tbr_main.cClient program's program file ($TMAXDIR/sample/client)
    Makefile.cClient program's makefile ($TMAXDIR/sample/client)
    compileClient program's build script ($TMAXDIR/sample/client)

Tmax can be integrated with Tibero in the following order:

  1. Configuring Tmax

  2. Compiling TMS

  3. Compiling a server program

  4. Compiling a client program

  5. Creating a DB table

  6. Executing an example program

Configuring Tmax

The following describes how to configure a Tmax environment.

  • Setting the Tmax configuration file

    sample.m under the $TMAXDIR/config directory is the ASCII type Tmax configuration file that includes information for starting Tmax. After the file is compiled with the cfl utility, a binary file is created. The binary file is accessed when Tmax is started and terminated.

    To activate a service to be integrated with Tibero server, modify the SVRGROUP, SERVER, and SERVICE sections in sample.m file as follows:

    ### tms for Tibero ###
    svg4           NODENAME = "integrity", DBNAME = TIBERO,
                   OPENINFO = "TIBERO_XA:user=tibero,pwd=tmax,sestm=60,db=tibero",
                   TMSNAME  = tms_tbr
    
    ### server for Tibero sample program ###
    tbrtest        SVGNAME = svg4
    
    ### services for tbrtest ###
    TBRINS         SVRNAME = tbrtest
    TBRSEL         SVRNAME = tbrtest
    TBRUPT         SVRNAME = tbrtest
    TBRDEL         SVRNAME = tbrtest

    NODENAME in the SVRGROUP section is automatically set as the hostname value during the Tmax installation. DBNAME, used to distinguish a DB vendor, is set to TIBERO. OPENINFO is set to TIBERO_XA, used for setting XA mode, followed by values for properties described in “4.2.2. xa_open Function Fields”. TMSNAME is set to an XA module name. In the SERVER section, the name of the example server program is set to tbrtest and four services provided by the example server program are set.

    Note

    For detailed information on how to set Tmax configuration file, refer to Tmax Administrator's Guide.

  • Compiling the Tmax configuration file

    Compile the modified sample.m with the following command:

    cfl -i sample.m

    If the file compiles successfully, the following message will be displayed:

    CFL is done successfully for node(<nodename>)
  • Creating a service table

    A service table is a file needed to creating server processes in each Tmax system. It includes information about the services each process handles. Create the service table with the following command:

    gst

    If the service table is successfully created, the following message will be displayed:

    SVC tables are successfully generated GST is successfully done
  • Creating a binary file for defining structures and a binary file for defining field keys

    If a structure or a field key is used in a server or a client program, a corresponding binary file should be created. This process is skipped in the example program as the program does not use a structure or a field key.

Compiling TMS

As a Tmax system's component, TMS (Transaction Management Server) is a process that manages databases and handles distributed transactions. Before compiling TMS for Tibero, check whether Tibero-related environment variables such as TB_HOME, TB_SID, LD_LIBRARY_PATH, and PATH are properly set.

Move to the $TMAXDIR/sample/server directory to compile TMS with TMS makefile for Tibero as follows:

cd $TMAXDIR/sample/server
make –f tms_tbr.mk all

Compiling a server program

Move to the $TMAXDIR/sample/server directory to compile a server program that provides actual services using a build script as follows:

cd $TMAXDIR/sample/server
./compile tbc tbrtest

Compiling a client program

Move to the $TMAXDIR/sample/server directory to compile a client program that requests services using a build script as follows:

cd $TMAXDIR/sample/client
./compile c tbr_main

Creating a DB table

Access Tibero server using the tibero/tmax account to create the emp table as follows:

tbsqltibero/tmax

create table emp (
    empno number,
    ename char(16),
    job char(16),
    hiredate char(16),
    sal number
);

Executing an Example program

  • Starting Tmax system

    Start Tmax with the following command:

    tmboot

    If Tmax successfully starts, the following message will be displayed:

    TMBOOT for node(<nodename>) is starting: 
    Welcome to Tmax demo system: it will expire 2012/3/11 
    Today: 2012/1/13 
            TMBOOT: TMM is starting: Fri Jan 13 14:18:31 2012 
            TMBOOT: CLL is starting: Fri Jan 13 14:18:31 2012 
            TMBOOT: CLH is starting: Fri Jan 13 14:18:31 2012 
    (I) CLH9991 Current Tmax Configuration: Number of client handler(MINCLH) = 1
                    Supported maximum user per node = 680
                    Supported maximum user per handler = 680 [CLH0125]
            TMBOOT: TLM(tlm) is starting: Fri Jan 13 14:18:31 2012 
            TMBOOT: TMS(tms_tbr) is starting: Fri Jan 13 14:18:31 2012 
    (I) TMS0211 General Infomation : transaction recovery will be started [TMS0221]
    (I) TMS0211 General Infomation : transaction recovery was completed [TMS0222]
            TMBOOT: TMS(tms_tbr) is starting: Fri Jan 13 14:18:31 2012 
            TMBOOT: SVR(tbrtest) is starting: Fri Jan 13 14:18:31 2012 
  • Executing a client program

    A client program has the following command options:

    Usage: ./tbr_main empno loop_cnt ins_flag upt_flag del_flag
    flag : 1|0 

    Select desired options and execute a client program, and the following result will be displayed:

    ./tbr_main 12 3 1 0 0
    
     LOOP COUNT = 1 
    >> INSERT : COMMIT TEST 
    [./tbr_main] [[TBRINS] emp Insert Success]
    [./tbr_main] [[TBRSEL] emp Select Success [1]]
    
     LOOP COUNT = 2 
    >> INSERT : COMMIT TEST 
    [./tbr_main] [[TBRINS] emp Insert Success]
    [./tbr_main] [[TBRSEL] emp Select Success [2]]
    
     LOOP COUNT = 3 
    >> INSERT : COMMIT TEST 
    [./tbr_main] [[TBRINS] emp Insert Success]
    [./tbr_main] [[TBRSEL] emp Select Success [3]]

4.4.2. Integrating with Tuxedo

As a platform for handling distributed transactions, Tuxedo provides mainframe's scalability and high-performance in open distributed systems for programs written in C, C++, and COBOL. It can also rehost mainframe applications on mainstream hardware.

Tuxedo not only provides reliability and scalability in a cost-effective way for supporting hundreds of thousands of transactions, but it also extends the lifecycle of existing IT resources that are a part of an innovative architecture such as SOA. Oracle Tuxedo is an Oracle Fusion Middleware product for handling transactions.

To test the following example program integrating Tuxedo with Tibero, Tuxedo and Tibero should be properly installed.

Note

1. If Tuxedo and Tibero to be integrated are installed in separate machines, Tibero client must be installed in the machine in which Tuxedo is installed, and the client needs to be able to access the Tibero server.

2. For detailed information on how to install and manage Tuxedo, refer to the Tuxedo documentation. For detailed information on how to install and manage Tibero, refer to Tibero Installation Guide and Tibero Administrator's Guide.

The following example program illustrates how a client accesses Tibero DB to search and add data in a certain table via Tuxedo server. For convenience, assume that the host name of the test server is tux_machine, Tibero and Tuxedo are installed in path/to/tibero and /path/to/tuxedo respectively, and relevant files are located in /path/to/example.

Descriptions for the test environment and each file used by the program are as follows:

  • Test environment

    ClassificationDescription
    OSAIX
    Host nametux_machine
    Shellbash
    Tibero installation directory/path/to/tibero
    Tuxedo installation directory/path/to/tuxedo
    Example program's home directory/path/to/example
  • Files

    FileDescription
    tb_tux.envSystem environment variable configuration file
    tb_tux.conf.mTuxedo configuration file
    tmax32.fldField table file
    trans_fml32.tbcServer program's tbESQL/C file
    builds.shServer program's build script
    insert.cINSERT client program file
    select.cSELECT client program file
    buildc.shClient program's build script
    create_table.sqlFile for creating a DB table for a test
    run.shScript for starting Tuxedo system

Note

To see the full source code of this example program, refer to “Appendix B. Example of Integrating with Tuxedo”.

Tuxedo can be integrated with Tibero in the following order. Depending on the OS and the system environment, the example files should be modified accordingly.

  1. Setting system environment variables

  2. Configuring Tuxedo

  3. Compiling TMS

  4. Compiling a server program

  5. Compiling client programs

  6. Creating a DB table

  7. Executing an example program

Setting system environment variables

To test the integration with Tibero and Tuxedo, set the following system environment variables:

  • Setting basic environment variables for Tibero

    export TB_HOME=/path/to/tibero
    export TB_SID=tibero
    export PATH=$TB_HOME/bin:$TB_HOME/client/bin:$TB_HOME/scripts:$PATH
    export LD_LIBRARY_PATH=$TB_HOME/client/lib:$TB_HOME/lib:$LD_LIBRARY_PATH
    export LIBPATH=$TB_HOME/client/lib:$TB_HOME/lib:$LIBPATH
  • Setting basic environment variables for Tuxedo

    export TUXDIR=/path/to/tuxedo
    export JAVA_HOME=$TUXDIR/jre
    export JVMLIBS=$JAVA_HOME/lib/amd64/server:$JAVA_HOME/jre/bin
    export PATH=$TUXDIR/bin:$JAVA_HOME/bin:$PATH
    export COBCPY=:$TUXDIR/cobinclude; export COBCPY
    export COBOPT="-C ANS85 -C ALIGN=8 -C NOIBMCOMP -C TRUNC=ANSI -C OSEXT=cbl"
    export SHLIB_PATH=$TUXDIR/lib:$JVMLIBS:$SHLIB_PATH
    export LIBPATH=$TUXDIR/lib:$JVMLIBS:$LIBPATH
    export LD_LIBRARY_PATH=$TUXDIR/lib:$JVMLIBS:$LD_LIBRARY_PATH
    export WEBJAVADIR=$TUXDIR/udataobj/webgui/java
  • Setting additional environment variables for Tuxedo

    To test the integration, set the following additional environment variables according to each environment.

    export TUXCONFIG=/path/to/tuxedo/tuxconf
    export FLDTBLDIR32=/path/to/tuxedo
    export FIELDTBLS32=tmax32.fld
    export TLOGDEVICE=/path/to/tuxedo/TLOG
    export ULOGPFX=/path/to/tuxedo/ULOG

Configuring Tuxedo

  • Setting the Tuxedo configuration file

    tb_tux.conf.m is the ASCII type Tuxedo configuration file that includes information about starting Tuxedo. After the file is compiled with the tmloadcf utility, a binary file is created. The binary file is accessed when Tuxedo is started and terminated.

    To activate a service to be integrated with Tibero server, modify the RESOURCES, MACHINES, GROUPS, SERVERS, and SERVICES sections in tb_tux.conf.m as follows:

    *RESOURCES
    IPCKEY          68300
    DOMAINID        tbrdomain
    MASTER          tbrtest
    MAXACCESSERS    10
    MAXSERVERS      5
    MAXSERVICES     10
    MODEL           SHM
    LDBAL           N
    
    *MACHINES
    DEFAULT:
                    TUXDIR="path/to/tuxedo"
                    APPDIR="path/to/example"
                    TUXCONFIG="path/to/example/tuxconf"
    
    tux_machine     LMID=tbrtest
    
    *GROUPS
    TBXA            LMID=tbrtest GRPNO=1
                    TMSNAME=tms_tibero
                    OPENINFO="TIBERO_XA:TIBERO_XA:user=sys,pwd=tibero,
                              sestm=60,db=tibero"
    
    *SERVERS
    DEFAULT:
                    CLOPT="-A -r"
    
    trans_fml32     SRVGRP=TBXA  SRVID=1
    
    *SERVICES
    SELECT_FML32
    INSERT_FML32
    ~

    The RESOURCES and MACHINES sections are the same as in a general Tuxedo configuration file.

    tux_machine, the host name in the MACHINE section should be modified according to each test environment. tbrtest for LMID and MASTER and tbrdomain for DOMAINID can be modified.

    The GROUPS section is the same as in a general Tuxedo configuration file. TMSNAME is set as a XA module name used to communicate with the Tibero server. OPENINFO is set to "'TIBERO_XA:TIBERO_XA:" which sets the XA mode, followed by the field values of the “4.2.2. xa_open Function Fields”.

    In the SERVERS section, trans_fml32, the name of the example server program, is set. In the SERVICE section, services provided by the example server program are set to SELECT_FML32 and INSERT_FML32.

    Note

    For detailed information on how to set Tuxedo configuration file, refer to the Tuxedo documentation.

  • Compiling the Tuxedo configuration file

    Compile the modified tb_tux.conf.m with the following command:

    tmloadcf -y tb_tux.conf.m
  • Converting a field table file to a header file

    Common structures are defined and used for data transfer between a server and a client.

    In this example program, tmax32.fld, the following field table file, is newly defined, using the Field Manipulation Language (FLM), and used.

    #name           number          type            flag    comment
    OUTPUT          302             string          0       -
    EMPNO           901             long            0       -
    ENAME           902             string          0       -
    JOB             903             string          0       -
    MGR             904             long            0       -
    SAL             905             float           0       -
    COMM            906             float           0       -
    DEPTNO          907             long            0       -

    Convert tmax32.fld to a header file with the following command:

    mkfldhdr32 tmax32.fld

    A header file named tmax32.fld.h is created as a result and is used by the example programs. For information on how to define other structures and create a field table file, refer to the Tuxedo documentation.

Compiling TMS

Compile TMS for Tibero with the following command:

buildtms -o $TUXDIR/bin/tms_tibero -v -r TIBERO_XA

Compiling a server program

Compile a server program that provides actual services with the following build script, builds.sh.

#### transaction server precompile ####
PRECOMP=$TB_HOME/client/bin/tbpc
PRECOMPFLAGS="UNSAFE_NULL=YES"
LIB=$TB_HOME/client/lib
INC=$TB_HOME/client/include
CFLAGS="-ltbcli -ltbxa -lm -lrt -lpthread -ltbertl -g "
CC=gcc
rm -f trans_fml32.c
$PRECOMP INCLUDE=$TUXDIR/include UNSAFE_NULL=YES INCLUDE=$INC 
$PRECOMPFLAGS ONAME=trans_fml32.c trans_fml32.tbc

#### transaction server build ####
buildserver -o trans_fml32 -v -f trans_fml32.c -s INSERT_FML32,
SELECT_FML32 -r TIBERO_XA

Note

For detailed information on precompiler options, refer to Tibero tbESQL/C Guide.

Compiling client programs

Compile client programs, that request insert and select services, with a build script as follows:

buildclient -o insert -v -f insert.c
buildclient -o select -v -f select.c

Creating a DB table

Access Tibero server using the tibero/tmax account to create the emp table as follows:

tbsqltibero/tmax

drop table emp;
CREATE TABLE emp (
    empno           NUMBER,
    ename           VARCHAR2(10),
    job             VARCHAR2(9),
    mgr             NUMBER(4),
    hiredate        DATE,
    sal             NUMBER(7,2),
    comm            NUMBER(7,2),
    deptno          NUMBER(2)
);

Executing an example program

  • Starting Tuxedo system

    Start Tuxedo with the following command:

    tmboot -y

    If Tuxedo successfully starts, the following message will be displayed:

    Booting all admin and server processes in /path/to/example/tuxconf
    INFO: Oracle Tuxedo, Version 10.3.0.0, 64-bit, Patch Level (none)
    
    Booting admin processes ...
    
    exec BBL -A :
            process id=3457104 ... Started.
    
    Booting server processes ...
    
    exec tms_tibero -A :
            process id=4046910 ... Started.
    exec tms_tibero -A :
            process id=9265576 ... Started.
    exec tms_tibero -A :
            process id=1863802 ... Started.
    exec trans_fml32 -A -r :
            process id=3719284 ... Started.
    5 processes started.
  • Executing a client program

    Execute a client program to add employee information to the emp table as follows:

    ./insert
    ******************************************
    | Employee Number : 1
    | Employee Name   : Kim
    | Employee Job    : Manager
    ******************************************
    

    If the insert program is executed, and Employee Number, Employee Name, and Employee Job values are entered as shown in the previous example, a record is added to the emp table in the Tibero server using the Tuxedo server program.

    ./select
    ******************************************
    | Employee Number : 1
    ******************************************
    
    EMPNO: 1
    ENAME: Kim
    JOB: Manager

    If the select program is executed, and a value for Employee Number is entered as shown in the previous example, a corresponding record is fetched from the emp table in the Tibero server and displayed using the Tuxedo server program.