Reliable Transaction Router
Application Programmer's Reference Manual


Previous Contents Index


rtr_set_wakeup

Register a function to be called when a message arrives and no call to rtr_receive_message() is active.

Syntax

status = rtr_set_wakeup (void (*wu_rou)(void))

Argument Data Type Access
status rtr_status_t write
wu_rou procedure read


C Binding

rtr_status_t rtr_set_wakeup (


procedure void (*wu_rou) (void)
)


Arguments

void (*wu_rou) (void)

The routine to be called by RTR when no call to rtr_receive_message() is being processed and a message is waiting to be delivered.

Description

The rtr_set_wakeup() call sets the address of a function to be called when no call to rtr_receive_message() is outstanding and a message is waiting to be delivered.

To cancel wakeups, call the routine with an argument of null .

If a wakeup routine has been set using this call, subsequent calls to rtr_set_wakeup() should either disable the wakeup feature (with an argument of null ), or replace the current wakeup routine with another.

Note

The wakeup feature is not required in a threaded application; its functionality can be provided by a dedicated thread that receives and dispatches RTR messages.
Return Value A value indicating the status of the routine. Possible values are:
RTR_STS_OK Normal successful completion

Example


/* This client application has written a function which 
 * RTR should call whenever there is a message for it. 
 * The function is a `wake-up' function. 
 */ 
void wake_me_up(void){ 
 
    . 
    . 
    . 
    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 application is using 
     * the message type to dispatch the message to handlers 
     * which the programmer has written. 
     */ 
    select (rtr_msg_type_t){ 
 
    case rtr_mt_prepare: 
          status = prepare_function(receive_msg, msgsb); 
          break; 
 
    case rtr_mt_accept: 
          status = accept_function(channel, receive_msg); 
          break; 
    . 
    .  Dispatch all possible; send needed parameter info. 
    . 
    } 
} 
 
/* In the main function, tell RTR to call the above function 
 * when there is a message being sent to this application. 
 */ 
status = rtr_set_wakeup(wake_me_up); 
sleep(); // Sleep until RTR sends a message. 

See Also


rtr_start_tx

Explicitly start a transaction on the specified channel.

Syntax

status = rtr_start_tx (channel, flags, timoutms, pjointxid)

Argument Data Type Access
status rtr_status_t write
channel rtr_channel_t read
flags rtr_sta_flag_t read
timoutms rtr_timout_t read
pjointxid rtr_pointer_t read


C Binding

rtr_status_t rtr_start_tx (


rtr_channel_t channel ,
rtr_sta_flag_t flags ,
rtr_timout_t timoutms ,
rtr_pointer_t pjointxid
)


Arguments

channel

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

flags

Flags that specify options for the call. Normally specify RTR_NO_FLAGS for this parameter, unless using nested transactions. Nested transaction flags, listed in Table 3-30, are only valid if the pjointxid parameter does not equal RTR_NO_JOINTXID.

Table 3-30 Nested Transaction Flags
Flag Usage
RTR_F_STA_TID_DDTM Only used if RTR_F_OPE_FOREIGN_TM is set in the rtr_open_channel call. Indicates that the transaction ID pointed to by the parameter pjointxid is a DECdtm transaction (16 bytes).
RTR_F_STA_TID_RTR Only used if RTR_F_OPE_FOREIGN_TM is set in the rtr_open_channel call. Indicates that the transaction ID pointed to by the parameter pjointxid is an RTR transaction (28 bytes).
RTR_F_STA_TID_XA Only used if RTR_F_OPE_FOREIGN_TM is set in the rtr_open_channel call. Indicates that the transaction ID pointed to by the parameter pjointxid is an XA transaction.

Note

The flags RTR_F_STA_TID_RTR, RTR_F_STA_TID_XA and RTR_F_STA_DDTM are mutually exclusive.

timoutms

Transaction timeout specified in milliseconds. If the timeout time expires, RTR aborts the transaction and returns status RTR_STS_TIMOUT.

