# hp Reliable Transaction Router
C Application Programmer's
Reference Manual

Previous | Contents | Index

# 2.5 Programming Examples

The following pseudocode examples of a client and a server application illustrate the use of the C programming API. Details have been omitted to keep the basic structure clear.

## 2.5.1 Simple Client

This simple client program issues transactions and receives event messages. It simply issues one transaction, waits for it to be processed, and in the meantime handles any events that arrive. It then issues the next transaction. It does not need to wait until one transaction finishes before starting the next.

The following two examples are single-threaded. They can be made multithreaded by opening more channels. The structure of the main receive loop does not need to be changed to implement this. Note that `rtr_receive_message` receives the next message in the process input queue for any of the channels opened by the program (unless preferred channels have been requested in the `rtr_receive_message` ).

Example 2-1 Example Client

            rtr_open_channel()        ! Open a channel to the required facility
            rtr_receive_message()     ! Get the completion status of the open call
                                      ! success returns rtr_mt_opened
    send_loop:
            rtr_send_to_server( ...RTR_F_SEN_ACCEPT....)
                                      ! Send a tx-message and
                                      ! implicitly start a new tx
    rcv_loop:
            rtr_receive_message()     ! Find out what RTR wants to tell us next
            switch  (message_received_type)
            {
         case    rtr_mt_reply:          Process_Reply_from_Server; break;
                case    rtr_mt_rtr_event:      Process_RTR_Event;  break;
                case    rtr_mt_user_event:     Process_User_Event;  break;
                case    rtr_mt_accepted:       Tell_User_It_Worked;  break;
                case    rtr_mt_rejected:       Tell_User_About_Failure; break;
            }

            IF ( message_received_type = rtr_mt_accepted )
            OR ( message_received_type = rtr_mt_rejected )
            THEN
                GOTO send_loop ! Last transaction done, issue the next one
            ELSE
                GOTO rcv_loop  ! Get the next incoming message

In Example 2-1, note that the switch statement tests on message type. All messages that are received from RTR have a message type; for further information, see Section 2.11.

## 2.5.2 Simple Server

Example 2-2 is a simple server that receives transactions and events.

Example 2-2 Example Server

            rtr_open_channel()        ! open a channel to the desired facility
            rtr_receive_message()     ! get the completion status of the open call
                                      ! success returns rtr_mt_opened

    rcv_loop:
            rtr_receive_message()     ! Find out what RTR wants to tell us next

            CASE message_received_type
            OF
                rtr_mt_msg1:         Do_Some_SQL_And_Maybe_Send_A_Reply;
                rtr_mt_msgn:         Do_Some_More_SQL_And_Maybe_Send_A_Reply;
                rtr_mt_prepare:      Accept_or_Reject_Tx ;
                rtr_mt_rtr_event:    Process_RTR_Event;
                rtr_mt_user_event:   Process_User_Event;
                rtr_mt_accepted:     Commit_DB ;
                rtr_mt_rejected:     Rollback_DB ;
            END_CASE;

            GOTO rcv_loop

# 2.6 Using the C Programming API

As can be seen from the examples in the previous section, an application first opens one or more channels by calling `rtr_open_channel` .

The application can then process transactions and events on the channels it has opened. When a channel is no longer needed, the application closes it by calling `rtr_close_channel` .

A transaction becomes associated with a channel in one of the following circumstances:

1. When a client issues the first `rtr_send_to_server` call on a previously idle channel
2. When a server receives from a client the first message belonging to a transaction by calling `rtr_receive_message`
3. When a client issues a `rtr_start_tx` call on a previously idle channel

From this point on the channel remains associated with the transaction until one of the following occurs:

1. The application rejects the transaction using `rtr_reject_tx` .
   - The transaction is over, no more messages will be received on behalf of this transaction.
   - The channel becomes idle, ready for initiation/reception of another transaction.
