[Top] [Prev] [Next] [Bottom]

14. Global Transactions in the BEA TUXEDO System


Introduction

The purpose of this chapter is to explain the concept of global transactions and how to define and manage them in your application using the ATMI calls for transaction management.

A global transaction is a transaction that allows work involving more than one resource manager and spanning more than one physical site to be treated as one logical unit. The TPBEGIN routine allows you to explicitly start a transaction. The process that calls TPBEGIN is the initiator of the transaction and must complete it by calling TPCOMMIT or TPABORT. Once a process is in transaction mode, any service requests made to servers may be processed on behalf of the current transaction. The services that are called and join the transaction are the participants. They may affect the outcome of the transaction by the value they return when they invoke the TPRETURN routine. A process can determine if it is currently working on behalf of a transaction by calling the TPGETLEV routine. The rest of this chapter will explain these routines in detail.

What Is a Global Transaction?

Before we get into how you can write applications that define and manage global transactions, this section gives you some idea as to what is meant by a transaction that is under the control of a transaction monitor.

The BEA TUXEDO system manages global transactions. As already indicated, a global transaction is one that can execute in more than one server, accessing data from more than one resource manager. A global transaction may be composed of several local transactions, each accessing a single resource manager. A local transaction accesses a single database or file and is controlled by the resource manager responsible for performing concurrency control and atomicity of updates at that distinct database. A given local transaction may be either successful or unsuccessful in completing its access.

A global transaction is always treated as a specific sequence of operations that is characterized by the four properties of atomicity, consistency, isolation, and durability. That is, it is a logical unit of work in which:

The BEA TUXEDO system is responsible for managing the status of the global transaction and making the decision as to whether or not a global transaction should be committed or rolled back. Global transactions are explicitly defined and controlled by the ATMI routine calls that are described in Section 3cbl of the BEA TUXEDO Reference Manual.

ATMI Transaction Primitives

More specifically, the ATMI routines enable the application programmer to begin and terminate transactions and to test if a client or service routine is currently in a transaction. The ATMI calls, TPBEGIN, TPCOMMIT, and TPABORT are used to explicitly begin and end a transaction. The initiator of a transaction uses TPBEGIN to mark its beginning. After specifying the operations (service requests) to be applied to the resource as part of this transaction, the initiator can then call either TPCOMMIT or TPABORT to mark its completion. The calls to initiate and terminate a transaction delineate the operations within the transaction. If the transaction is completed with a call to TPCOMMIT, the changes made as a result of the transaction are applied to the resource and become permanent. TPABORT causes the resource to be in the consistent state at the start of the transaction. That is, any changes made to the resource are rolled back. Any of the participants of a transaction can cause the global transaction to fail by communicating their local failure to the initiator through the TPRETURN routine. A two-phase commit protocol is used by the BEA TUXEDO system to coordinate the commitment, rollback, and recovery of global transactions. This protocol will be further discussed later in the chapter.

When the TPGETLEV routine is invoked, it returns a setting in TPTRXLEV-REC that indicates if the caller is within a transaction (TP-IN-TRAN) or not (TP-NOT-IN-TRAN).

Explicitly Defining a Global Transaction

Global transactions can be defined in either client or server processes. To explicitly define a global transaction, call the TPBEGIN routine. Follow it by the program statements that are to be in transaction mode. Terminate the statements by a call to TPCOMMIT or TPABORT.

The three routines have the following syntax:

*
01 TPTRXDEF-REC.
COPY TPTRXDEF.
*
01 TPSTATUS-REC.
COPY TPSTATUS.
*
CALL "TPBEGIN" USING TPTRXDEF-REC TPSTATUS-REC.
*
CALL "TPCOMMIT" USING TPTRXDEF-REC TPSTATUS-REC.
*
CALL "TPABORT" USING TPTRXDEF-REC TPSTATUS-REC.

A high-level view of defining a transaction is shown in Listing 14-1.

Listing 14-1 Delineating a Transaction
. . .
MOVE 0 TO T-OUT.
CALL "TPBEGIN" USING
TPTRXDEF-REC
TPSTATUS-REC.
IF NOT TPOK
error processing
. . .
program statements
. . .
CALL "TPCOMMIT" USING
TPTRXDEF-REC
TPSTATUS-REC.
IF NOT TPOK
error processing

