Table of Contents
This chapter describes how to use XA (Extended Architecture) to handle distributed transactions.
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.
For more information about distributed transactions, refer to Tibero Administrator's Guide.
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:
The two-phase commit mechanism is performed in two phases. The previous figure is described as follows:
First Phase (or prepare phase)
In this phase, commitment is prepared.
Detailed processes of the first phase:
Step | Description |
---|---|
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. |
Second Phase (or commit phase)
In this phase, commitment is performed.
Detailed processes of the second phase:
Step | Description |
---|---|
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. |
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:
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.
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.
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.
Tibero provides XA functions, but they can only be used by C programming language.
The following table lists XA functions:
Function | Description |
---|---|
xa_open | Connects to a resource manager. For more information, refer to “4.2.2. xa_open Function Fields”. |
xa_close | Disconnects from a resource manager. |
xa_start | Starts a new transaction with a given global transaction identifier (XID) or associates current process with an existing transaction. |
xa_end | Disassociates current process from a given XID. |
xa_rollback | Rolls 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_recover | Checks a list of prepared transactions and then commits or rolls back according to the result. |
xa_forget | Removes logs when a transaction associated with a given XID has already been handled. |
The following table shows the fields used to call the xa_open function:
Field | Required | Description |
---|---|---|
user | O | User name with which to connect with. (Example: user=tibero) |
pwd | O | Password of a user. (Example: pwd=1234) |
db | X | DSN name of the database to connect to (DSN name in the tbdsn.tbr file). (Example: db=sample) |
conn_id | X | Name for the XA connection. The name can be used in the AT statement of ESQL. (Example: conn_id=db1) |
Loose_Coupling | O | 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) |
sestm | O | 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) |
seswt | X | 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) |
logdir | X | Directory in which XA log is saved. (Example: logdir=/home/test/log) |
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], >rid, 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], >rid, 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], >rid, 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], >rid, 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; }
This section describes XA interfaces and an example program using the interfaces.
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.XADataSource | com.tmax.tibero.jdbc.ext.TbXADataSource |
javax.sql.XAConnection | com.tmax.tibero.jdbc.ext.TbXAConnection |
javax.transaction.xa.XAException | com.tmax.tibero.jdbc.ext.TbXAException |
javax.transaction.xa.Xid | com.tmax.tibero.jdbc.ext.TbXid |
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) {} } }
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.
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.
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
Classification | Description |
---|---|
OS | Ubuntu Linux 2.6.32-24-server x86-64 |
Shell | bash |
$TMAXDIR | Tmax installation directory |
Files
File | Description |
---|---|
sample.m | Tmax configuration file ($TMAXDIR/config) |
tms_tbr.mk | TMS makefile for Tibero ($TMAXDIR/sample/server) |
tbrtest.tbc | Server program's tbESQL/C file ($TMAXDIR/sample/server) |
tbrtest.h | Server program's header file ($TMAXDIR/sample/server) |
Makefile.tbr | Server program's makefile ($TMAXDIR/sample/server) |
compile | Server program's build script ($TMAXDIR/sample/server) |
tbr_main.c | Client program's program file ($TMAXDIR/sample/client) |
Makefile.c | Client program's makefile ($TMAXDIR/sample/client) |
compile | Client program's build script ($TMAXDIR/sample/client) |
Tmax can be integrated with Tibero in the following order:
Configuring Tmax
Compiling TMS
Compiling a server program
Compiling a client program
Creating a DB table
Executing an example program
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.
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.
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
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
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
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 );
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]]
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.
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
Classification | Description |
---|---|
OS | AIX |
Host name | tux_machine |
Shell | bash |
Tibero installation directory | /path/to/tibero |
Tuxedo installation directory | /path/to/tuxedo |
Example program's home directory | /path/to/example |
Files
File | Description |
---|---|
tb_tux.env | System environment variable configuration file |
tb_tux.conf.m | Tuxedo configuration file |
tmax32.fld | Field table file |
trans_fml32.tbc | Server program's tbESQL/C file |
builds.sh | Server program's build script |
insert.c | INSERT client program file |
select.c | SELECT client program file |
buildc.sh | Client program's build script |
create_table.sql | File for creating a DB table for a test |
run.sh | Script for starting Tuxedo system |
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.
Setting system environment variables
Configuring Tuxedo
Compiling TMS
Compiling a server program
Compiling client programs
Creating a DB table
Executing an example program
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
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.
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.
Compile TMS for Tibero with the following command:
buildtms -o $TUXDIR/bin/tms_tibero -v -r TIBERO_XA
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
For detailed information on precompiler options, refer to Tibero tbESQL/C Guide.
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
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) );
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.