2. The application accepts the transaction using `rtr_accept_tx` .
   - After calling `rtr_accept_tx` the application may continue receiving messages belonging to the transaction. However, it cannot subsequently either reverse its decision to accept by calling `rtr_reject_tx` , or (in the case of a client application) make additional calls to `rtr_send_to_server` .
   - The final message received for a transaction will always be a transaction completion status; either `rtr_mt_rejected` or `rtr_mt_accepted` .
   - The channel becomes idle, ready for initiation or reception of another transaction.
3. The application receives, by a call to `rtr_receive_message` , a completion status indicating that the transaction has been rejected by some other participant.
   - The transaction is over. No more messages will be received, and no more calls may be made on behalf of this transaction.
   - The channel becomes idle, ready for initiation or reception of another transaction.

Note that RTR considers a transaction to have been committed to the database (so that it does not need to replay it in case of failure) when the server indicates willingness to receive a new transaction by calling `rtr_receive_message` on the channel, after having received the transaction completion status.

Calling `rtr_close_channel` also indicates to RTR that the last transaction has been committed.

# 2.7 Concurrency

The routine `rtr_receive_message` is used by an application to receive all incoming messages, responses and events. This provides a single consistent method of information delivery.

All RTR routines other than `rtr_receive_message` complete immediately, and any responses are queued for later reception by `rtr_receive_message` .

The application calling `rtr_receive_message` may choose whether (and how long) it should wait for an incoming message to arrive (if there is no message available for immediate reception).

In addition, the application may optionally specify a "wakeup routine" to be called by RTR when a message becomes available for reception.

# 2.8 Exit Handlers in Applications

Making RTR calls from within an application exit handler does not work, because the channel is usually closed by the time the application exits. If an exit handler contains a call to RTR, then the exit handler must be declared after the first call to RTR. If an exit handler is declared before the first call to RTR, then any call to RTR made within the exit handler will return an error.

The error status returned is `RTR_STS_INV_CHANNEL` .

# 2.9 Using the RTR Set Wakeup Routine

An application program may typically wish to respond to input from more than one source. An example of this is an application program that prompts for user input in a window and at the same time displays information received asynchronously via broadcast events.

To avoid the application polling its various input sources, RTR provides the `rtr_set_wakeup` routine. This allows the application to specify a routine to be called when there is data to be received from RTR. The application program can then be coded as shown in the example provided with the rtr_set_wakeup routine.

The processing context of the application wakeup handler depends upon the platform and RTR library variant employed.

Core RTR functionality and the C API are delivered in a single sharable library. This library is named `rtrdll` on Windows, and `librtr` on other platforms. The latter is supplied in two variants: `librtr_r` which is targeted at developers of threaded applications, and `librtr` which provides a platform-specific wakeup handler implementation.

Wakeup handlers under `rtrdll` and `librtr_r` are called in a dedicated thread created by RTR for this purpose.

Wakeup handlers under `librtr` on UNIX are called from a signal handler established by RTR to handle SIGIO. If the application also wishes to use this signal, it should establish its handler prior to the first call to the RTR API. In this case the signal handler should be aware that the SIGIO signal may have been generated by RTR, not necessarily by the event for which the signal handler was written.

Wakeup handlers under `librtr` on OpenVMS are called from an AST handler. In the presence of multiple competing ASTs, calling `rtr_set_wakeup()` from the wakeup handler can be used to limit RTR processing and serialize the execution of RTR events with other asynchronous activity in the program.

`Rtrdll` and `librtr_r` provide thread synchronization and are safe to use in a multithreaded environment. `Librtr` offers no such protection.

It is not anticipated that applications on OpenVMS will want to use both threads and ASTs. For this reason the RTR V2 API is functional in `librtr` on OpenVMS only.

Summarizing:

Sharable Name | Thread-safe | Wakeup Mechanism | V2 API
--- | --- | --- | ---
`rtrdll` | Yes | RTR thread | No
`librtr_r` | Yes | RTR thread | No
`librtr` /UNIX | No | signal handler | No
`librtr` /OpenVMS | No | AST | Yes

