Previous | Contents | Index |
There are two ways to start a transaction:
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 |
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:
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; |
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.
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.
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.
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.
The two-phase commit process includes prepare and commit phases. A transaction is tentatively accepted or rejected during the 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.
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:
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.
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:
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.
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.
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.
If a failure occurs before the rtr_accept_tx call is issued, RTR causes the following to occur:
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:
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 |