Reliable Transaction Router
C Application Programmer's
Reference Manual


Previous Contents Index


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. This tutorial uses the implicit start, prepare, and accept transaction capabilities of RTR that are described in the Reliable Transaction Router Application Design Guide, a prerequisite for using this manual.

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.

This tutorial and the example code provided with it does not do database transactions. However, there are likely places in the code where you would probably want to access the database in most applications. Because the standby server steps into place when the primary server crashes, each must have access to your database.

This configuration can be supplied using a number of options:

Create a ‘Facility’:
There can be numerous RTR applications running on any of your computers in your network. The systems or nodes that service one RTR application and the role of each must be clearly defined. This makes the RTR daemons and processes aware of who is talking with whom, and why. The description of a configuration of a group of nodes into frontends, backends and routers is called a facility.

To create a facility, use your command prompt utility again and type ‘RTR’; at the RTR> prompt, create the facility for this example with the following command on a Windows system in the DOS command prompt window:


C:\> rtr 
RTR> create facility RTRTutor/node=(FE,BE1,BE2) - 
_RTR>  /frontend=FE/router=FE/backend=(BE1,BE2) 
RTR> exit 

With this command, you have now:

Take a Break:
At this point you have accomplished a lot; you’ve configured RTR to protect a multi-tiered application by providing failover capability, and to handle communications between your client and your server. Next, you will write the application: your client will talk to RTR, and your server will talk to RTR. RTR will deliver the messages between them and, if the server crashes, bring in the standby server to handle your client’s requests. The client will never know that the server has been switched, and no data or requests to retrieve or modify data will be lost!

Application:
The C modules and header files for this application are located in the ‘examples’ subdirectory of the directory into which you installed RTR. They consist of the following files:
ADG_CLIENT.C The client application
ADG_SERVER.C The server application
ADG_SHARED.C C code common to both the client and server applications
ADG_HEADER.H Header file containing definitions specific to both sample applications

Although you won’t have much typing to do, this tutorial will explain what the code in each module is doing. Copy all four of these files into a working directory of your own. For convenience, you may also wish to copy rtr.h from the RTR installation directory into your working directory as well.

The example code you’ll run must reference the facility you created earlier, so edit the example file ADG_HEADER.H and change the FACILITY value to "RTRTutor".

The application example code supplied with RTR has a lot going on inside of it, but can be broken down into a few general and very simple concepts that will give you an idea of the power of RTR, and how to make it work for you. As you see, you have code for the client app and the server app. Each will talk only to RTR, who will move the messages and data between them. And you are free not to worry about:

RPC Stubs
Time zones
Endianism
Network protocols and packets

Aren’t you relieved? Maybe you should take another break to celebrate!

Client App:
The files shipped with the RTR kit used in the client application for this tutorial are ADG_CLIENT.C, ADG_SHARED.C and ADG_HEADER.H.

All applications that wish to talk to RTR through its API need to include ‘rtr.h’ as a header file. This file lives in the directory into which RTR was installed, and contains the definitions for RTR structures and values that you’ll need to reference in your application. Please do not modify this file. Always create your own application header file to include, as we did in the sample (ADG_HEADER.H) whenever you need additional definitions for your application.


#include "ADG_header.h" 
#include "rtr.h" 

The client application design follows this outline:

  1. Initialize RTR
  2. Send a message to the server
  3. Get a response from the server
  4. Decide what to do with the response

Pretty straightforward, don’t you think? Let’s look at how it’s done:

Initialize RTR:
This is the first thing that every RTR client application needs to do: tell RTR that it wants to get a facility up and running, and to talk with the server. You will find this happening in the declare_client function in adg_client.c, and somewhat more simplified here.

You remember from the ‘Start RTR’ step in this tutorial that there are RTR daemons or processes executing on the nodes in a facility, listening for communications from other RTR components and applications. Your client application is going to request that all processes associated with the RTRTutor facility "listen up." To do this, you’ll open a channel that enables communication between the client and the RTR router. Remember that the RTR router has been described as "keeping track of everything" that goes on in an RTR application.

