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 toTPTRAN
. - 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.
Parent topic: Writing Global Transactions