If no timeout is required, specify RTR_NO_TIMOUTMS.

pjointxid

Pointer to the transaction identifier if the parent transaction.

Description

The rtr_start_tx() call is used to start a transaction explicitly.

An explicit transaction start is only necessary if:

Transactions are implicitly started when a message is sent on a currently inactive channel. Implicitly started transactions have no timeout and are not joined to other RTR transactions.

Nested Transaction Usage

If the RTR_F_OPE_FOREIGN_TM flag is set for a channel, then the global coordinating transaction manager for this transaction is a foreign transaction manager. In this case, the application must use the rtr_start_tx() call to start a transaction (the transaction cannot be started implicitly on a first call to rtr_send_to_server() ), and specify the pjointxid parameter.

When a nested transaction is started (pjointxid not equal to RTR_NO_JOINTXID), then that transaction is given a new RTR transaction ID (which the application can retrieve by calling rtr_get_tid()). The foreign transaction ID passed in pjointxid is used only to identify the transaction for the foreign transaction manager (for example, when the foreign transaction manager goes through recovery and requests RTR to return all transactions in prepared state).

The channel on which a nested transaction is started must be opened as a client channel, on a node defined with the frontend role, on which an RTR journal is required. If no facilities on that node have the backend role defined, so as to support a journal, RTR opens a local journal on the node.

Each nested transaction is started on a separate client channel. There is no restriction on the levels of nesting for nested transactions, or on the number of nested transactions that can be started and controlled by one global transaction manager.
Return Value A value indicating the status of the routine. Possible status values are:
RTR_STS_OK Normal successful completion
RTR_STS_INVCHANNEL Invalid channel argument
RTR_STS_INVFLAGS Invalid flags argument
RTR_STS_INVTIMOUTMS Invalid timoutms argument
RTR_STS_TRAALRSTA Transaction already started
RTR_STS_INVJOINTXID Invalid join transaction argument
The flag RTR_F_OPE_FOREIGN_TM was defined in the call to rtr_open_channel() , but pjointxid is equal to RTR_NO_JOINTXID , or the formatID field of an XA transaction in the pjointxid parameter is equal to RTR_XID_FORMATID_NONE .
RTR_STS_VERMISMAT RTR version mismatch
The RTR router is running an older version of RTR that does not support nested transactions.

Example


rtr_xid_t xa_txn; 
 
/* This client-server pair handle transactions which contain 
 * multiple messages within each one. Transactions are explicitly 
 * started and prepared, as directed by this client. 
 * 
 * Fill in the information in the XA transaction id struct. 
 * The information will be sent to the server to tag the transaction. 
 */ 
        xa_txn.formatID = RTR_XID_FORMATID_RTR_XA; 
        xa_txn.gtrid_length = 4; 
        xa_txn.bqual_length = 4; 
        strcpy(xa_txn.data, "6789.0003"); 
 
/* Start the transaction; specify a timeout so we don't get 
 * stuck waiting forever. 
 */ 
        status = rtr_start_tx( 
                                &channel, 
                                RTR_F_STA_TID_XA, 
                                1000, 
                                &xa_txn ); 
 
check_status(status);   // May be RTR_STS_TIMEOUT. 

See Also


Appendix A
Comparison of Portable and OpenVMS APIs

This appendix describes the differences between the portable RTR API available in Reliable Transaction Router Version 3, the portable API, and the OpenVMS API used in Reliable Transaction Router Version 2, the OpenVMS API.

A.1 Compatibility between RTR Versions

