Reliable Transaction Router
Application Design Guide


Previous Contents Index

Two-Phase Commit

The two-phase commit process includes prepare and commit phases. A transaction is tentatively accepted or rejected during the prepare phase.

Prepare Phase

To initiate the prepare phase, the server application specifies the RTR_F_OPE_EXPLICIT_PREPARE flag when opening the channel, and can use the message rtr_mt_prepare to check commit status. The message indicates to the server application that it is time to prepare any updates for a later commit or rollback operation. RTR lets the server application explicitly accept a transaction using the RTR_F_OPE_EXPLICIT_ACCEPT flag on the rtr_open_channel call. Alternatively, RTR implicitly accepts the transaction after receiving the rtr_mt_accepted message when the server issues its next rtr_receive_message call.

The commit process is initiated by the client application when it issues a call to RTR indicating that the client "accepts" the transaction. This does not mean that the transaction is fully accepted, only that the client is prepared to accept it. RTR then asks the server applications participating in the transaction if they are prepared to accept the transaction. A server application that is prepared to accept the transaction votes its intention by issuing the rtr_accept_tx call, an "accept" vote. A server application that is not prepared to accept the transaction issues the rtr_reject_tx call, a "not accept" vote. Issuing all votes concludes the prepare phase.

Commit Phase

When RTR has collected all votes from all participating server applications, it determines if the transaction is to be committed. If all collected votes are "accept," the transaction is committed; RTR informs all participating channels. If any vote is "not accept," the transaction is not committed. A server application can expose the prepare phase of two-phase commit by using the rtr_mt_prepare message type with the RTR_F_OPE_EXPLICIT_PREPARE flag. If the application's rtr_open_channel call sets neither the RTR_F_OPE_EXPLICIT_ACCEPT nor RTR_F_OPE_EXPLICIT_PREPARE flag, both prepare and accept processing are implicit.

The server application can participate in the two-phase commit process fully, somewhat, a little, or not at all. To participate fully, the server does an explicit prepare and an explicit accept of the transaction. To participate somewhat, the server does an explicit prepare and an implicit accept of the transaction. To participate a little, the server does an explicit accept of the transaction. To participate not at all, the server does an implicit accept of the transaction. Table 5-6 summarizes the level of server participation:

Table 5-6 Server Participation
Commit Phase Full Somewhat Little Not at all
Explicit prepare yes yes    
Explicit accept yes   yes  
Implicit accept   yes   yes

Your application can use the level of participation that makes the most sense for your business and operations needs.

Explicit Accept, Explicit Prepare

To request an explicit accept and explicit prepare of transactions, the server channel is opened with the RTR_F_OPE_EXPLICIT_PREPARE and RTR_F_OPE_EXPLICIT_ACCEPT flags. These specify that the channel will receive both prepare and accept messages. The server then explicitly accepts or rejects a transaction when it receives the prepare message. The transaction sequence for an explicit prepare and explicit accept is as follows:
Client RTR Server
rtr_start_tx    
rtr_send_to_server -> rtr_mt_msg1 -> rtr_receive_message
rtr_accept_tx -> rtr_mt_prepare -> rtr_receive_message
    <- rtr_accept_tx
rtr_receive_message <- rtr_mt_accepted <- rtr_receive_message

With explicit transaction handling, the following steps occur:

  1. The server application waits for a message from the client application.
  2. The server application receives the rtr_mt_prepare request message from RTR.
  3. The server application issues the accept or reject.

A participant can reject the transaction up to the time RTR has sent the rtr_mt_prepare message type to the server in the rtr_accept_tx call. A participant can reject the transaction up to the time the rtr_accept_tx call is executed. Once the client application has called rtr_accept_tx , the result cannot be changed.

Implicit Prepare, Explicit Accept

The sequence for an implicit prepare and explicit accept is as follows:
Client RTR Server
rtr_start_tx    
rtr_send_to_server -> rtr_mt_msg1 -> rtr_receive_message
rtr_accept_tx -> <- rtr_accept_tx
rtr_receive_message <- rtr_mt_accepted <- rtr_receive_message