Declare the items needed for the open channel call:


 rtr_status_t    status;   /* will be returned by RTR */ 
 rtr_channel_t   channel;  /* a channel */ 

Open the channel:


status = rtr_open_channel( 
            &channel,          /* channel of communication */ 
            RTR_F_OPE_CLIENT , /* I am a client */ 
            "RTRTutor",        /* the facility we created */ 
            NULL,              /* recipient name */          
            RTR_NO_PEVTNUM,    /* don’t send events, just messages */    
            NULL,              /* access key */ 
            RTR_NO_NUMSEG ,    /* number of key segments */ 
            RTR_NO_PKEYSEG );  /* first key segment */ 

Let’s examine what this ‘open channel’ call does. First, the ‘channel’ parameter we sent to it is only a pointer to a block of memory; we’ve done nothing to set any values in it. RTR will use this block of memory to store the information it needs in order to assign and keep track of this channel. The channel represents the means of communication from the client to the rest of the components in this system. There is a lot going on here to make the communication work, but it’s all being done by RTR so you won’t have to worry about all of the problems inherent in communicating over a network.

The second parameter tells RTR that this application is acting as a client. So now RTR knows that if the server goes down, it certainly doesn’t want to force this application to come to the rescue as the standby server! And there will be other things that RTR will be handling that are appropriate only to clients or only to servers. This information helps it to keep track of all the players.

And now [trumpets are heard in the distance!] the third parameter tells RTR the name of the facility we created earlier. Suddenly, RTR has a whole lot more information about your application: where to find the server, the standby server, and the router. You will see later in this tutorial that the server also declares itself and supplies the same facility name.

At this point, RTR has all of the information it needs to put the pieces together into one system; you’re ready to start sending messages to the server, and to get messages back from it.

A Word About RTR’s API Parameters:
You may have noticed that although we’ve looked at only three of the parameters in the ‘open channel’ call, there are a number more. It’s a quirk of RTR that you’ll often need to tell it to default. Rather than defaulting on its own when you do not provide a parameter (or provide a null parameter), it needs the "default" parameter. So you’ll see things like RTR_NO_PEVTNUM to tell it "I don’t want to be notified of any events" which is actually a default, and RTR_NO_NUMSEG to tell it "I have defined no key segments" which is also a default. Whenever we skip the discussion on non-null parameters, you’ll know they are default parameters.

The parameter RTR_NO_FLAGS tells RTR that there are no flags.

A Word About RTR’s Return Status:
Your facility may have more than just one client talking to your server. In fact, your neighbor who so generously allowed you to run your standby server on his or her machine might want to get in on this RTR thing, too. That’s all right: just add a machine to the RTRTutor facility definition that will also run a copy of the client. But not yet; we’re only telling you this to illustrate the point that there can be more than one client in an RTR-based application.

Because of this, after the RTR router hands off your client’s request to your server, it must then be able to do the same for other clients.

Servers can also decide they want to talk to your client, and the RTR router may need to handle their requests at any time, as well. If RTR were to wait for the server to do its processing and then return the answer each time, there would be an awful bottleneck.

But RTR doesn’t wait. This means that the status that you get back from each call means only, "I passed your message on to the server", not that the server successfully handled it and here is the result. So how does your client actually get the result of the request it made on the server? It will need to explicitly "receive" a message, as you’ll see later in this tutorial.

Checking RTR Status:
Throughout this code example, you’ll see a line of code that looks like this (with a different string in the first parameter each time):


    check_status( "rtr_open_channel", status ); 

This is good because, as you know from your Programming 101 course, you should always check your return status. But it’s also good that your program knows when something has gone wrong and can tell the user, or behave accordingly. The ‘check_status’ function is not part of RTR, but is something you will probably want to do in your application.

