Reliable Transaction Router
C Application Programmer's
Reference Manual


Previous Contents Index

Example 3-2 Server Application

*************************************************************************** 
/* Open a channel in a server application. This server will 
 * handle only records where the last name begins with A. 
 * It also wants an explicit message sent when it is time 
 * to prepare the transaction, and one when it is time to 
 * vote whether to accept or reject the transaction. 
 */ 
rtr_channel_t   channel; 
rtr_status_t    status; 
rtr_keyseg_t    p_keyseg[1]; 
rtr_string_t    last = "A"; 
 
/* 
 * Use this rtr_keyseg_t structure to define this server as 
 * handling only those records whose last name begins 
 * with `A'. 
 */ 
p_keyseg[0].ks_type = rtr_keyseg_string; 
p_keyseg[0].ks_length  = 1; 
p_keyseg[0].ks_offset  =  0; 
p_keyseg[0].ks_lo_bound = last; 
p_keyseg[0].ks_hi_bound = last; 
 
/* Open the channel as a server that wants explicit ACCEPT and 
 * PREPARE messages. It is a member of the CcardPurchases 
 * facility, accepts no events (only messages) and we are 
 * sending 1 rtr_keyseg_t structure that defines those 
 * messages to be handled by this server. 
 * 
 * Note also that we are specifying that this channel 
 * will be `XA managed'; that is, the transaction manager 
 * will be one that implements the X/Open standard. 
 */ 
status = rtr_open_channel( 
                        &channel, 
    RTR_F_OPE_SERVER | RTR_F_OPE_EXPLICIT_ACCEPT | 
    RTR_F_OPE_EXPLICIT_PREPARE | RTR_OPE_XA_MANAGED, 
                  "CCardPurchases", 
                  NULL, 
                  RTR_NO_PEVTNUM, 
                  NULL, 
                  1, 
                  p_keyseg); 
check_status(status); 
 
 

For Use with XA

The snippets from a sample server application show use of the RM information, the XA flag, and commenting out RM commits and rollbacks.

Example 3-3 Sample XA Server Application

 
void 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 in use */ 
     server_key[1].ks_length = 0;              /* not applicable */ 
     server_key[1].ks_offset = 0; 
     server_key[1].ks_lo_bound = rm_name;      /* RM name */ 
     server_key[1].ks_hi_bound = xa_open_string; 
                                   /* RM 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); 
        ... 
     rtr_receive_message(&server_channel, 
            RTR_NO_FLAGS,RTR_ANYCHAN, 
         &receive_msg,sizeof(receive_msg), 
            RTR_NO_TIMOUTMS, &msgsb); 
        ... 
     do 
     { 
        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: 
           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 */ 
            case rtr_mt_accepted: 
                 /* EXEC SQL ROLLBACK;  Comment out SQL rollbacks */ 
 
              /* 
            case rtr_mt_msg1_uncertain: 
                 ... 
              */ 
                 ... 
        } 
            } while(...) 
 
            EXEC SQL COMMIT WORK RELEASE; 
            exit(0); 
       } 
 

Example 3-4 Use of Partition Names

/*  **  topen_channel.com  
 **  Demonstrate use of partition names           */ 
/*                                                */ 
/*                                                */ 
 
#include    "rtr.h" 
#include    <stdio.h> 
 