In certain database applications, where the database manager does not let an application explicitly prepare the database, transactions can simply be accepted or rejected. Server applications that do not specify the RTR_F_EXPLICIT_ACCEPT flag in their rtr_open_channel call implicitly accept the in-progress transaction when an rtr_receive_message call is issued after the last message has been received for the transaction. This call returns the final status for the transaction, rtr_mt_accepted or rtr_mt_rejected . If neither the RTR_F_OPE_EXPLICIT_ACCEPT nor the RTR_F_OPE_EXPLICT_PREPARE flags are set in the rtr_open_channel call, then both prepare and accept processing will be implicit.

For server optimization, the server can signal its acceptance of a transaction with either rtr_reply_to_client , using the RTR_F_REP_ACCEPT flag, or with the client issuing the rtr_send_to_server call, using the RTR_F_SEN_ACCEPT flag. This helps to minimize network traffic for transactions by increasing the likelihood that the data message and the RTR accept message will be sent in the same network packet.

Transaction Recovery

When a transaction fails in progress, RTR provides recovery support using RTR replay technology. RTR, as a distributed transaction manager, communicates with a database resource manager in directing the two-phase commit process. When using the XA protocol, the application does not need to process rtr_mt_uncertain messages (see the section Using XA, for more details on using XA).

The typical server application transaction sequence for committing a transaction to the database is as follows:


rtr_receive_message (rtr_mt_msg1) 
SQL update 
rtr_accept_tx 
rtr_receive_message (rtr_mt_accepted) 
SQL commit 
rtr_receive_message [wait for next transaction] 

This sequence is also illustrated in Figure 2-9, CSN Vote Window for the C API.

A failure can occur at any step in this sequence; the impact of a failure depends on when (at which step) it occurs, and on the server configuration.

Failure before rtr_accept_tx

If a failure occurs before the rtr_accept_tx call is issued, RTR causes the following to occur:

Failure after rtr_accept_tx

If a failure occurs after the rtr_accept_tx call is issued but before the rtr_receive_message , the transaction is replayed. The type of the first message is then rtr_mt_uncertain when the server is restarted. In this case, servers should check to see if the transaction has already been executed in a previous presentation. If not, it is safe to re-execute the transaction because the database operation never occurred. After the failure, the following occurs:

If a failure occurs after the SQL commit but before receipt of a message starting the next transaction, RTR does not know the difference.

If a failure occurs after an rtr_receive_message call is made to begin a new transaction, RTR assumes a successful commit if a server calls rtr_receive_message after receiving the rtr_mt_accepted message and will forget the transaction. There is no replay following these events.

Changing Transaction State

Under certain conditions, transactions may become blocked or hung, and applications can use certain RTR features to clear such roadblocks. Often, a blocked state can be cleared by the system manager using the SET TRANSACTION CLI command to change the state of a transaction, for example, to DONE. Only certain states, however, can be changed, and changing the state of a transaction manually can endanger the integrity of the application database. For information on using the SET TRANSACTION command from the CLI, see the Reliable Transaction Router System Manager's Manual.

To achieve a change of state within an application, the designer can use the rtr_set_info C API call. For example, the following code fragments illustrate how such application code could be written. Such code must be used in conjunction with a design that uses a change of state only when transactions are blocked.


rtr_tid_t tid; 
rtr_channel_t pchannel; 
rtr_qualifier_value_t select qualifiers[4]; 
rtr_qualifier_value_t set_qualifiers[3]; 
int select_idx = 0; 
int set_idx = 0; 
 
rtr_get_tid(pchannel, RTR_F_TID_RTR, &tid); 
 
/* Transaction branch to get current state */ 
 select_qualifiers[select_idx].qv_qualifier = rtr_txn_state; 
 select_qualifiers[select_idx].qv_value = &rtr_txn_state_commit; 
 select _ idx++; 
/* Transaction branch to set new state */ 
 set_qualifiers[set_idx].qv_qualifier = rtr_txn_state; 
 set_qualifiers[set_idx].qv_value = &rtr_txn_state_exception; 
 set_idx++; 
 
sts = rtr_set_info(pchannel, 
     (rtr_flags_t) 0, 
     (rtr_verb_t)verb_set, 
     rtr_transaction_object, 
     select_qualifiers, 
     set_qualifiers); 
if(sts != RTR_STS_OK) 
       write an error; 
 
