Reliable Transaction Router
Application Design Guide


Previous Contents Index

RTR Message Types

RTR calls and responses to them contain RTR message types (mt) such as rtr_mt_reply or rtr_mt_rejected . The four groups of message types, listed in Table 5-4, are:

Table 5-4 RTR Message Types
Transactional Status Event-related Informational
rtr_mt_msg1 rtr_mt_accepted rtr_mt_user_event rtr_mt_opened
rtr_mt_msg1_uncertain rtr_mt_rejected rtr_mt_rtr_event rtr_mt_closed
rtr_mt_msgn rtr_mt_prepare   rtr_mt_request_info
rtr_mt_reply rtr_mt_prepared   rtr_mt_rettosend

Applications should include code for all RTR expected return message types. Message types are returned to the application in the message status block. For more detail on message types see the Reliable Transaction Router C Application Programmer's Reference Manual. Figure 5-1 shows the RTR C API calls you use to achieve transactional messaging in your application.

Figure 5-1 RTR C API Calls for Transactional Messaging


Message Format Definitions

To work in a mixed-operating system environment, an application can specify a message format definition on the following calls:

RTR performs data marshaling, evaluating and converting data appropriately as directed by the message format descriptions provided in the application.

The following example shows an RTR application using a message format declaration; first the RTR call specifying that TXN_MSG_FMT contains the actual format declaration, then the definition used by the call.

RTR application call:


status = rtr_send_to_server(p_channel, 
                            RTR_NOFLAGS, 
                            &txn_msg, 
                            msg_size, 
                            TXN_MSG_FMT ); 

Data definition: #define TXN_MSG_FMT "%1C%UL%7UL%31C"

This data structure accommodates an 8-bit signed character field ( C ) for the key, a 32-bit unsigned field (UL) for the server number, a 224-bit (7x32) field (7UL) for the transaction ID, and a 31-bit byte (248-bit) field (31C) for character text. For details of defining message format for a mixed-endian environment, see the Reliable Transaction Router C Application Programmer's Reference Manual.

Using the XA Protocol

You use the XA protocol supported by RTR to communicate with an X/Open Distributed Transaction Processing (DTP) conformant resource manager. This eliminates the need for an application program to process rtr_mt_uncertain messages. For examples of system setup, see the RTR System Manager's Manual, Appendix C.

XA Oracle Example

Note

