Reliable Transaction Router
Application Design Guide


Previous Contents Index

Channel Identifier

To specify the location to return the channel identifier , use the channel argument in the rtr_open_channel call. For example,

rtr_channel_t channel;
or
rtr_channel_t
*p_channel = &channel;

This parameter points to a valid channel identifier when the application receives an rtr_mt_opened message.

Flags Parameter

To define the application role type (client or server), use the flags parameter . For example,


 rtr_ope_flag_t 
 flags = RTR_F_OPE_CLIENT; 

or


 flags = RTR_F_OPE_SERVER; 

Facility Name

The facility name is a required string supplied by the application. It identifies the RTR facility used by the application. The default facility name for the RTR CLI only is RTR$DEFAULT_FACILITY ; there is no default facility name for an RTR application. You must supply one.

To define the facility name, use the facnam parameter. For example,


 rtr_facnam_t 
 facnam = "DESIGN"; 

Recipient Name

To specify a recipient name, use the rcpnam parameter, which is case sensitive. For example,


 rtr_rcpnam_t 
 rcpnam  = "* Rogers"; 

Event Number

To specify user event numbers, use the evtnum parameter. For example,


rtr_evtnum_t all user_events[]={ 
    RTR_EVTNUM_USERDEF, 
        RTR_EVTNUM_USERBASE, 
        RTR_EVTNUM_UP_TO, 
        RTR_EVTNUM_USERMAX, 
    RTR_EVTNUM_ENDLIST 
}; 

There are both RTR events and user events. For additional information on employing events, see the Broadcast Messaging Processes section of this chapter, and the section on RTR Events in the Reliable Transaction Router C Application Programmer's Reference Manual .

Access Key

You can use the facility access key to restrict client or server access to a facility. The key acts as a password to restrict access to the specific facility for which it is declared.

To define the facility access key, use the access parameter. For example,


  rtr_access_t 
   access = "amalasuntha"; 

The facility access key is a string supplied by the application. The first server channel in an RTR facility defines the access key; all subsequent server and client open channel requests must specify the same access value. To use no access key, use RTR_NO_ACCESS or NULL for the access argument.

You can also use this feature for version control. By changing the access code whenever an incompatible protocol change is made in the application message format, client applications are prevented from processing transactions with the server applications.

Key Segments

To specify the number of key segments defined for a server application, use the numseg parameter. For example,


 rtr_numseg_t 
  numseg = 2; 

Partition or Key Range

To specify the key range for a partition to do data-content routing, the server application defines the routing key when it opens a channel on a facility with the rtr_open_channel call. All servers in a facility must specify the same offset, length, and data type for the key segments in the rtr_open_channel call; only high and low bounds ( *ks_lo_bound, *ks_hi_bound ) can be unique to each server key segment. By application convention, the client places key data in the message at the offset, length, and data type defined by the server.

Channel-Open Operation

The channel-open operation completes asynchronously. Call completion status is returned in a subsequent message. RTR sends a message to the application indicating successful or unsuccessful completion; the application receives the status message using an rtr_receive_message call. If status is rtr_mt_opened , the open operation is successful. If status is rtr_mt_closed , the open operation is unsuccessful, and the application must examine the failure and respond accordingly. The channel is closed.

Determining Message Status

Data returned in the user buffer with rtr_mt_opened and rtr_mt_closed include both the status and a reason. For example,


case rtr_mt_opened: 
  printf(" Channel %d opened\n", channel); 
  status = RTR_STS_OK; 
  break; 
case rtr_mt_closed: 
  p_status_data = (rtr_status_data_t *)txn_msg; 
  printf(" cannot open channel because %s\n", 
   rtr_error_text(p_status_data->status)); 
  exit(-1); 

Use the call rtr_error_text to find the meaning of returned status. A client channel will receive no message at all if a facility is configured but no server is available. Once a server becomes available, RTR sends the rtr_mt_opened message.

Closing a Channel

To close a channel, the application uses the rtr_close_channel call. A channel can be closed at any time after it has been opened. Once closed, no further operations can be performed on a channel, and no further messages for the channel are received.

Receiving on a Channel

To receive on a channel and obtain status information from RTR, use the rtr_receive_message call. To receive on any open channel, use the RTR_ANYCHAN value for the p_rcvchan parameter in the rtr_receive_message call. To receive from a list of channels, use the p_rcvchan parameter as a pointer to a list of channels, ending the list with RTR_CHAN_ENDLIST . An application can receive on one or more opened channels. RTR returns the channel identifier. A pointer to a channel is supplied on the rtr_open_channel call, and RTR returns the channel identification (ID) by filling in the contents of that pointer.

User Handles

To simplify matching an RTR channel ID with an application thread, an application can associate a user handle with a channel. The handle is returned in the message status block with the rtr_receive_message call. The application can use the message status block ( MsgStatusBlock ) to identify the message type of a received message. For example,