The process that makes the call to TPBEGIN, the initiator, must also be the one that terminates it by invoking either TPCOMMIT or TPABORT. There is no limit to the number of sequential transactions that a process may define using these routines. Any process may call TPBEGIN except if

With reference to the second point, it is an error to make the sequence of calls shown in Listing 14-2.

Listing 14-2 Error - Starting a Transaction with an Outstanding Reply
  . . .
MOVE "BUY" TO SERVICE-NAME.
SET TPBLOCK TO TRUE.
SET TPNOTRAN TO TRUE.
SET TPREPLY TO TRUE.
SET TPNOTIME TO TRUE.
SET TPSIGRSTRT TO TRUE.
CALL "TPACALL" USING
TPSVCDEF-REC
TPTYPE-REC
BUY-REC
TPSTATUS-REC.
IF NOT TPOK
error processing
. . .
MOVE 0 TO T-OUT.
CALL "TPBEGIN" USING
TPTRXDEF-REC
TPSTATUS-REC.
IF NOT TPOK
error processing
* ERROR TP-STATUS is set to TPEPROTO
. . .
program statements
. . .
SET TPBLOCK TO TRUE.
SET TPNOTRAN TO TRUE.
SET TPCHANGE TO TRUE.
SET TPNOTIME TO TRUE.
SET TPSIGRSTRT TO TRUE.
SET TPGETANY TO TRUE.
CALL "TPGETRPLY" USING
TPSVCDEF-REC
TPTYPE-REC
WK-AREA
TPSTATUS-REC.
IF NOT TPOK
error processing

If TPBEGIN is called with either of these two conditions existing, the call will fail because of an error in protocol and TP-STATUS will be set to TPEPROTO. If the process is in transaction mode, the transaction is unaffected by the failure.

Any service subroutines that are called within the transaction delimiters of TPBEGIN and TPCOMMIT/TPABORT become part of the current transaction. However, if TPCALL or TPACALL have explicitly set TPNOTRAN, the operations performed by the called service do not become part of that transaction. This in effect means that the calling process is not inviting the called service to be a participant in the current transaction. As a result, any services performed by the called process will not be affected by the outcome of the current transaction. It should be noted here that a call made with TPNOTRAN set that is directed to a service in an XA-compliant server group may produce unexpected results. See the discussion under "Implicitly Defining a Global Transaction" later in this chapter.

Starting the Transaction

The transaction is started by a call to TPBEGIN. The value of T-OUT indicates the least amount of time in seconds that a transaction should be given before timing out. If 0 is specified for this parameter, the transaction is given the maximum number of seconds allowed by the system before timing out (that is, the time-out value will equal the maximum value for an unsigned long as defined by the system).

Note: The use of 0 or unrealistically large values for the T-OUT parameter delays system detection and reporting of errors. A time-out value is used to ensure response to service requests within a reasonable time, and to terminate transactions that have encountered problems such as network failures prior to commit. For a transaction in which a human is waiting for a response, a small value, often less than 30 seconds, is best. In a production system, the time-out value should be large enough to accommodate expected delays due to system load, and database contention; a small multiple of the expected average response time is often an appropriate choice.

If a transaction times out, it is aborted. You can determine if a transaction has timed out by testing the value of TP-STATUS as illustrated in Listing 14-3. Note that if the transaction timed out and it goes untested, a call to TPCOMMIT will still cause the transaction to be aborted. In this case, TPCOMMIT fails and returns TPEABORT in TP-STATUS and the transaction is implicitly aborted.

The value assigned to the T-OUT parameter should be consistent with the SCANUNIT parameter set by the BEA TUXEDO system administrator in the configuration file. The system parameter specifies the frequency with which timed-out transactions and blocked calls are looked for. Its value represents an interval of time between periodic scans to find old transactions and timed out blocking calls within service requests. The T-OUT parameter should be set to a value that is greater than the scanning unit. If the time-out value were smaller, there would be some discrepancy between the time the transaction timed out and its discovery. The default value for SCANUNIT is 10 seconds. The value you give to T-OUT may need to be coordinated with your system administrator to be sure it makes sense with regard to the system parameters.

