Programming an Oracle Tuxedo Application Using COBOL

     Previous  Next    Open TOC in new window    View as PDF - New Window  Get Adobe Reader - New Window
Content starts here

Writing Global Transactions

This topic includes the following sections:

 


What Is a Global Transaction?

A global transaction is a mechanism that allows a set of programming tasks, potentially using more than one resource manager and potentially executing on multiple servers, to be treated as one logical unit.

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 referred to as transaction participants. The value returned by a participant may affect the outcome of the transaction.

A global transaction may be composed of several local transactions, each accessing the same resource manager. The resource manager is responsible for performing concurrency control and atomicity of updates. A given local transaction may be either successful or unsuccessful in completing its access; it cannot be partially successful.

A maximum of 16 server groups can participate in a single transaction.

The Oracle Tuxedo system manages a global transaction in conjunction with the participating resource managers and treats it as a specific sequence of operations that is characterized by atomicity, consistency, isolation, and durability. In other words, a global transaction is a logical unit of work in which:

The Oracle Tuxedo system tracks the status of each global transaction and determines whether it should be committed or rolled back.

 


Starting the Transaction

To start a global transaction, use the TPBE GIN(3cbl) routine with the following signature:

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

Table 9-1 describes the TPTRXDEF-REC structure fields

Table 9-1 TPTRXDEF Structure Field
Field
Description
T-OUT
Specifies the amount of time, in seconds, a transaction can execute before timing out. You can set this value to the maximum number of seconds allowed by the system, by specifying a value of 0. In other words, you can set timeout to the maximum value for an unsigned long as defined by the system.
The use of 0 or an unrealistically large value for the T-OUT parameter delays system detection and reporting of errors. The system uses the T-OUT parameter to ensure that responses to service requests are sent within a reasonable time, and to terminate transactions that encounter problems such as network failures before executing a commit.
For a transaction in which a person is waiting for a response, you should set this parameter to a small value: if possible, less than 30 seconds.
In a production system, you should set T-OUT to a value 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.

Note: The value assigned to the T-OUT parameter should be consistent with that of the SCANUNIT parameter set by the Oracle Tuxedo application administrator in the configuration file. The SCANUNIT parameter specifies the frequency with which the system checks, or scans, for timed-out transactions and blocked calls in service requests. The value of this parameter represents the interval of time between these periodic scans, referred to as the scanning unit.

You should set the T-OUT parameter to a value that is greater than the scanning unit. If you set the T-OUT parameter to a value smaller than the scanning unit, there will be a discrepancy between the time at which a transaction times out and the time at which this timeout is discovered by the system. The default value for SCANUNIT is 10 seconds. You may need to discuss the setting of the T-OUT parameter with your application administrator to make sure the value you assign to the T-OUT parameter is compatible with the values assigned to your system parameters.

TRANID
Transaction identifier.

Any process may call TPBEGIN unless the process is already in transaction mode. If TPBEGIN is called in transaction mode, the call fails due to a protocol error and TP-STATUS is set to TPEPROTO. If the process is in transaction mode, the transaction is unaffected by the failure.

The following example provides a high-level view of how a global transaction is defined.

Listing 9-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 following example shows how an outstanding reply can cause an error.

Listing 9-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.
vIF 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 a transaction times out, a call to TPCOMMIT causes the transaction to be aborted. As a result, TPCOMMIT fails and sets TP-STATUS to TPEABORT.

The following example shows how to test for a transaction timeout. Note that the value of T-OUT is set to 30 seconds.

Listing 9-3 Testing for Transaction Timeout
. . .
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: When a process is in transaction mode and makes a communication call with TPNOTRAN, it prohibits the called service from becoming a participant in the current transaction. Whether the service request succeeds or fails has no impact on the outcome of the transaction. The transaction can still timeout while waiting for a reply that is due from a service, whether it is part of the transaction or not. Refer to “Managing Errors” in Programming Oracle Tuxedo ATMI Applications Using C for more information on the effects of the TPNOTRAN flag.

The following example shows how to define a transaction.

Listing 9-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

To end a global transaction, call TPCOMM IT(3cbl) to commit the current transaction, or TPABORT( 3cbl) to abort the transaction and roll back all operations.