{ 
rtr_receive_message (&channel, RTR_NO_FLAGS, RTR_ANYCHAN, txn_msg, maxlen, 
RTR_NO_TIMOUTMS, 
MsgStatusBlock); 
} . . . 
   typedef struct { 
   rtr_msg_type_t  msgtype; 
   rtr_usrhdl_t      usrhdl; 
   rtr_msglen_t     msglen; 
   rtr_tid_t  tid; 
   rtr_evtnum_t     evtnum; 
   } rtr_msgsb_t; 

RTR delivers both RTR and application messages when the rtr_receive_message call completes. The application can use the message type indicator in the message status block to determine relevant buffer format. For further details on using message types and interpreting the contents of the user buffer, see the Reliable Transaction Router C Application Programmer's Reference Manual .

Message Reception Styles

An application can specify one of three reception styles for the rtr_receive_message call. These are:

Blocking Receive

An application can use a blocking receive to wait until a message arrives. To use a blocking receive, include RTR_NO_TIMOUTMS in the rtr_receive_message call. The call completes only when a message is available on one of the specified channels. For example,


rtr_receive_message (&channel, RTR_NO_FLAGS, RTR_ANYCHAN, 
  MsgBuffer, DataLen, RTR_NO_TIMOUTMS, &MsgStatusBlock); 

Polled Receive

An application can use a polled receive to poll RTR with a specified timeout. To use a polled receive, the application can set a value in milliseconds on the timoutms parameter. The timeout can be:

The call completes after the specified timeout or when a message is available on one of the specified channels.

For example, the following declaration sets polling at 1 second (1000 milliseconds).


rtr_receive_message(&channel, RTR_NO_FLAGS, RTR_ANYCHAN, MsgBuffer, DataLen, 
1000, &MsgStatusBlock); 

Note

The rtr_receive_message timeout is not the same as a transaction timeout.

Signaled Receive

An application can use a signaled receive to be alerted by RTR when a message is received. The application establishes a signal handler using the rtr_set_wakeup call, informing RTR where to call it back when the message is ready.

To use a signaled receive, the application uses the rtr_set_wakeup call and provides the address of a routine to be called by RTR when a message is available. When the wakeup routine is called, the application can use the rtr_receive_message call to get the message. For example,


rtr_status_t 
rtr_set_wakeup( 
  procedure  ) 
void 
wakeup_handler(void){ 
 rtr_receive_message(); 
} 
 
main(){ 
 rtr_set_wakeup(wakeup_handler); 
 sleep(); 
} 

Note

To disable wakeup, call rtr_set_wakeup with a null routine address.

When using rtr_set_wakeup in a multithreaded application, be careful not to call any non-reentrant functions or tie up system resources unnecessarily inside the callback routine.

The rtr_open_channel parameters are further described in the Reliable Transaction Router C Application Programmer's Reference Manual.

Starting a Transaction

There are two ways to start a transaction:

Using the rtr_start_tx Call

Use the rtr_start_tx call when the application must set a client-side transaction timeout to ensure that both client and server do not wait too long for a message. When a transaction is started with rtr_send_to_server , no timeout is specified.

For example,


 rtr_start_tx(&Channel, 
        RTR_NO_FLAGS, 
        RTR_NO_TIMOUTMS, 
        RTR_NO_JOINCHAN); //or NULL 

Using the rtr_send_to_server Call

The rtr_send_to_server call sends a message as part of a transaction from a client. If there is no transaction currently active on the channel, a new one is started. The transaction accept can be bundled with the last message. A client has two options for message delivery after a failure:

Using the rtr_reply_to_client Call

The rtr_reply_to_client call sends a reply message from a server to the client. The reply message is part of the transaction initiated by the client. For example,


status = rtr_reply_to_client (&Channel, 
                              RTR_NO_FLAGS, 
                              MsgBuffer, 
                              DataLen, 
                              RTR_NO_MSGFMT); 

The reply message format can be of any form as designed by the application. For example,


     struct acct_inq_msg_t { 
                            char reply_text[80]; 
                           } acct_reply_msg; 

Identifying a Transaction

When an application receives a message with the rtr_receive_message call, the message status block ( MsgStatusBlock ) contains the transaction identifier. For example,


status = rtr_receive_message (&Channel, 
                              RTR_NO_FLAGS, 
                              RTR_ANYCHAN, 
                              MsgBuffer, 
                              DataLen, 
                              RTR_NO_TIMOUTMS, 
                              &MsgStatusBlock); 

The pointer &MsgStatusBlock points to the message status block that describes the received message. For example,


 typedef struct {rtr_msg_type_t         msgtype; 
                 rtr_usrhdl_t           usrhdl; 
                 rtr_msglen_t           msglen; 
                 rtr_tid_t              tid;     
/*If a transactional message, the transaction ID or tid, msgsb.tid */ 
                 rtr_evtnum_t           evtnum; 
                } rtr_msgsb_t; 