Listing 14-3 illustrates the starting of a transaction with the time-out value set to 30 seconds followed by a check to see if a timeout occurred.

Listing 14-3 Testing for Transaction Time Out
. . .
MOVE 30 TO T-OUT.
CALL "TPBEGIN" USING TPTRXDEF-REC TPSTATUS-REC.
IF NOT TPOK
MOVE "Failed to BEGIN a transaction" TO LOG-REC-TEXT.
MOVE 29 to LOG-REC-LEN
CALL "USERLOG" USING
LOG-REC-TEXT
LOG-REC-LEN
TPSTATUS-REC
CALL "TPTERM" USING
TPSTATUS-REC
PERFORM A-999-EXIT.
. . .
communication CALL statements
. . .
IF TPETIME
CALL "TPABORT" USING
TPTRXDEF-REC
TPSTATUS-REC
IF NOT TPOK
error processing
ELSE
CALL "TPCOMMIT" USING
TPTRXDEF-REC
TPSTATUS-REC
IF NOT TPOK
error processing

Note that a transaction is still subject to timing out even when a process calls on another with the TPNOTRAN communication flag set. This will be further discussed in Chapter 15, "Error Management."

The example in Listing 14-4 illustrates how to define a transaction.

Listing 14-4 Defining a Transaction
 DATA DIVISION.
WORKING-STORAGE SECTION.
*
01 TPTYPE-REC.
COPY TPTYPE.
*
01 TPSTATUS-REC.
COPY TPSTATUS.
*
01 TPINFDEF-REC.
COPY TPINFDEF.
*
01 TPSVCDEF-REC.
COPY TPSVCDEF.
*
01 TPTRXDEF-REC.
COPY TPTRXDEF.
*
01 LOG-REC PIC X(30) VALUE " ".
01 LOG-REC-LEN PIC S9(9) COMP-5.
*
01 USR-DATA-REC PIC X(16).
*
01 AUDV-REC.
05 AUDV-BRANCH-ID PIC S9(9) COMP-5.
05 AUDV-BALANCE PIC S9(9) COMP-5.
05 AUDV-ERRMSG PIC X(60).
*
PROCEDURE DIVISION.
*
A-000.
. . .
* Get Command Line Options set Variables (Q-BRANCH)
MOVE SPACES TO USRNAME.
MOVE SPACES TO CLTNAME.
MOVE SPACES TO PASSWD.
MOVE SPACES TO GRPNAME.
CALL "TPINITIALIZE" USING TPINFDEF-REC
USR-DATA-REC
TPSTATUS-REC.
IF NOT TPOK
MOVE "Failed to join application" TO LOG-REC
MOVE 26 TO LOG-REC-LEN
CALL "USERLOG" USING LOG-REC
LOG-REC-LEN
TPSTATUS-REC
PERFORM A-999-EXIT.
* Start global transaction
MOVE 30 TO T-OUT.
CALL "TPBEGIN" USING TPTRXDEF-REC TPSTATUS-REC.
IF NOT TPOK
MOVE 29 to LOG-REC-LEN
MOVE "Failed to begin a transaction" TO LOG-REC
CALL "USERLOG" USING LOG-REC
LOG-REC-LEN
TPSTATUS-REC
PERFORM DO-TPTERM.
* Set up record
MOVE Q-BRANCH TO AUDV-BRANCH-ID.
MOVE ZEROS TO AUDV-BALANCE.
MOVE SPACES TO AUDV-ERRMSG.
* Set up TPCALL records
MOVE "GETBALANCE" TO SERVICE-NAME.
MOVE "VIEW" TO REC-TYPE.
MOVE LENGTH OF AUDV-REC TO LEN.
SET TPBLOCK TO TRUE.
SET TPTRAN IN TPSVCDEF-REC TO TRUE.
SET TPNOTIME TO TRUE.
SET TPSIGRSTRT TO TRUE.
SET TPCHANGE TO TRUE.
*
CALL "TPCALL" USING TPSVCDEF-REC
TPTYPE-REC
AUDV-REC
TPTYPE-REC
AUDV-REC
TPSTATUS-REC.
IF NOT TPOK
MOVE 19 to LOG-REC-LEN
MOVE "Service call failed" TO LOG-REC
CALL "USERLOG" USING LOG-REC
LOG-REC-LEN
TPSTATUS-REC
PERFORM DO-TPABORT
PERFORM DO-TPTERM.
* Commit global transaction
CALL "TPCOMMIT" USING TPTRXDEF-REC
TPSTATUS-REC
IF NOT TPOK
MOVE 16 to LOG-REC-LEN
MOVE "Failed to commit" TO LOG-REC
CALL "USERLOG" USING LOG-REC
LOG-REC-LEN
TPSTATUS-REC
PERFORM DO-TPTERM.
* Show results only when transaction has completed successfully
DISPLAY "BRANCH=" Q-BRANCH.
DISPLAY "BALANCE=" AUDV-BALANCE.
PERFORM DO-TPTERM.
* Abort the transaction
DO-TPABORT.
CALL "TPABORT" USING TPTRXDEF-REC
TPSTATUS-REC
IF NOT TPOK
MOVE 26 to LOG-REC-LEN
MOVE "Failed to abort transaction" TO LOG-REC
CALL "USERLOG" USING LOG-REC
LOG-REC-LEN
TPSTATUS-REC.
* Leave the application
DO-TPTERM.
CALL "TPTERM" USING TPSTATUS-REC.
IF NOT TPOK
MOVE 27 to LOG-REC-LEN
MOVE "Failed to leave application" TO LOG-REC
CALL "USERLOG" USING LOG-REC
LOG-REC-LEN
TPSTATUS-REC.
EXIT PROGRAM.
*
A-999-EXIT.
*
EXIT PROGRAM.