In this example, error checking has been omitted for clarity.


 int main( int argc, char argv[] ) 
{ 
     server_key[0].ks_type = rtr_keyseg_unsigned; 
     server_key[0].ks_length = sizeof(rtr_uns_8_t); 
     server_key[0].ks_offset = 0; 
     server_key[0].ks_lo_bound = &low; 
     server_key[0].ks_hi_bound = &high; 
     server_key[1].ks_type = rtr_keyseg_rmname;          /* RM name */ 
     server_key[1].ks_length = 0;                        /* not applicable */ 
     server_key[1].ks_offset = 0; 
     server_key[1].ks_lo_bound = rm_name; 
     server_key[1].ks_hi_bound = xa_open_string; 
     
     (flag = RTR_F_OPE_SERVER | 
      RTR_F_OPE_NOSTANDBY | 
      RTR_F_OPE_XA_MANAGED |                       /* XA flag */ 
      RTR_F_OPE_EXPLICIT_PREPARE | 
      RTR_F_OPE_EXPLICIT_ACCEPT; 
rtr_open_channel(&server_channel, flag, fac_name, NULL, RTR_NO_PEVTNUM, 
                 NULL, 2, server_key); 
while (rtr_receive_message(&server_channel, RTR_NO_FLAGS, RTR_ANYCHAN, 
    &receive_msg,sizeof(receive_msg), RTR_NO_TIMOUTMS, &msgsb) 
         == RTR_STS_OK) 
   { ... 
    msg = receive_msg.receive_data_msg; 
    
    (switch(msgsb.msgtype) 
       { 
     case rtr_mt_msg1: 
     case rtr_mt_msgn: 
       switch(msg.txn_type) 
         { 
     case ... 
        EXEC SQL ... 
         } 
             ... 
rtr_reply_to_client(server_channel, RTR_NO_FLAGS, &reply_msg, 
sizeof(reply_msg), RTR_NO_MSGFMT); 
              ... 
     case rtr_mt_prepare: 
              ... 
rtr_accept_tx(s_chan,RTR_NO_FLAGS,RTR_NO_REASON); 
              ... 
     case rtr_mt_accepted: 
      /* EXEC SQL COMMIT;   Comment out SQL Commits */ 
      break; 
     case rtr_mt_rejected: 
      /* EXEC SQL ROLLBACK;  Comment out SQL rollbacks */ 
      break; 
      /* 
     case rtr_mt_msg1_uncertain: 
              ... 
      */ 
       }      ... 
    } 
       EXEC SQL COMMIT WORK RELEASE; 
              ... 
} 

Using XA with MS DTC

The XA software architecture of RTR provides interoperability with the Distributed Transaction Controller of Microsoft, MS DTC . Thus RTR users can develop application programs that update MS SQL databases, MS MQ, or other Microsoft resource managers under the control of a true distributed transaction. RTR as a distributed transaction manager communicates directly with MS DTC to manage a transaction or perform recovery using the XA protocol. For each standard XA call received from RTR, MS DTC translates it into a corresponding OLE transaction call that SQL Server or MS MQ expects to perform database updates. This is shown in Figure 5-2.

Figure 5-2 MS DTC and RTR


For example, using XA and DTC (Compaq Tru64 UNIX and Microsoft Windows NT only) eliminates the need to process uncertain messages rtr_mt_msg1_uncertain ). To use the XA protocol with RTR, you must:

Both the resource manager instance name and the database (RM) name in [OPEN- STRING] must be identical to that in the previously executed REGISTER RM command. The information is stored in the RTR key segment structure, and the RTR_F_OPE_XA_MANAGED flag associates the channel with the XA interface.

Only one transaction at a time is processed on an RTR channel; thus a server process or thread of control can only open one channel to handle a single XA request. Better throughput can be achieved by using a multithreaded application.

For example, the following code from a sample server application shows use of the RM key, the XA flag, and commenting out commits and rollbacks for the Oracle and DTC environments.

XA DTC Example

The following XA/DTC server application example is for a Windows NT environment only.

Note

In this example, error checking has been omitted for clarity.


int main( int argc, char argv[] ) 
{ 
 server_key[0].ks_type = rtr_keyseg_unsigned; 
 server_key[0].ks_length = sizeof(rtr_uns_8_t); 
 server_key[0].ks_offset = 0; 
 server_key[0].ks_lo_bound = &low; 
 server_key[0].ks_hi_bound = &high; 
 server_key[1].ks_type = rtr_keyseg_rmname;  /* RM name */ 
 server_key[1].ks_length = sizeof(String32)+sizeof(String128); 
 server_key[1].ks_offset = 0; 
 server_key[1].ks_lo_bound = rm_name; 
 server_key[1].ks_hi_bound = xa_open_string; 
 
 flag = RTR_F_OPE_SERVER | 
  RTR_F_OPE_XA_MANAGED |               /* XA flag */ 
  RTR_F_OPE_NOSTANDBY | 
  RTR_F_OPE_EXPLICIT_PREPARE | 
  RTR_F_OPE_EXPLICIT_ACCEPT; 
/* Connect SQL server thru DB-Library */ 
dbinit(); 
login = dblogin(); 
DBSETLUSER(login, sql_username); 
DBSETLPWD(login, sql_password); 
dbproc = dbopen(login, sql_servername); 
dbfreelogin(login); 
dbuse(dbproc, sql_dbname); 
 
rtr_open_channel(&server_channel, flag, fac_name, 
 NULL, RTR_NO_PEVTNUM, NULL,2, server_key); 
             ... 
rtr_receive_message(&server_channel, RTR_NO_FLAGS, RTR_ANYCHAN, 
           &receive_msg,sizeof(receive_msg), RTR_NO_TIMOUTMS, &msgsb) 
           == RTR_STS_OK) 
                             ... 
while (rtr_receive_message(&server_channel, RTR_NO_FLAGS, RTR_ANYCHAN, 
     &receive_msg, sizeof(receive_msg), RTR_NO_TIMOUTMS, &msgsb); 
              ... 
   msg = receive_msg.receive_data_msg; 
     switch(msgsb.msgtype) 
     { 
        case rtr_mt_msg1: 
   dbenlistxatrans(dbproc, RTR_TRUE); 
      /* Remove uncertain processing 
        case rtr_mt_msg1_uncertain: 
              ... 
      */ 
        case rtr_mt_msgn: 
   switch(msg.txn_type) 
    { 
            case 
             ... 
               dbfcmd(dbproc, "..."); 
               dbsqlexec(dbproc); 
              while(1) { 
                         dbresults(dbproc); 
          ... 
                         break; 
                        } 
                ... 
    rtr_reply_to_client(server_channel, RTR_NO_FLAGS, 
                   &reply_msg, sizeof(reply_msg), RTR_NO_MSGFMT); 
                ... 
          case rtr_mt_prepare: 
                ... 
    rtr_accept_tx(s_chan,RTR_NO_FLAGS,RTR_NO_REASON); 
                 ... 
          case rtr_mt_accepted: 
          /* EXEC SQL COMMIT;    Comment out SQL Commits */ 
          case rtr_mt_rejected: 
           /* EXEC SQL ROLLBACK;Comment out SQL rollbacks */ 
                 ... 
 } 
  exit(0); 
} 

Using DECdtm

You can use the DECdtm protocol to communicate with OpenVMS Rdb. This provides a two-phase commit capability. For additional information on using this protocol, see the OpenVMS documentation, for example, Managing DECdtm Services in the OpenVMS System Manager's Manual, and the Oracle Rdb Guide to Distributed Transactions available from Oracle.

Nested Transactions

Nested transactions extend transactional control rights between two transaction domains. To implement nested transactions, the application uses the following RTR C API calls:

For additional details on the syntax and use of these calls, see the Reliable Transaction Router C Application Programmer's Reference Manual.

When using nested transactions, a journal is required on the frontend node used for nested transactions, if that node does not already support a backend.

The transactional outcome of the nested transaction is delivered to the RTR client that starts the nested transaction. This provides a flexible model where parent and nested transactions can commit independently if required by the application. For example, using nested transactions, several outcomes are possible:

The application must provide the logic to perform the correct processing based on each case and the requirements of the application.

To start a global transaction, an application uses rtr_open_channel and rtr_start_tx . For example,

To engage the nested transaction, the application uses rtr_send_to_server and rtr_prepare_tx . For example,


rtr_send_to_server(... pmsg, msglen, ...) 
 
rtr_prepare_tx(channel, flags, reason, 
               pmsg,               /* blob / 
               msglen)             /* blob length */ 

The client process sends the data to the nested resource on the client channel that has started the nested transaction. When the client process is ready to complete the transaction, it must first determine if the nested transaction can complete:

Nested Transaction Example

The RTR application client establishes the connection with rtr_open_channel and rtr_start_tx . For example,


   rtr_open_channel(..., flags=RTR_F_OPE_CLIENT, ...) 
   rtr_start_tx(..., jointxid=XA_txid, ...) 
   rtr_send_to_server(msg1) 
   rtr_send_to_server(msg2) 
   rtr_prepare_tx() 
   rtr_receive_message() 
   rtr_accept_tx() 
 

The RTR application server also uses rtr_open_channel , combined with rtr_receive_message . For example,


   rtr_open_channel(..., flags=RTR_F_OPE_SERVER,...) 
   rtr_receive_message() 
   rtr_receive_message() 
   rtr_receive_message() 
   rtr_receive_message() 
   rtr_accept_tx() 
   rtr_receive_message() 

This sequence establishes the following dialog between the client and server applications. On the client application, when the rtr_start_tx call is executed, RTR sends an rtr_mt_opened message to both client and server applications. The server application receives this message with the rtr_receive_message call. The client sends its first message to the server as rtr_mt_msg1 , followed by rtr_mt_msgn and rtr_mt_prepare . The server application responds to the client with an rtr_mt_prepared message, and the client sends back an rtr_mt_accepted message.

For recovery of nested transactions, in the event of failure of the client application or of the node where an RTR nested transaction is started, the superior transaction manager must be able to determine which transactions are in an indeterminate state. Before the rtr_mt_opened message is delivered to the client application, RTR scans the local journal and creates a list of in-doubt (prepared) transactions. After the rtr_mt_opened message has been delivered to the application, the application must ask RTR if there are any transactions in an incomplete state. This is achieved with the rtr_request_info call. For example,


   status= rtr_request_info(...
        rtr_info_class_t = "ftx", 
        rtr_itemcode_t = "$name",       /* Select item */ 
        rtr_selval_t = "facility_name", 
        rtr_itemcode_t = "kr_id, tx_id" /* Get items */ 
 ...) ; 

The rtr_request_info call returns information about the prepared transactions for the specified facility.

In another example, user data passed in the pmsg parameter (blob) of the rtr_prepare_tx call is retrieved during recovery of a prepared, nested transaction. The XID specified by the foreign transaction manager ( rtr_xid_t ) is also available. Sample code follows:


   status= rtr_request_info(...
        rtr_info_class_t = "ftx", 
        rtr_itemcode_t = "txid",       /* Select item */ 
        rtr_selval_t = "tx id value from previous call", 
        rtr_itemcode_t = "xid, state, jnl_state, sr_state, 
                  bloblen, blob"      /* Get items */ 
 ...); 

Table 5-5 lists possible client actions based on the contents of the journal state ( jnl_state ) field.

Table 5-5 Client Action Based on Journal State
State in Journal Action
rtr_tx_jnl_prepare Participants are waiting for final phase of two-phase commit. Set the transaction state to either COMMIT or ABORT using the rtr_set_info statement.
rtr_tx_jnl_commit RTR is waiting for confirmation that the superior transaction has been committed. The next operation on this channel implicitly forgets this transaction.
rtr_tx_jnl_abort RTR is waiting for confirmation that the superior transaction has been aborted. The next operation on this channel implicitly forgets this transaction.

RTR Transaction Processing

To pass transactions from client to server, RTR (with the C API) uses channel s as identifiers. Each application communicates with RTR on a particular channel. In a multithreaded application, when multiple transactions are outstanding, the application uses the channel to inform RTR which transaction a command is for.

With RTR, the client or server application can:

To open a channel, the application uses the rtr_open_channel call. This opens a channel for communication with a client or server application on a specific facility. Each application process can open up to 255 channels.

For example, the rtr_open_channel call in this client application opens a single channel for the facility called DESIGN:


status = rtr_open_channel(&Channel,    
         RTR_F_OPE_CLIENT, [1] 
         DESIGN,            /* Facility name */ [2]
         client_name, 
         rtrEvents, 
         NULL,              /* Access key / [3]   
         RTR_NO_NUMSEG, 
         RTR_NO_PKEYSEG     /* Key range */ [4] 
         ); 

The application uses parameters on the rtr_open_channel call to define the application environment. Typically, the application defines the:

For a server application, the rtr_open_channel call additionally supplies the number of key segments, numseg , and the partition name, in pkeyseg .

The syntax of the rtr_open_channel call is as follows:


   status = rtr_open_channel (pchannel,flags,facnam,rcpnam, 
   pevtnum,access,numseg,pkeyseg) 

You can set up a variable section in your client program to define the required parameters and then set up your rtr_open_channel call to pass those parameters. For example, the variables definition would contain code similar to the following:


/* 
** ---------------- Variables ------------------- 
*/ 
rtr_status_t Status; 
rtr_channel_t Channel; 
rtr_ope_flag_t Flags  = RTR_F_OPE_CLIENT; 
rtr_facnam_t        Facility  = "DESIGN"; 
rtr_rcpnam_t        Recipient  = RTR_NO_RCPNAM; 
rtr_access_t        Access  = RTR_NO_ACCESS; 

The rtr_open_channel call would contain:


status = rtr_open_channel(&Channel, 
                          Flags, 
                          Facility, 
                          Recipient, 
                          Evtnum, 
                          Access, 
                          RTR_NO_NUMSEG, 
                          RTR_NO_PKEYSEG); 
if (Status != RTR_STS_OK)  
/* 
{ Provide for error return */} 

You will find more complete samples of client and server code in the appendix of this document and on the RTR software kit in the Examples directory.


Previous Next Contents Index