## 2.9.1 Restrictions on the RTR Wakeup Handler

The wakeup handler itself cannot call any function that might have to wait such as `rtr_reply_to_client` , `rtr_send_to_server` or `rtr_broadcast_event` ; the only RTR call allowed in the wakeup handler is `rtr_receive_message` called with a zero timeout. Other RTR calls may block or halt processing when they need transaction IDs or flow control, which will cause unexpected behavior. This restriction applies to both threaded and unthreaded applications.

A threaded application does not need to use a wakeup handler; its functionality can be provided by a dedicated thread that receives and dispatches RTR messages.

Functions permitted in an `rtr_set_wakeup()` handler:

- While wakeups are unnecessary in threaded application, they may be used in common code in applications that run on OpenVMS. Because mainline code continues to run while the wakeup is executing, extra synchronization may be required. If the wakeup does block then it does not generally hang the whole application.
- For an RTR wakeup handler in a signal handler within an unthreaded UNIX application, no RTR API functions and only the very few asynch-safe system and library functions may be called, because the wakeup is performed in a signal handler context. An application can write to a pipe or access a volatile `sig_atomic_t` variable, but using `malloc()` and `printf()` , for example, will cause unexpected failures. Alternatively, on most UNIX platforms, you can compile and link the application as a threaded application with the reentrant RTR shared library `-lrtr_r` .
- For maximum portability, the wakeup handler should do the minimum necessary to wake up the mainline event loop. You should assume that mainline code and other threads might continue to run in parallel with the wakeup, especially on machines with more than one CPU.

# 2.10 API Optimizations

Reliable Transaction Router provides client and server optimizations for greater performance and programming ease.

## 2.10.1 Client Optimization

Reliable Transaction Router introduces greater flexibility and efficiency in how transactions are packaged at the client.

The total sequence of events that a client application has to execute are as follows:

1. Start a transaction.
2. Send one or more transaction messages, optionally receive one or more transaction messages.
3. Either accept or reject the transaction.
4. Wait for the transaction accept or reject message and process accordingly.
5. Return to Step 1.

In Reliable Transaction Router, all these steps can be followed if required, but optimizations allow some of the steps to be handled implicitly.

- The call to `rtr_start_tx` (Step 1) may be omitted if, for example, no timeout is required for the transaction. A call to `rtr_send_to_server` on a channel that does not have an active transaction automatically implies a call to `rtr_start_tx` .
- Step 3 may be handled implicitly if the client wishes to accept the transaction. This is done by setting the `RTR_F_SEN_ACCEPT` flag on the last (or only) call to `rtr_send_to_server` .

## 2.10.2 Voting Optimization and Server Flags

Reliable Transaction Router introduces greater flexibility and efficiency in how transaction voting (acceptance by servers) is handled; RTR allows implicit voting.

In detail, the sequence of events that a server executes is as follows:

1. Get one or more transaction messages from RTR and process them.
2. Get the vote request message from RTR.
3. Issue the accept (commit).
4. Get the final transaction state.
5. Return to Step 1.

This scheme is not efficient in some cases. For example, a callout (authentication) server may only need to receive the first message of a multiple message transaction, whereupon it can vote immediately.

In Reliable Transaction Router, all these steps can be enforced if required, but optimizations allow some of the steps to be handled implicitly.

An implicit accept allows Step 3 to be omitted; the transaction is accepted by the server when it does the next call to `rtr_receive_message` .

These optimizations are controlled by flags ( `RTR_F_OPE_EXPLICIT_PREPARE` and `RTR_F_OPE_EXPLICIT_ACCEPT` ) on the call used to open a server channel.

### 2.10.2.1 The RTR_F_OPE_EXPLICIT_PREPARE Flag