main() 
{ 
 
/* This program will open a server channel. Servers 
 * need to identify the partition they will be operating 
 * on by passing information coded in the pkeyseg argument. 
 * If the partition already exists and its name is known, 
 * it suffices to specify the partition name. If this is 
 * not the case, then the partition must be specified by 
 * describing the key segments. In the latter case, name 
 * information is optional. If present, the new partition 
 * will receive the specified name, otherwise a default 
 * name will be generated.                          */ 
/*                                                  */ 
 * This program assumes the presence of a partition named 
 * par_test in the facility fac_test and opens a server 
 * channel to it. Create the partition prior to running 
 * the program, e.g.,                               */ 
/*                                                  */ 
/* RTR> create partition par_test/facility=fac_test */ 
/*                                                  */ 
 
rtr_channel_t    AChannel; 
const char       *pszFacilityName    = "fac_test"; 
const char       *pszPartitionName   = "par_test"; 
rtr_status_t     status; 
rtr_ope_flag_t   flags  = RTR_F_OPE_SERVER; 
rtr_keyseg_t     partition_info; 
 
partition_info.ks_type          = rtr_keyseg_partition; 
partition_info.ks_lo_bound      = (rtr_pointer_t)pszPartitionName; 
partition_info.ks_hi_bound      = NULL;     
                         /* Must be NULL             */ 
 
status  = rtr_open_channel( 
                          &AChannel, 
                          flags, 
                          pszFacilityName, 
                          RTR_NO_RCPNAM, 
                          RTR_NO_PEVTNUM, 
                          RTR_NO_ACCESS, 
                          1, 
                          &partition_info); 
 
/* Call rtr_receive_message() to receive completion status    */ 
} 

See Also

rtr_close_channel()

rtr_prepare_tx

Send a transactional message to a server, in the context of nested transactions.

Syntax

status = rtr_prepare_tx (channel, flags, reason, pmsg, msglen)

Argument Data Type Access
status rtr_status_t write
channel rtr_channel_t read
flags rtr_pre_flag_t read
reason rtr_reason_t read
pmsg rtr_msgbuf_t read
msglen rtr_msglen_t read


C Binding

rtr_status_t rtr_prepare_tx (


rtr_channel_t channel ,
rtr_pre_flag_t flags ,
rtr_reason_t reason ,
rtr_msgbuf_t pmsg ,
rtr_msglen_t msglen ,
)


Arguments

channel

The channel identifier (returned earlier by the rtr_open_channel() call).

flags

No flags are currently defined. Specify RTR_NO_FLAGS for this parameter.

reason

Optional reason for preparing the transaction. The reason is ORed with the reasons of the other participants in the transaction and returned in the reason field of the rtr_status_data_t structure returned with the rtr_mt_prepared message to all participants in the transaction. Specify RTR_NO_REASON if no reason is required.

pmsg

Pointer to the message to be sent.

msglen

Length in bytes of the message to be sent, up to RTR_MAX_BLOB_LEN bytes. The value of RTR_MAX_BLOB_LEN is defined as 2048 in rtr.h .

Description

The rtr_prepare_tx() call can only be used in the context of nested transactions (that is, rtr_start_tx() was called with the parameter jointxid not equal to RTR_NO_JOINTXID ). If this call returns RTR_STS_OK, then the first (prepare) phase of the RTR two-phase commit protocol has been initiated.

A new message type is associated with this call, rtr_mt_prepared. Like the message types rtr_mt_accepted and rtr_mt_rejected, the rtr_mt_prepared message type returns data of type rtr_status_data_t in the user buffer. In this case, the status field of rtr_status_data_t is always RTR_STS_OK , and the reason field contains the same reason mask that would be returned in the rtr_mt_accepted message type for the same transaction were the transaction to be accepted. For an example of use of the reason mask, see the Reliable Transaction Router Application Design Guide.

Only when the rtr_mt_prepared message is delivered, can the application be sure that all participants of the nested transaction are ready to commit. Alternatively, calling rtr_prepare_tx() can cause delivery of the message rtr_mt_rejected, if one of the participating servers votes to reject the nested transaction.

The rtr_mt_prepared message is only delivered to the application if the rtr_prepare_tx is called.

A call to rtr_prepare_tx must be followed by a call to rtr_accept_tx (or rtr_reject_tx ), which in this context implements the commit phase of the two-phase commit. (Generally, rtr_prepare_tx and rtr_accept_tx will be called by the foreign transaction manager directly, not by the application.)

The reason parameter to rtr_prepare_tx is used in place of the reason parameter in the subsequent rtr_accept_tx call (that is, the reason field in the call to rtr_accept_tx or rtr_reject_tx which follows a call to rtr_prepare_tx is ignored).