sts = rtr_receive_message( 
  /* channel  */ &channel_id, 
  /* flags    */ RTR_NO_FLAGS, 
  /* prcvchan */ pchannel, 
  /* pmsg     */ msg, 
  /* maxlen   */ RTR_MAX_MSGLEN, 
  /* timoutms */ 0, 
  /* pmsgsb   */ &msgsb); 
if (sts == RTR_STS_OK){ 
 const rtr_status_data_t *pstatus = (rtr_status_data_t *)msg; 
 rtr_uns_32_t num; 
 
 switch(pstatus -> status) 
 { 
 case RTR_SETTRANDONE: /*Set Tran done successfully */ 
 memcpy(&num,(char)msg+sizeof(rtr_status_data_t), 
  sizeof(rtr_uns_32_t)); 
 
 printf(" %d transaction(s) have been processed\n"); 
 break; 
default; 
} 
} 

Exception on Transaction Handling

RTR keeps track of how many times a transaction is presented to a server application before it is VOTED. The rule is: three strikes and you're out! After the third strike, RTR rejects the transaction with the reason RTR_STS_SRVDIED . The server application has committed the transaction and the client believes that the transaction is committed. The transaction is flagged as an exception and the database is not committed. Such an exception transaction can be manually committed if necessary. This process eliminates the possibility that a single rogue transaction can crash all available copies of a server application at both primary and secondary sites.

Application design can change this behavior. The application can specify the retry count to use when in recovery using the /recovery_retry_count qualifier in the rtr_set_info call, or the system administrator can set the retry count from the RTR CLI with the SET PARTITION command. If no recovery retry count is specified, RTR retries replay three times. For recovery, retries are infinite. For more information on the SET PARTITION command, see the Reliable Transaction Router System Manager's Manual; for more information on the rtr_set_info call, see the Reliable Transaction Router C Application Programmer's Reference Manual .

When a node is down, the operator can select a different backend to use for the server restart. To complete any incomplete transactions, RTR searches the journals of all backend nodes of a facility for any transactions for the key range specified in the server's rtr_open_channel call.

Broadcast Messaging

Use the rtr_broadcast_event call to broadcast a user event message.

A user broadcast is named or unnamed. An unnamed broadcast does a match on user event number; the event number completely describes the event. A named broadcast does a match on user event number and recipient name. The recipient name is a user-defined string. Named broadcasts provide greater control over who receives a particular broadcast. Named events specify an event number and a textual recipient name. The name can include wildcards (% and *).

For all unnamed events, specify the evtnum field and RTR_NO_RCPSPC for the recipient name.

For example, the following code specifies named events for all subscribers:


rtr_status_t 
rtr_open_channel { 
 ... 
 rtr_rcpnam_t rcpnam = "*"; 
 rtr_evtnum_t evtnum = { 
  RTR_EVTNUM_USERDEF, 
   RTR_EVTNUM_USERBASE, 
   RTR_EVTNUM_UP_TO, 
   RTR_EVTNUM_USERMAX, 
  RTR_EVTNUM_ENDLIST 
 }; 
rtr_evtnum_t *p_evtnum = &evtnum; 

For a broadcast to be received by an application, the recipient name specified by the subscribing application on its rtr_open_channel call must match the recipient specifier used by the broadcast sender on the rtr_broadcast_event call.

Note

RTR_NO_RCPSPC is not the same as "*".

An application receives broadcasts with the rtr_receive_message call. A message type returned in the message status block informs the application of the type of broadcast received.

Authentication Using Callout Servers

RTR callout servers enable security checks to be carried out on all requests using a facility. Callout servers can run on either backend or router nodes. They receive a copy of every transaction delivered to, or passing through, the node, and they vote on every transaction. To enable a callout server, use the /CALLOUT qualifier when issuing the RTR CREATE FACILITY command. Callout servers are facility based, not key-range or partition based.

Router Callout Server

An application enables a callout server by setting a flag on the rtr_open_channel call.

For a router callout server, the application sets the following flag on the rtr_open_channel call:


  rtr_ope_flag_t 
          flags=RTR_F_OPE_SERVER |RTR_F_OPE_TR_CALL_OUT 

Backend Callout Server

For a backend callout server, the application sets the following flag on the rtr_open_channel call:


  rtr_ope_flag_t 
          flags=RTR_F_OPE_SERVER|RTR_F_OPE_BE_CALL_OUT 


Previous Next Contents Index