Terminating the Transaction

As already indicated, a transaction is terminated by a call to either TPCOMMIT or TPABORT. When TPCOMMIT returns successfully, all changes to the resource as a result of the current transaction become permanent. TPABORT is called to indicate an abnormal condition and explicitly aborts the transaction and invalidates the communications handles of any outstanding replies. None of the changes that were produced as a result of the transaction are applied to the resource. For TPCOMMIT to succeed, the following two conditions must be true:

If either condition is not true, the call fails and TP-STATUS is set to TPEPROTO indicating an error in protocol. If a participant calls TPCOMMIT or TPABORT, the transaction is unaffected. If TPCOMMIT is called by the initiator with outstanding replies, the transaction is aborted and those reply descriptors become invalid.

TPCOMMIT Initiates the 2-phase Commit

When TPCOMMIT is called, it initiates the two-phase commit protocol mentioned earlier. This protocol, as the name suggests, has two parts. In the first, each participating resource manager indicates a readiness to commit. In the second, the initiator gives permission to commit. The process that calls TPCOMMIT must be the initiator of the transaction. As the initiator, this process starts the commit processing in which the participants (the other server processes that took part in the transaction) communicate their success or failure. This can be made known to the initiator by TPRETURN through the TP-RETURN-VAL parameter that can be set to either TPSUCCESS or TPFAIL. If TPFAIL has been returned, TPCOMMIT fails, TP-STATUS is set to TPEABORT, and the transaction is implicitly aborted. All the work that is performed by every process that participated in that transaction is undone. More will be said about the transaction role of TPRETURN and TPFORWAR in Chapter 15, "Error Management."

Setting When TPCOMMIT Should Return

When more than one machine is involved in a transaction, the application can elect to specify that TPCOMMIT should return successfully when all participants have indicated a readiness to commit; that is, when phase 1 of the two-phase commit has been logged as complete by all participants. The alternative choice is to have TPCOMMIT wait until all participants have finished phase 2 of the two-phase commit. The CMTRET parameter in the RESOURCES section of UBBCONFIG can be set to either LOGGED or COMPLETE to control this characteristic. The routine TPSCMT can be called with TPCMTDEF-REC set to either TP-CMT-LOGGED or TP-CMT-COMPLETE to override the setting in the configuration file.