To check RTR’s return status, compare it to RTR_STS_OK. If it’s the same, everything is fine, and you can go on to the next call. But if it is something else, you’ll probably to print a message to the user. To get the text string that goes with this status, call ‘rtr_error_text’ which returns a null terminated ASCII string containing the message in human readable format.


     if (status != RTR_STS_OK) 
     { 
     sprintf("    Call failed: %s", rtr_error_text(status)); 
     } 

Receiving Messages:
As explained earlier, RTR doesn’t hold your client up while it processes your request, or even a request from another client. And since nothing can continue until the system has been set up, you now need to wait for the open channel call to let you know that everything is started up and ready to go. This is what the rest of the code in the "declare_client" function does. These statements:


      receive_msg_t receive_msg = {0}; /* message received */ 
      rtr_msgsb_t msg_status;     /* message status block */ 

declare the memory for a "receive" message and a message status block. And now the rtr_receive_message waits to receive a message from RTR.


   status = rtr_receive_message( 
                 &channel,           /* channel on which message received */ 
                 RTR_NO_FLAGS,       /* sending no flags (default) */ 
                 RTR_ANYCHAN,        /* default channel */ 
                 &receive_msg,       /* location to place return info */ 
                 sizeof(receive_msg),/* size of last */ 
                 RTR_NO_TIMEOUTMS,   /* do not timeout */ 
                 &msg_status);       /* location to return status */ 

The channel parameter and the RTR_NO_FLAGS parameter should now be familiar to you; we discussed them in the sections of this document on ‘Initialize’ and ‘Parameters’. RTR_ANYCHAN and RTR_NO_TIMEOUTMS are defaults for this API.

Remember Programming 101 --- check your status every time!

Information about whether RTR or your server has successfully handled your client’s request is returned in an rtr_msgsb_t message status block structure. It is received from RTR in as the last parameter in the rtr_receive_message call. For rtr_open_channel, we are looking for the "rtr_mt_opened" message type in the status block to confirm that the channel has been opened, and that we are now prepared to do all of the rest of the messaging on it for our application. If we don’t have the "opened" message, then we can expect there to be an error status in the receive message block.


    if ( msg_status.msgtype != rtr_mt_opened ) 
    { 
        print(" Error opening rtr channel : "); 
        print( rtr_error_text(receive_msg.receive_status_msg.status)); 
    } 

The rtr.h header file provided with the RTR installation kit describes the rtr_msgsb_t structure in detail.

Send Messages:
The rest of the client application is simply a ‘send/receive’ message loop. It continues to send messages to the server, then listen for the server’s response.

It is important to remember that, although the client is sending these messages to the server, it is doing so through the RTR router. Because of this, the client can receive, asynchronously, different types of messages:

In addition, RTR may send the client messages under certain conditions. So the client application must be prepared to accept any of these messages, and not necessarily in a particular sequence.

That’s certainly a tall order! How should you handle this? Well, there are a number of ways, but in this tutorial we will explain how to run a "message loop" that both sends and receives messages.

A Word About RTR Data types:
You may have noticed that your client, server and router can be on any one of many different operating systems. And you’ve probably written code for more than one operating system and noticed that each has a number of data types that the other doesn’t have. If you send data between a Solaris UNIX machine and a VMS or Windows NT machine, you’ll also have to worry about the order different operating system stores bytes in their data types (called "endian" order). And what happens to the data when you send it from a 16 bit Intel 486 Windows machine to a 64 bit Alpha UNIX machine?

Thanks to RTR, you don’t need to worry about it. RTR will handle everything for you. Just write standard C code that will compile on the machines you choose, and the run-time problems won’t complicate your design. When you do this, you need to use RTR data types to describe your data. RTR converts the data to the native data types on the operating system with which it happens to be communicating at the time.

Think of RTR as your very own "Babel fish," if you’ve read the "Hitchhiker’s Guide to the Galaxy" series. It will translate everything necessary when your data gets to a new machine. The little fish you put in your ear is actually made up of the RTR application programming interface and the RTR data types.


Previous Next Contents Index