Reliable Transaction Router Version 3 interoperates with RTR Version 2.2 in a DECnet environment using DECnet Phase IV naming. (The same version of RTR must be installed on all routers and backends. See the section on Network Transports in the Reliable Transaction Router System Manager's Manual to find out how to configure your Version 3 nodes.)

Note that the size of an RTR transaction ID has been changed for Reliable Transaction Router Version 3; it is now 28 bytes. (This ensures that the transaction ID contains a unique node specification.)

A.2 Reasons for a Portable API

RTR was first developed for use within an OpenVMS environment. Reliable Transaction Router Version 3 extends the applicability of RTR to allow users to create fault-tolerant distributed applications running on networks of heterogeneous machines and platforms.

The OpenVMS API presented some incompatibilities when used on non-OpenVMS platforms as follows:

  1. The "$" character contained in all RTR identifiers is not permitted in identifiers in some languages.
  2. There was no provision for reformatting user messages passed between machines to account for differing machine representations of particular data types.
  3. RTR permits applications to be written to perform multiple concurrent operations, a feature that can be critical for good performance in high-volume transaction processing systems. The notification mechanisms used to indicate completion of such asynchronous operations (event-flag, txsb, completion-AST) were OpenVMS-specific.

A.3 Benefits of the Portable API

The benefits of using the portable API are:

The portable API has been designed to:

A.4 Comparison of OpenVMS and Portable API Calls

Table A-1 compares the OpenVMS and Portable API calls.

Table A-1 OpenVMS API (V2) and Portable API (V3) Compared
OpenVMS API Portable API
$dcl_tx_prc() rtr_open_channel()
$start_tx() rtr_start_tx() [optional]
$commit_tx() rtr_accept_tx()
$abort_tx() rtr_reject_tx()
$vote_tx() rtr_accept_tx()/rtr_reject_tx()
$deq_tx() rtr_receive_message()
$enq_tx() rtr_send_to_server()/ rtr_reply_to_client()/rtr_broadcast_event()
$dcl_tx_prc() (SHUT) rtr_close_channel()
$get_txi() rtr_request_info()
$set_txi() rtr_set_info()
ASTPRM (on asynch calls) rtr_set_user_handle()
-- rtr_error_text()
-- rtr_get_tid()
-- rtr_prepare_tx()
-- rtr_set_wakeup()


Appendix B
RTR Application Development Tutorial

Start here!

Purpose:
This tutorial goes through all of the steps needed to set up a simple RTR-based application for a new user. The intent is to provide a starting point for learning about RTR, and to simplify the main concepts of RTR; you will be able to cruise through this at a more rapid pace than you normally would with the RTR reference information.

At the end of this tutorial, you’ll find brief descriptions of some of the more complex features RTR provides, and pointers to the documentation where you can study them in detail.

Summary:
This tutorial walks you through designing, coding and setting up a basic RTR-based client-server application. To do this, you’ll use RTR to perform two important services for you:

In the system that you are about to develop, the client application interacts with the user to read and display data. The server application handles requests from the client, and sends replies back to it. When we refer to ‘client’ and ‘server’, we will be referring to the applications. When we refer to the computer nodes on which the client or server is executing, we will call them ‘frontend’ and ‘backend’ nodes, respectively.

In most applications, the server would probably talk to a database in order to retrieve or save data according to what a user had entered in the user-interface. In the interest of simplifying this tutorial, however, this server is only going to tell you whether it received your client’s request.

What’s different in this system from a non-RTR system is that there will be two servers: one of the servers, also known as the ‘primary server’, almost always talks with the client. In a perfect world, nothing would ever happen to this server; clients would always get the information they asked for, and all changes would be made to the database when the user updated information. Every time anyone attempted to access this server, it would always be there, ready and waiting to ‘serve’, and users could feel secure in the knowledge that the data in the database was changed exactly as they had requested.

But we’re all well aware that this is not always the case, and when servers do go down, it’s usually at the most inopportune time. So you are going to use RTR to designate a second server as a "standby" server. In this way, if a user is attempting to get some real work done, and the primary server is down, the user will never notice. The standby server will spring into action, and replace the original server by handling the user’s requests in just the same way as the primary server had been doing. And, this will be done from the same point at which the primary server had crashed!

Materials List:
In order to fully develop this system, you will need a client application and frontend node, a server application and two backend nodes, and a router. What are these things?

Frontend:
The frontend node is the system on which your client application is executing. As in any client-server system, the client application interacts with the user, then conveys the user’s requests to the server. When developing an RTR-based client-server system, your client will have the following characteristics:

Example code for the client application and the server application can be found in the ‘examples’ subdirectory of your RTR installation directory.

BackEnd1:
Your first backend node will be running the primary server application. It, too, can be on any of the above operating systems, except the Windows system must be NT. It also must have RTR installed on it, and will contain your server application. Your server application will use RTR to listen for requests from the client, receive and handle those requests, and confirm the result to the client.

BackEnd2:
This machine will run the standby server application. It will probably also be doing any one of a number of other things that have nothing to do with this tutorial, or even with RTR. It most probably will be sitting on one of your coworkers’ desks, helping him or her to earn their weekly salary and support their family. Hopefully, you get along with this coworker well enough that they will install RTR on their machine, so that you may complete this tutorial.

Router:
Your router is simply RTR software which keeps track of everything that is going on for you when your application is running. The router can execute on a separate machine, on a frontend machine, or on a backend machine. In this tutorial, we will keep our router on the same machine as the client.

Install RTR:
Your first step, once you have determined the three computers you are going to use for this tutorial, is to be sure RTR is installed and configured on each machine. The RTR installation is well documented and straightforward, although slightly different for each operating system on which the installation is being run. Refer to the section in the RTR Installation Guide for the system on which you are installing RTR.

For the purpose of documenting examples, the machine you have decided to use for the client application will be referred to as FE (frontend), primary server as BE1 (backend 1), secondary server as BE2 (backend 2). Remember that the router will be on the FE machine. The journal must be accessible to both backend servers.

Start RTR:
You will need to start RTR on each of the machines on which you have installed it. You may do this from one machine. In order to be able to issue commands to RTR on a remote node, however, you must have an account on that node with the necessary access privileges. The operating system’s documentation, or your system manager, will have information on how set up privileges to enable users to run applications over the network.

Use the command interface on your system to interact with RTR. At the command prompt, type in RTR, and press the Return or Enter key. You will then be at the RTR> prompt, and can start RTR on all of the nodes. For example, on a UNIX system, it will look like this:


%  rtr 
RTR> start rtr/node=(FE,BE1,BE2) 
RTR> exit 

This command starts ‘services’ or ‘daemons’ on each of the nodes in the list. These are processes that listen for messages being sent by other RTR services or daemons over the network. After executing the command, a ‘ps’, ‘show process’ or Task Manager review of processes executing on your system should now show at least one process named ‘rtr’ or ‘rtr.exe’ on each of the machines. This process is the one that manages the communications between the nodes in the RTR-based application, and handles all transactions and recoveries.

Create a Recovery Journal:
This step holds the key to letting the second server pick up on the work at exactly the right time; no work is lost, and the hot swap to the standby server is "automagic". RTR keeps track of the work being done by writing data to this journal. If a failure occurs, all incomplete transactions are being kept track of here, and can be replayed by the standby server when it comes to the rescue. When transactions have been completed, they are removed from this journal.

For this example, only your backend nodes need a recovery journal, and you must create the journal before creating your facility; you’ll learn more about facilities in the next section. You’ll now need to go to each of the backend nodes that you’ll be using and create a journal there. Log into each machine and, using the command prompt interface, run RTR and create the journal. When you specify the location of the journal, it should be the disk name or share name where the journal will be located. The journal must be accessible by both of the backend servers.

This is an example of what the command would look like on a VMS system.


$  RTR 
RTR> create journal user2
RTR> exit 

To allow both servers to access the journal, you have a number of options:

In any case, you should be sure the disk is not on your primary server, since this is the machine that we are protecting, in case of a crash. If the machine goes down, the standby server would not be able to access the disk.

The Database:
While we are having this discussion on sharing resources, we should also mention how a database fits into this system, as well.


Previous Next Contents Index