The idea behind this option is that most of the time when all participants in a global transaction have logged successful completion of phase 1, they will not fail to complete phase 2. By setting TP-COMMIT-CONTROL to LOGGED you allow slightly faster return of calls to TPCOMMIT, but you run the slight risk that a participant (probably on a remote node) may heuristically complete its part of the transaction in a way that is not consistent with the commit decision. Whether it is prudent to accept the risk depends to a large extent on the nature of your application. If your application demands complete accuracy (for example, if you are running a financial application) you would probably prefer to allow for the time required for all participants fully to complete the two-phase commit process. If you are counting beans, you may prefer to have the application run as fast as possible even knowing you may be a few beans off over a period of time.

Testing for Participant Errors

Listing 14-5 shows a client making a synchronous call to a fictitious REPORT service (line 24). It demonstrates testing for errors that can be returned on a communication call that indicate participant failure (lines 30-42).

Listing 14-5 Testing for Participant Success or Failure
01   . . .
02 CALL "TPINITIALIZE" USING TPINFDEF-REC
03 USR-DATA-REC
04 TPSTATUS-REC.
05 IF NOT TPOK
06 error message,
07 EXIT PROGRAM .
08 MOVE 30 TO T-OUT.
09 CALL "TPBEGIN" USING TPTRXDEF-REC TPSTATUS-REC.
10 IF NOT TPOK
11 error message,
12 PERFORM DO-TPTERM.
13 * Set up record
14 MOVE "REPORT=accrcv DBNAME=accounts" TP-RECORD.
15 MOVE 27 TO LEN.
16 MOVE "REPORTS" TO SERVICE-NAME.
17 MOVE "STRING" TO REC-TYPE.
18 SET TPBLOCK TO TRUE.
19 SET TPTRAN IN TPSVCDEF-REC TO TRUE.
20 SET TPNOTIME TO TRUE.
21 SET TPSIGRSTRT TO TRUE.
22 SET TPCHANGE TO TRUE.
23 *
24 CALL "TPCALL" USING TPSVCDEF-REC
25 TPTYPE-REC
26 TP-RECORD
27 TPTYPE-REC
28 TP-RECORD
29 TPSTATUS-REC.
30 IF TPOK
31 PERFORM DO-TPCOMMIT
32 PERFORM DO-TPTERM.
33 * Check return status
34 IF TPESVCERR
35 DISPLAY "REPORT service's TPRETURN encountered problems"
36 ELSE IF TPESVCFAIL
37 DISPLAY "REPORT service FAILED with return code=" APPL-RETURN-CODE
38 ELSE IF TPEOTYPE
39 DISPLAY "REPORT service's reply is not of any known REC-TYPE"
40 *
41 PERFORM DO-TPABORT
42 PERFORM DO-TPTERM.
43 * Commit global transaction
44 DO-TPCOMMIT.
45 CALL "TPCOMMIT" USING TPTRXDEF-REC
46 TPSTATUS-REC
47 IF NOT TPOK
48 error message
49 * Abort the transaction
50 DO-TPABORT.
51 CALL "TPABORT" USING TPTRXDEF-REC
52 TPSTATUS-REC
53 IF NOT TPOK
54 error message
55 * Leave the application
56 DO-TPTERM.
57 CALL "TPTERM" USING TPSTATUS-REC.
58 IF NOT TPOK
59 error message
60 EXIT PROGRAM.

Committing a Transaction in Conversational Mode

Figure 14-1 shows a conversational connection hierarchy that includes a global transaction. The originator of a connection in transaction mode (process A that called TPBEGIN followed by TPCONNECT) can call TPCOMMIT after all services have called TPRETURN. If a hierarchy of connections exists as it does in Figure 14-1, each subordinate service must call TPRETURN when it no longer has replies outstanding. A TPEV-SVCSUCC or TPEV-SVCFAIL event setting for TPEVENT IN TPSTATUS-REC is sent back up the hierarchy to the process that began the transaction. If all subordinates return successfully, the client (Process A) completes the transaction; otherwise the transaction is aborted.

