# hp Reliable Transaction Router
Application Design Guide

Previous | Contents | Index

# Starting a Transaction

There are two ways to start a transaction:

- Explicitly, using `rtr_start_tx`
- Implicitly, using `rtr_send_to_server`

## 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:

- Return to sender
  Use the `RTR_F_SEN_RETURN_TO_SENDER` flag to tell RTR to return the message with a message type of `rtr_mt_rettosend` if delivery fails. This lets a client determine which message failed in a multiple message stream.
- Accept transaction
  Use the `RTR_F_SEN_EXPENDABLE` flag to tell RTR not to reject the transaction associated with the message if the message cannot be delivered. This lets other non-expendable messages be delivered without creating a dependency on the flagged message. RTR does not abort the transaction if delivery fails. To specify a read-only server operation for which neither shadowing nor journaling are used, use the `RTR_F_SEN_READONLY` flag.

## 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.

## Two-Phase Commit

The two-phase commit process includes prepare and commit phases. A transaction is tentatively accepted or rejected during the prepare phase.

## Prepare Phase

To initiate the prepare phase, the server application specifies the `RTR_F_OPE_EXPLICIT_PREPARE` flag when opening the channel, and can use the message `rtr_mt_prepare` to check commit status. The message indicates to the server application that it is time to prepare any updates for a later commit or rollback operation. RTR lets the server application explicitly accept a transaction using the `RTR_F_OPE_EXPLICIT_ACCEPT` flag on the `rtr_open_channel` call. Alternatively, RTR implicitly accepts the transaction after receiving the `rtr_mt_accepted` message when the server issues its next `rtr_receive_message` call.

The commit process is initiated by the client application when it issues a call to RTR indicating that the client "accepts" the transaction. This does not mean that the transaction is fully accepted, only that the client is prepared to accept it. RTR then asks the server applications participating in the transaction if they are prepared to accept the transaction. A server application that is prepared to accept the transaction votes its intention by issuing the `rtr_accept_tx` call, an "accept" vote. A server application that is not prepared to accept the transaction issues the `rtr_reject_tx` call, a "not accept" vote. Issuing all votes concludes the prepare phase.

## Commit Phase

When RTR has collected all votes from all participating server applications, it determines if the transaction is to be committed. If all collected votes are "accept," the transaction is committed; RTR informs all participating channels. If any vote is "not accept," the transaction is not committed. A server application can expose the prepare phase of two-phase commit by using the `rtr_mt_prepare` message type with the `RTR_F_OPE_EXPLICIT_PREPARE` flag. If the application's `rtr_open_channel` call sets neither the `RTR_F_OPE_EXPLICIT_ACCEPT` nor `RTR_F_OPE_EXPLICIT_PREPARE` flag, both prepare and accept processing are implicit.

The server application can participate in the two-phase commit process fully, somewhat, a little, or not at all. To participate fully, the server does an explicit prepare and an explicit accept of the transaction. To participate somewhat, the server does an explicit prepare and an implicit accept of the transaction. To participate a little, the server does an explicit accept of the transaction. To participate not at all, the server does an implicit accept of the transaction. Table 5-5 summarizes the level of server participation:

Table 5-5 Server Participation
Commit Phase | Full | Somewhat | Little | Not at all
--- | --- | --- | --- | ---
Explicit prepare | yes | yes |  |
Explicit accept | yes |  | yes |
Implicit accept |  | yes |  | yes

Your application can use the level of participation that makes the most sense for your business and operations needs.

## Explicit Accept, Explicit Prepare

To request an explicit accept and explicit prepare of transactions, the server channel is opened with the `RTR_F_OPE_EXPLICIT_PREPARE` and `RTR_F_OPE_EXPLICIT_ACCEPT` flags. These specify that the channel will receive both prepare and accept messages. The server then explicitly accepts or rejects a transaction when it receives the prepare message. The transaction sequence for an explicit prepare and explicit accept is as follows:

Client | RTR | Server
--- | --- | ---
`rtr_start_tx` |  |
`rtr_send_to_server` | -> `rtr_mt_msg1` | -> `rtr_receive_message`
`rtr_accept_tx` | -> `rtr_mt_prepare` | -> `rtr_receive_message`
|  | <- `rtr_accept_tx`
`rtr_receive_message` | <- `rtr_mt_accepted` | <- `rtr_receive_message`

With explicit transaction handling, the following steps occur:

1. The server application waits for a message from the client application.
2. The server application receives the `rtr_mt_prepare` request message from RTR.
3. The server application issues the accept or reject.

A participant can reject the transaction up to the time RTR has sent the `rtr_mt_prepare` message type to the server in the `rtr_accept_tx` call. A participant can reject the transaction up to the time the `rtr_accept_tx` call is executed. Once the client application has called `rtr_accept_tx` , the result cannot be changed.

## Implicit Prepare, Explicit Accept

The sequence for an implicit prepare and explicit accept is as follows:

Client | RTR | Server
--- | --- | ---
`rtr_start_tx` |  |
`rtr_send_to_server` | -> `rtr_mt_msg1` | -> `rtr_receive_message`
`rtr_accept_tx` | -> | <- `rtr_accept_tx`
`rtr_receive_message` | <- `rtr_mt_accepted` | <- `rtr_receive_message`

In certain database applications, where the database manager does not let an application explicitly prepare the database, transactions can simply be accepted or rejected. Server applications that do not specify the `RTR_F_EXPLICIT_ACCEPT` flag in their `rtr_open_channel` call implicitly accept the in-progress transaction when an `rtr_receive_message` call is issued after the last message has been received for the transaction. This call returns the final status for the transaction, `rtr_mt_accepted` or `rtr_mt_rejected` . If neither the `RTR_F_OPE_EXPLICIT_ACCEPT` nor the `RTR_F_OPE_EXPLICT_PREPARE` flags are set in the `rtr_open_channel` call, then both prepare and accept processing will be implicit.

For server optimization, the server can signal its acceptance of a transaction with either `rtr_reply_to_client` , using the `RTR_F_REP_ACCEPT` flag, or with the client issuing the `rtr_send_to_server` call, using the `RTR_F_SEN_ACCEPT` flag. This helps to minimize network traffic for transactions by increasing the likelihood that the data message and the RTR accept message will be sent in the same network packet.

# Transaction Recovery

When a transaction fails in progress, RTR provides recovery support using RTR replay technology. RTR, as a distributed transaction manager, communicates with a database resource manager in directing the two-phase commit process. When using the XA protocol, the application does not need to process `rtr_mt_uncertain` messages (see the section Using XA, for more details on using XA).

The typical server application transaction sequence for committing a transaction to the database is as follows:

    rtr_receive_message (rtr_mt_msg1)
    SQL update
    rtr_accept_tx
    rtr_receive_message (rtr_mt_accepted)
    SQL commit
    rtr_receive_message [wait for next transaction]

This sequence is also illustrated in Figure 2-7, CSN Vote Window for the C API.

A failure can occur at any step in this sequence; the impact of a failure depends on when (at which step) it occurs, and on the server configuration.

## Failure before rtr_accept_tx

If a failure occurs before the `rtr_accept_tx` call is issued, RTR causes the following to occur:

- With no database replication: the transaction is aborted and the database rolled back.
- With a concurrent server: the database is rolled back and the transaction replayed to another server instance.
- With a standby server: the database is rolled back and the transaction replayed to the standby.
- With a shadow server: the shadow server completes the transaction as a lone member. When the failed server returns, the database is rolled back and the transaction is replayed.

## Failure after rtr_accept_tx

If a failure occurs after the `rtr_accept_tx` call is issued but before the `rtr_receive_message` , the transaction is replayed. The type of the first message is then `rtr_mt_uncertain` when the server is restarted. In this case, servers should check to see if the transaction has already been executed in a previous presentation. If not, it is safe to re-execute the transaction because the database operation never occurred. After the failure, the following occurs:

- With no database replication: the database is rolled back and the transaction is replayed as uncertain. The server should re-execute the transaction.
- With a concurrent server: the database is rolled back and the transaction is replayed as uncertain to another concurrent server. The server should re-execute the transaction.
- With a standby server: the database is rolled back and the transaction is replayed as uncertain to the standby server. The server should re-execute the transaction.
- With a shadow server: the shadow server completes the transaction as a lone member. When the failed server returns, the database is rolled back and the transaction is replayed as uncertain. The primary server should re-execute the transaction.

If a failure occurs after the SQL commit but before receipt of a message starting the next transaction, RTR does not know the difference.

If a failure occurs after an `rtr_receive_message` call is made to begin a new transaction, RTR assumes a successful commit if a server calls `rtr_receive_message` after receiving the `rtr_mt_accepted` message and will forget the transaction. There is no replay following these events.

Previous | Next | Contents | Index