A server channel may be opened with the `RTR_F_OPE_EXPLICIT_PREPARE` flag; this specifies that it will receive prepare messages (messages of type `rtr_mt_prepare` ). The server is then expected to accept or reject a transaction on receipt of this message (or earlier). The server may accept the transaction before the prepare message is sent: in this case, the prepare message is not delivered to the server.

The default behaviour of RTR (for example, when this flag is not set in the call to `rtr_open_channel` ) is to not send prepare messages to the server application. In this case, RTR expects the server to accept or reject transactions without RTR triggering it into voting activity by sending prepare messages.

### 2.10.2.2 The RTR_F_OPE_EXPLICIT_ACCEPT Flag

A server channel may be opened with the `RTR_F_OPE_EXPLICIT_ACCEPT` flag; this specifies that it will accept transactions only by making an explicit call to `rtr_accept_tx` .

The default behaviour of RTR (that is, when this flag is not set) is to treat a server's call to `rtr_receive_message` (after the last transaction message has been received) as an implicit acceptance of the transaction.

If a transaction has been accepted before the last message has been received, the setting of the `RTR_F_OPE_EXPLICIT_ACCEPT` is irrelevant.

However, if a transaction has not been prematurely accepted, when the server's vote is required by RTR, the setting of the flags have the following effects:

1. When both `RTR_F_OPE_EXPLICIT_PREPARE` and `RTR_F_OPE_EXPLICIT_ACCEPT` are set, the `rtr_mt_prepare message` is returned to the server, and the server must accept or reject the transaction.
2. When `RTR_F_OPE_EXPLICIT_PREPARE` is set but `RTR_F_OPE_EXPLICIT_ACCEPT` is not set, the `rtr_mt_prepare` message is also returned to the server, but if the server does not perform an explicit accept or reject, then a subsequent call to `rtr_receive_message` implies an accept of the transaction.
3. When `RTR_F_OPE_EXPLICIT_PREPARE` is not set but `RTR_F_OPE_EXPLICIT_ACCEPT` is set, no `rtr_mt_prepare` message is returned to the server, and no implicit accept of the transaction will be performed: It is assumed that some other event will trigger the application into voting.
4. With neither `RTR_F_OPE_EXPLICIT_PREPARE` nor `RTR_F_OPE_EXPLICIT_ACCEPT` set, no `rtr_mt_prepare` message is returned to the server. An implicit transaction accept is performed.

# 2.11 RTR Messages

All RTR calls return a completion status immediately except `rtr_receive_message` . If the immediate status is successful, many calls will also result in a further message or messages being delivered on the channel.

All RTR received messages are of a defined message type. The message type is given in the message status block. (See pmsgsb on `rtr_receive_message` in Chapter 3).

The message type allows your application to handle the message appropriately; the message type indicates whether this message contains information that is part of a transaction, or a broadcast, or RTR informational, and so on.

The use of `rtr_receive_message` for both RTR status messages and application data messages requires the application designer to consider how to respond to the different message types. Message types for server and client applications are listed in Table 2-2 and Table 2-3.

All received messages cause the message status block (pmsgsb on `rtr_receive_message` ) to be filled; most message types also put data into the user buffer (pmsg on `rtr_receive_message` ). Only the `rtr_mt_prepare` message type does not fill the user buffer.

Table 2-4 provides information put in the user buffer for each message type. Table 2-2 and Table 2-3 list all the message types that server channels or client channels can receive, together with a description of their meaning and the recommended application behavior. Order is alphabetical.