Note: If TPCALL, TPACALL, or TPCONNECT is called by a process that has explicitly set TPNOTRAN, the operations performed by the called service do not become part of the current transaction. In other words, when you call the TPABORT routine, the operations performed by these services are not rolled back.

Committing the Current Transaction

The TPCOMM IT(3cbl) routine commits the current transaction. When TPCOMMIT returns successfully, all changes to resources as a result of the current transaction become permanent.

Use the following signature to call the TPCOMMIT routine:

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

Refer to Starting the Transaction for a description of the TPTRXDEF-REC structure.

Prerequisites for a Transaction Commit

For TPCOMMIT to succeed, the following conditions must be true:

If the first condition is false, the call fails and TP-STATUS is set to TPEPROTO, indicating a protocol error. If the second or third condition is false, the call fails and TP-STATUS is set to TPEABORT, indicating that the transaction has been rolled back. If TPCOMMIT is called by the initiator with outstanding transaction replies, the transaction is aborted and those reply descriptors associated with the transaction become invalid. If a participant calls TPCOMMIT or TPABORT, the transaction is unaffected.

A transaction is placed in a rollback-only state if any service call returns TPFAIL or indicates a service error. If TPCOMMIT is called for a rollback-only transaction, the routine cancels the transaction, returns -1, and sets TP-STATUS to TPEABORT. The results are the same if TPCOMMIT is called for a transaction that has already timed out: TPCOMMIT returns -1 and sets TP-STATUS to TPEABORT. Refer to “Managing Errors” in Programming Oracle Tuxedo ATMI Applications Using C for more information on transaction errors.

Two-phase Commit Protocol

When the TPCOMMIT routine is called, it initiates the two-phase commit protocol. This protocol, as the name suggests, consists of two steps:

  1. Each participating resource manager indicates a readiness to commit.
  2. The initiator of the transaction gives permission to commit to each participating resource manager.

The commit sequence begins when the transaction initiator calls the TPCOMMIT routine. The Oracle Tuxedo TMS server process in the designated coordinator group contacts the TMS in each participant group that is to perform the first phase of the commit protocol. The TMS in each group then instructs the resource manager (RM) in that group to commit using the XA protocol that is defined for communications between the Transaction Managers and RMs. The RM writes, to stable storage, the states of the transaction before and after the commit sequence, and indicates success or failure to the TMS. The TMS then passes the response back to the coordinating TMS.

When the coordinating TMS has received a success indication from all groups, it logs a statement to the effect that a transaction is being committed and sends second-phase commit notifications to all participant groups. The RM in each group then finalizes the transaction updates.

If the coordinator TMS is notified of a first-phase commit failure from any group, or if it fails to receive a reply from any group, it sends a rollback notification to each RM and the RMs back out all transaction updates. TPCOMMIT then fails and sets TP-STATUS to TPEABORT.

Selecting Criteria for a Successful Commit

When more than one group is involved in a transaction, you can specify which of two criteria must be met for TPCOMMIT to return successfully:

To specify one of these prerequisites, set the CMTRET parameter in the RESOURCES section of the configuration file to one of the following values:

By default, CMTRET is set to COMPLETE.

Trade-offs Between Possible Commit Criteria

In most cases, when all participants in a global transaction have logged successful completion of phase 1, they do not fail to complete phase 2. By setting CMTRET to LOGGED, you allow a slightly faster return of calls to TCOMMIT, but you run the slight risk that a participant 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 should probably wait until all participants fully complete the two-phase commit process before returning. If your application is more time-sensitive, you may prefer to have the application execute faster at the expense of accuracy.

Aborting the Current Transaction

Use the TPABORT (3cbl) routine to indicate an abnormal condition and explicitly abort a transaction. This function invalidates the call descriptors of any outstanding transactional replies. None of the changes produced by the transaction are applied to the resource. Use the following signature to call the TPABORT routine:

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

Refer to Starting the Transaction for a description of the TPTRXDEF-REC structure.

Example: Committing a Transaction in Conversational Mode

Figure 9-1 illustrates a conversational connection hierarchy that includes a global transaction.