Figure 14-1 Connection Hierarchy: Transaction Mode

Implicitly Defining a Global Transaction

Besides using the ATMI calls explicitly to start and end a transaction, it is possible for a global transaction to be started in a service routine. A service routine can be placed in transaction mode through the system parameter, AUTOTRAN, in the configuration file. If AUTOTRAN is set to Y, a transaction is automatically started in the service subroutine when a request message is received from another process. Let's look at some variations on this theme.

Because a service can automatically be placed in transaction mode, it is possible for the call to be made with the communication setting of TPNOTRAN and the setting member of the service information structure to return TPTRAN when queried.

What a Service in an XA-Compliant Server Group Expects

A service that is part of an XA-compliant server group is generally written to perform some operation via the group's resource manager, which automatically opened the associated database when the application was booted. In the normal case, the service expects to do its work within a transaction. If a service like this is called with the caller's communication setting of TPNOTRAN, the results of the ensuing database operation may be a little strange.

The solution is to write your application so that services in groups associated with XA-compliant resource managers are always called in transaction mode or are always defined in the configuration file with AUTOTRAN=Y. Another precaution is to test early in the service code to see what the transaction level is.

Testing Whether a Transaction has Begun

In order correctly to interpret the error messages that can occur, it is important to know if a process is in transaction mode or not. It is an error for a process that is already in transaction mode to make a call to TPBEGIN. TPBEGIN will fail and set TP-STATUS to TPEPROTO to indicate that the routine was invoked while the caller was already in a transaction. However, the transaction will not be affected.

It might be helpful to think of transaction mode as something that is propagated unless specifically suppressed. When one process in transaction mode calls on the services of another process, that process acquires the same "condition."

Service subroutines can be written so that they test to see if they are already in transaction mode before invoking TPBEGIN. Testing transaction level can be done by querying the settings of the service information structure that is passed to the service routine. If its value is set to TPTRAN, the service is in transaction mode. Also, this information can be retrieved by calling the TPGETLEV routine. The syntax of this routine is:

01 TPTRXLEV-REC.
COPY TPTRXLEV.
01 TPSTATUS-REC.
COPY TPSTATUS.
CALL "TPGETLEV" USING TPTRXLEV-REC TPSTATUS-REC.

TPGETLEV returns TP-NOT-IN-TRAN if the caller is not in a transaction and TP-IN-TRAN if it is.

Listing 14-6 is an example of a service that shows testing for transaction level using the TPGETLEV routine (line 3). If the process is not in transaction mode, it starts one (line 5). If TPBEGIN fails, a message is returned to the status line (line 9) and APPL-CODE IN TPSVCRET-REC is set to a code that can be retrieved in APPL-RETURN-CODE IN TPSTATUS-REC (line 11 and line 1).

If the AUTOTRAN configuration parameter discussed above is set to Y, you avoid the overhead of testing for transaction level and the need of explicitly calling the TPBEGIN and TPCOMMIT/TPABORT transaction routines. For example, in the fragment shown in Listing 14-6, if the service is always to be called in transaction mode, the system parameters AUTOTRAN and TRANTIME can be set in the configuration file eliminating the need to define the transaction or determine its existence within the programming code (line 4).

Listing 14-6 Testing Transaction Level
     . . . Application defined codes
001 77 BEG-FAILED PIC S9(9) VALUE 3.
. . .
002 PROCEDURE DIVISION.
. . .
003 CALL "TPGETLEV" USING TPTRCLEV-REC
TPSTATUS-REC.
004 IF NOT TPOK
error processing EXIT PROGRAM
005 IF TP-NOT-IN-TRAN
006 MOVE 30 TO T-OUT.
007 CALL "TPBEGIN" USING
TPTRXDEF-REC
TPSTATUS-REC.
008 IF NOT TPOK
009 MOVE "Attempt to TPBEGIN within service failed"
TO USER-MESSAGE.
010 SET TPFAIL TO TRUE.
011 MOVE BEG-FAILED TO APPL-CODE.
012 COPY TPRETURN REPLACING
DATA-REC BY USER-MESSAGE.
. . .



[Top] [Prev] [Next] [Bottom]