Previous | Contents | Index |
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:
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
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.
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.
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; ... } |
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.
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.
The following XA/DTC server application example is for a Windows NT environment only.
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); } |
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.
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:
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.
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. |
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 |