9.7 Testing Whether a Transaction Has Started

When a process in transaction mode requests a service from another process, the latter process becomes part of the transaction, unless specifically instructed not to join it.

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 tperrno(5) 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:

  • Querying the flags field of the service information structure that is passed to the service routine. The service is in transaction mode if the value is set to TPTRAN.
  • Calling the tpgetlev(3c) function.

Use the following signature to call the tpgetlev() function:

int
tpgetlev() /* Get current transaction level */

The tpgetlev() function requires no arguments. It returns 0 if the caller is not in a transaction, and 1 if it is.

The following listing is a variation of the OPEN_ACCT service that shows how to test for transaction level using the tpgetlev() function (line 12). If the process is not already in transaction mode, the application starts a transaction (line 14). If tpbegin() fails, a message is returned to the status line (line 16) and the rcode argument of tpreturn() is set to a code that can be retrieved in the global variable tpurcode(5) (lines 1 and 17).

Listing Testing Transaction Level

001 #define BEGFAIL     3     /* tpurcode setting for return if tpbegin fails */
002 void
003 OPEN_ACCT(transb)

004 TPSVCINFO *transb;

005 {
 ... other declarations ...
006 FBFR *transf;     /* fielded buffer of decoded message */
007 int dotran;      /* checks whether service tpbegin/tpcommit/tpaborts */

008 /* set pointer to TPSVCINFO data buffer */
009 transf = (FBFR *)transb->data;

010 /* Test if transaction exists; initiate if no, check if yes */

011 dotran = 0;
012 if (tpgetlev() == 0) {
013     dotran = 1;
014     if (tpbegin(30, 0) == -1) {
015         Fchg(transf, STATLIN, 0,
016             "Attempt to tpbegin within service routine failed\n");
017     tpreturn(TPFAIL, BEGFAIL, transb->data, 0, 0);
018     }
019 }
    . . .

If the AUTOTRAN parameter is set to Y, you do not need to call the tpbegin(), and tpcommit() or tpabort() transaction functions 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 (see lines 7 and 10-19). 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:

  • Description of the AUTOTRAN configuration parameter in the section Implicitly Defining a Global Transaction in Setting Up an Oracle Tuxedo Application.
  • TRANTIME configuration parameter in Setting Up an Oracle Tuxedo Application.
  • Using Tuxedo with Oracle Real Application Clusters (RAC) in Setting Up an Oracle Tuxedo Application.