Use the rtr_get_tid call to obtain the RTR transaction identifier for the current transaction. The TID (transaction identifier) is a unique number generated by RTR for each transaction. The application can use the TID if the client needs to know the TID to take some action before receiving a response.

Use the rtr_set_user_handle call to set a user handle on a transaction instead of using a channel. A client application with multiple transactions outstanding can match a reply or completion status with the appropriate transaction by establishing a new user handle each time a transaction is started.

Committing a Transaction

A server application ends a transaction by accepting or rejecting it. A transaction is accepted explicitly with the rtr_accept_tx call, and rejected explicitly with the rtr_reject_tx call. RTR can reject a transaction at any time once the transaction is started, but before it is committed. If RTR cannot deliver a transaction to its destination, it rejects the transaction explicitly and delivers the reject completion status to all participants.

A transaction participant can specify a reason for an accept or reject on the rtr_accept_tx and rtr_reject_tx call. If more than one transaction participant specifies a reason, RTR uses the OR operator to combine the reason values together. For example, with two servers A and B, each providing a reason code of 1 and 2, respectively, the client receives the result of the OR operation, reason code 3, in its message buffer.


Server A                      Server B 
 rtr_reason_t                 rtr_reason_t 
  reason = 1 ;                reason=2 ; 
  rtr_reject_tx (             rtr_reject_tx ( 
  channel,                    channel, 
  flags,                      flags, 
  reason );                   reason ); 
typedef struct { 
  rtr_status_t status; 
  rtr_reason_t reason; 
} rtr_status_data_t; 
 

The client receives the results of the OR operation in its message buffer:


rtr_status_data_t 
    msgbuf; 
    msgbuf.reason = 3; 

A transaction is done once a client or server application receives a completion message, either an rtr_mt_closed, rtr_mt_accepted , or rtr_mt_rejected message from RTR. An application no longer receives messages related to a transaction after receiving a completion message or if the application calls rtr_reject_tx . A client or server can also specify RTR_F_ACC_FORGET on the rtr_accept_tx call to signal its acceptance and end its involvement in a transaction early. RTR returns no more messages (including completion messages) associated with the transaction; any such messages received will be returned to the caller.

When issuing the rtr_accept_tx call with RTR_NO_FLAGS on the call, the caller expresses its request for successful completion of the transaction, and may give an accept reason that is passed on to all participants in the transaction. The accept is final; the caller cannot reject the transaction later. The caller cannot send any more messages for this transaction.

A client can accept a transaction in one of two ways: with the rtr_accept_tx call or by using the RTR_F_SEN_ACCEPT flag on the rtr_send_to_server call.

When the client sets RTR_F_SEN_ACCEPT on the rtr_send_to_server call, this removes the need to issue an rtr_accept_tx call and can help optimization of client traffic. Merging the data and accept messages in one call puts them in a single network packet. This can make better use of network resources and improve throughput.

The rtr_reject_tx call rejects a transaction. Any participant in a transaction can call rtr_reject_tx . The reject is final; the caller cannot accept the transaction later. The caller can specify a reject reason that is passed to all accepting participants of the transaction. Once the transaction has been rejected, the caller receives no more messages for this transaction.

The server can set the retry flag RTR_F_REJ_RETRY to have RTR redeliver the transaction beginning with msg1 without aborting the transaction for other participants. Issuing an rtr_reject_tx call with this flag can let another transaction proceed if locks held by this transaction cause a database deadlock.

Uncertain Transactions

If there is a crash before the rtr_accept_tx statement is executed, on recovery, the transaction is replayed as rtr_mt_msg1 because the database will have rolled back the prior transaction instance. However, if there is a crash after the rtr_accept_tx statement is executed, on recovery, the transaction is replayed as rtr_mt_msg1_uncertain because RTR does not know the status of the prior transaction instance. Your application must understand the implications of such failures and deal with them appropriately.

Administering Transaction Timeouts

RTR provides a relatively simple way to administer a transaction timeout in the server. Use of timeout values on the rtr_receive_message function lets a server application specify how long it is prepared to wait for the next message. (Of course, the server should be prepared to wait forever to get a new transaction or for the result of an already-voted transaction.)

One way to achieve this would be to have a channel-specific global variable, say, called SERVER_INACTIVITY_TIMEOUT , which is set to the desired value (in milliseconds-that is, use a value of 5000 to set a 5 second timeout). Note that this timeout value should be used after receiving the first message of the transaction. The value should be reset to RTR_NO_TIMOUTMS after receiving the rtr_mt_prepare message. Whenever the rtr_receive_message completes with a RTR_STS_TIMOUT , the server calls the rtr_reject_tx function on that channel to abort the partially- processed transaction. This would prevent transactions from occupying the server process beyond a reasonable time.


Previous Next Contents Index