The pmsg parameter can be used to pass a block of data to RTR that will be saved in the local journal. This data is not sent to the router or backends, and is used only during recovery, when it is passed back to the client application. RTR does not interpret or modify this data in any way.

The maximum size of data that can be passed in a prepare call is defined as RTR_MAX_BLOB_LEN .

Return Value A value indicating the status of the routine. Possible status values are:
RTR_STS_INSVIRMEM Insufficient virtual memory
RTR_STS_INVCHANNEL Invalid channel argument
RTR_STS_INVFLAGS Invalid flags argument
RTR_STS_INVMSGLEN Invalid msglen argument
The size of data in pmsg cannot be larger than RTR_MAX_BLOB_LEN .
RTR_STS_NOCURROU No router currently available for this frontend
RTR_STS_NOSRVAVL Service not yet available
RTR_STS_NOTNESTEDTX TX in progress is not nested
RTR_STS_OK Normal successful completion

Example


rtr_string_t prep_msg = 
"Preparing create_new_member transaction"; 
/* 
 * The transaction was explicitly started, and multiple 
 * messages sent. It is now time to commit the full 
 * transaction. The client notifies RTR and the server 
 * to prepare the transaction; this is the first phase of 
 * RTR's two-phase commit protocol. 
 */ 
        status = rtr_prepare_tx( 
                &channel, 
                RTR_NO_FLAGS, 
                RTR_NO_REASON, 
                prep_msg,               
        // Write this message to journal. 
                strlen(prep_msg)); 
 
        check_status(status); 
 
/* The client should now expect to receive an rtr_mt_prepared 
 * message from the server in a future rtr_receive_message call, 
 * indicating that all participants are prepared, and ready to 
 * commit the transaction. 
 */ 
status = rtr_receive_message( 
                        &channel, 
                        RTR_NO_FLAGS, 
                        RTR_ANYCHAN, 
                        &receive_msg, 
                        sizeof(receive_msg), 
                        receive_time_out, 
                        &msgsb); 
 
        check_status( status ); 
 
        if (msgsb.msgtype == rtr_mt_prepared) 
        { 
                status = rtr_accept_tx( 
                            &channel, 
                            RTR_NO_FLAGS, 
                            RTR_NO_REASON ); 
                check_status( status ); 
        } 
else 
        // Issue an error; possibly retry. 

See Also

rtr_receive_message()
rtr_open_channel()

rtr_receive_message

Receive a message from RTR or the application.

Syntax

status = rtr_receive_message (pchannel, flags, prcvchan, pmsg, maxlen, timoutms, pmsgsb)

Argument Data Type Access
status rtr_status_t write
pchannel rtr_channel_t write
flags rtr_rcv_flag_t read
prcvchan rtr_channel_t read
pmsg rtr_msgbuf_t write
maxlen rtr_msglen_t read
timoutms rtr_timout_t read
pmsgsb rtr_msgsb_t write


C Binding

rtr_status_t rtr_receive_message (


rtr_channel_t *pchannel ,
rtr_rcv_flag_t flags ,
rtr_channel_t *prcvchan ,
rtr_msgbuf_t pmsg ,
rtr_msglen_t maxlen ,
rtr_timout_t timoutms ,
rtr_msgsb_t *pmsgsb
)


Arguments

pchannel

The channel identifier on which the message was received.

flags

No flags are currently defined. Specify RTR_NO_FLAGS for this parameter.

prcvchan

A pointer to a list of channels on which a receive is required. This parameter can be used to select a subset of channels on which messages can be received. Terminate the list with RTR_CHAN_ENDLIST .

If no selection is required, that is, a receive from any open channel is acceptable, specify RTR_ANYCHAN for this parameter.

pmsg

Required pointer to the user buffer where the received message is written.

maxlen

Size allocated in the user buffer for received messages, in bytes.

timoutms

Receive timeout specified in milliseconds. If the timeout expires, the call completes with status RTR_STS_TIMOUT.

If no timeout is required, specify RTR_NO_TIMOUTMS .