Figure 9-1 Connection Hierarchy in Transaction Mode

The connection hierarchy is created through the following process:

  1. A client (process A) initiates a connection in transaction mode by calling TPBEGIN and TPCONNECT.
  2. The client calls subsidiary services, which are executed.
  3. As each subordinate service completes, it sends a reply indicating success or failure (TPEV_SVCSUCC or TPEV_SVCFAIL, respectively) back up through the hierarchy to the process that initiated the transaction. In this example the process that initiated the transaction is the client (process A). When a subordinate service has completed sending replies (that is, when no more replies are outstanding), it must call TPRETURN.
  4. The client (process A) determines whether all subordinate services have returned successfully.
    • If so, the client commits the changes made by those services, by calling TPCOMMIT, and completes the transaction.
    • If not, the client calls TPABORT, since it knows that TPCOMMIT could not be successful.

Example: Testing for Participant Errors

In the following sample code, a client makes a synchronous call to the fictitious REPORT service (line 24). Then the code checks for participant failures by testing for errors that can be returned on a communication call (lines 30-42).

Listing 9-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.

 


Implicitly Defining a Global Transaction

An application can start a global transaction in either of two ways:

This section describes the second method.

You can implicitly place a service routine in transaction mode by setting the system parameter AUTOTRAN in the configuration file. If you set AUTOTRAN to Y, the system automatically starts a transaction in the service subroutine when a request is received from another process.

When implicitly defining a transaction, observe the following rules:

Note: Because a service can be placed in transaction mode automatically, it is possible for a service with the TPNOTRAN flag set to call services that have the AUTOTRAN parameter set. If such a service requests another service, the member of the service information structure returns TPTRAN when queried. For example, if the call is made with TPNOTRAN | TPNOREPLY, and the service automatically starts a transaction when called, the information structure is set to TPTRAN | TPNOREPLY.

 


Defining Global Transactions for an XA-Compliant Server Group

Generally, the application programmer writes a service that is part of an XA-compliant server group to perform some operation via the group’s resource manager. In the normal case, the service expects to perform all operations within a transaction. If, on the other hand, the service is called with the communication setting of TPNOTRAN, you may receive unexpected results when executing database operations.

In order to avoid unexpected behavior, design the 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 set to Y. You should also test the transaction level in the service code early.

 


Testing Whether a Transaction Has Started

It is important to know whether or not a process is in transaction mode in order to avoid and interpret certain error conditions. For example, it is an error for a process already in transaction mode to call TPBEGIN. When TPBEGIN is called by such a process, it fails and sets TP-STATUS to TPEPROTO to indicate that it was invoked while the caller was already participating in a transaction. The transaction is not affected.

You can design a service subroutine so that it tests whether it is in transaction mode before invoking TPBEGIN. You can test the transaction level by either of the following methods:

Use the following signature to call the TPGETLEV routine:

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 the caller is.

The following code sample shows how to test for transaction level using the TPGETLEV routine (line 3). If the process is not already in transaction mode, the application starts a transaction (line 5). If TPBEGIN fails, a message is returned to the status line (line 9) and APPL-CODE IN TPSVCRET-REC of TPRETURN is set to a code that can be retrieved in APL-RETURN-CODE IN TPSTATUS-REC (lines 1 and 11).

Listing 9-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
013 DATA-REC BY USER-MESSAGE.
     . . .

If the AUTOTRAN parameter is set to Y, you do not need to call the TPBEGIN, and TPCOMMIT or TPABORT transaction routines explicitly. As a result, you can avoid the overhead of testing for transaction level. In addition, you can set the TRANTIME parameter to specify the time-out interval: the amount of time that may elapse after a transaction for a service begins, and before it is rolled back if not completed.

For example, suppose you are revising the OPEN_ACCT service shown in the preceding code listing. Currently, OPEN_ACCT defines the transaction explicitly and then tests for its existence. To reduce the overhead introduced by these tasks, you can eliminate them from the code. Therefore, you need to require that whenever OPEN_ACCT is called, it is called in transaction mode. To specify this requirement, enable the AUTOTRAN and TRANTIME system parameters in the configuration file.

See Also


  Back to Top       Previous  Next