Table 2-2 RTR Received Message Types for Server Applications
Message Type | Description | Recommended Action
--- | --- | ---
rtr_mt_accepted | The specified transaction has been accepted by all participants. | Commit the transaction in the database and release database locks.
rtr_mt_closed | Channel has been closed. Sent by RTR if an `rtr_open_channel` fails (that is, no such facility) or as a result of an operator command such as DELETE FACILITY, or the last message from a `rtr_request_info` or `rtr_set_info` call. | Examine reason status. Roll back database for any active transaction.
rtr_mt_msg1 | This is the first application message of a transaction, sent by a client. | Process the message.
rtr_mt_msg1_uncertain | This is the first application message of a replayed transaction, that is, a previous incarnation of the server failed during the voting phase. | Check in database to see if the transaction has been processed. If not processed, redo the transaction; else forget the transaction.
rtr_mt_msgn | This is the nth application message (that is, not the first) of a transaction, sent by a client. | Process the message.
rtr_mt_opened | Channel has been opened. | Use the channel.
rtr_mt_prepare | The specified transaction is complete (that is, all messages from the client have been received). This message type is only received by a server that specified that it requires a prepare. (Servers specify this by using the `RTR_F_OPE_EXPLICIT_PREPARE` flag on the `rtr_open_channel` call.) | Call either `rtr_reject_tx` to reject the transaction, or have all required database records locked before calling `rtr_accept_tx` to accept the transaction.
rtr_mt_rejected | The specified transaction has been rejected by a participant. | Roll back the transaction.
rtr_mt_request_info | Message from a previous call to `rtr_request_info` . | Use information as required.
rtr_mt_rtr_event | An RTR event with an associated message. | evtnum describes which RTR event occurred. See Table 2-5.
rtr_mt_set_info | Message from a previous call to `rtr_set_info` . | Use information as required.
rtr_mt_user_event | A user event with an associated message. | evtnum has an application-specific meaning.

Table 2-3 RTR Received Message Types for Client Applications
Message Type | Description | Recommended Action
--- | --- | ---
rtr_mt_accepted | The specified transaction has been accepted by all participants. | Inform user of successful completion.
rtr_mt_closed | Channel has been closed. Sent by RTR if an `rtr_open_channel` fails (for example, no such facility) or as a result of an operator command such as DELETE FACILITY, or the last message from an `rtr_request_info` or `rtr_set_info` call. | Examine reason status.
rtr_mt_opened | Channel has been opened. | Use the channel.
rtr_mt_rejected | The specified transaction has been rejected by a participant. | Inform user of reason for failure.
rtr_mt_reply | This is an application reply message sent by a server. | Process message.
rtr_mt_request_info | Message from a previous call to `rtr_request_info` . | Use information as required.
rtr_mt_rettosend | This message (which had been sent with the `RTR_F_SEN_RETURN_TO_SENDER` flag) could not be delivered and has been returned. | Take appropriate action for the transaction as required by your application.
rtr_mt_rtr_event | An RTR event with an associated message. | evtnum describes which RTR event occurred. See Table 2-5.
rtr_mt_set_info | Message from a previous call to `rtr_set_info` . | Use information as required.
rtr_mt_user_event | A user event with an associated message. | evtnum has an application-specific meaning.

Table 2-4 Contents of the User Buffer for Different Message Types
Message Type | Buffer Contents
--- | ---
rtr_mt_accepted | `rtr_status_data_t` , see Example 2-3.
rtr_mt_closed | `rtr_status_data_t` , see Example 2-3.
rtr_mt_msg1 | The first application message of a transaction, sent by a client.
rtr_mt_msg1_uncertain | The first application message of a replayed transaction.
rtr_mt_msgn | The nth application message (that is, not the first) of a transaction, sent by a client.
rtr_mt_opened | `rtr_status_data_t` , see Example 2-3.
rtr_mt_prepare | None.
rtr_mt_rejected | `rtr_status_data_t` , see Example 2-3.
rtr_mt_reply | An application reply message sent by a server.
rtr_mt_request_info | Requested information from `rtr_request_info` .
rtr_mt_rettosend | Returned message.
rtr_mt_rtr_event | RTR event message.
rtr_mt_set_info | Set information from `rtr_set_info` .
rtr_mt_user_event | The user broadcast message.

Previous | Next | Contents | Index