pmsgsb

Pointer to a message status block describing the received message. The message status block is shown in Example 3-5.

Example 3-5 RTR Message Status Block

typedef struct          /* RTR message status block */ 
{ 
    rtr_msg_type_t msgtype; 
    rtr_usrhdl_t usrhdl; 
    rtr_msglen_t msglen; 
    rtr_tid_t  tid; 
    rtr_evtnum_t evtnum; 
} rtr_msgsb_t ; 

The msgtype field can assume one of the values listed in Table 2-2, RTR Received Message Types for Server Applications and Table 2-3, RTR Received Message Types for Client Applications.

The usrhdl field contains the value supplied with a call to rtr_set_user_handle() .

The msglen field contains the length of the data stored in the user buffer after the call has been executed.

The tid field contains the RTR unique ID for the transaction to which this received message belongs.

The evtnum field contains the event number if the msgtype field is rtr_mt_rtr_event or rtr_mt_user_event.


Description

The rtr_receive_message() call is used to receive a message.

The caller must have previously opened at least one channel (via rtr_open_channel() or rtr_request_info() ).

By default, this function waits for a message to become available if no message is currently ready to be received.

Upon successful return (RTR_STS_OK), the message status block pointed to by pmsgsb contains the description of the message received.

When a client application calls rtr_send_to_server , RTR sends the message from frontend to router. It is the router's job to find out which key range the message belongs to (by looking at the key field in the application message), and then to forward the message to the backend node where the server application for this key range is running. If the router does not know of a backend that has a server running for this key range, then the router aborts the transaction. In this case, the client application receives an rtr_mt_rejected message for this transaction with status RTR_STS_NODSTFND.

If a client application receives an RTR_STS_NODSTFND error, then the client can try to resend the transaction, as the cause may have been only temporary. Note that the reasons the router cannot find a backend node with an appropriate server include:

  1. The application server for this key range has not been started.
  2. The link between the router and backend has gone down.
  3. In unusual circumstances, a transaction can be rejected with RTR_STS_NODSTFND status after the client calls rtr_accept_tx . This can occur for transactions with multiple participants and no timeout specified where the link between the router (which is quorate) and one of the backend participants has gone down for a period greater than the router's transaction replay timeout period. (This can occur even if the messages in the transaction had all been sent with the RTR_F_SEN_EXPENDABLE flag set.)
Return Value A value indicating the status of the routine. Possible status values are:
RTR_STS_ACPNOTVIA RTR ACP not a viable entity
RTR_STS_INVCHANNEL Invalid channel argument
RTR_STS_INVFLAGS Invalid flags argument
RTR_STS_INVMSG Invalid pmsg argument
RTR_STS_INVRMNAME Invalid resource manager name
RTR_STS_NOACP No RTRACP process available
RTR_STS_NOCURROU No router currently available for this frontend
RTR_STS_NOSRVAVL Service not yet available
RTR_STS_OK Normal successful completion
RTR_STS_SRVDCLSBY Successful server declaration, but as standby
RTR_STS_TIMOUT Call to rtr_receive_message timed out
RTR_STS_TRUNCATED Buffer too short for msg

Message has been truncated


Example


status = rtr_receive_message( 
                        &channel, 
                        RTR_NO_FLAGS, 
                        RTR_ANYCHAN, 
                        &receive_msg, 
                        sizeof(receive_msg), 
                        receive_time_out, 
                        &msgsb); 
 
        check_status( "rtr_receive_message", status ); 
 
/* The rtr_msgsb_t tells us what type of 
 * message we are receiving. This server has asked to 
 * be notified when it is time to prepare the transaction. 
 * It should also handle other message types, as well. 
 */ 
        if (msgsb.msgtype == rtr_mt_prepare) 
        { 
                // Do the work necessary to prepare the transaction 
                // before committing. 

See Also

rtr_broadcast_event()
rtr_accept_tx()
rtr_open_channel()
rtr_reject_tx()
rtr_send_to_server()


Previous Next Contents Index