VisiTransact Guide : Transaction completion

Transaction completion
This section provides information about transaction completion, explains heuristic completion, and provides information necessary for multithreaded applications.
Transaction completion
Transaction completion is a sequence of steps that the VisiTransact Transaction Service goes through when it receives a request to either commit or rollback the work of a transactional application. The request for completion can be initiated in different circumstances:
How does the VisiTransact Transaction Service ensure completion?
When a transaction originator requests to commit or roll back a transaction, the VisiTransact Transaction Service initiates the completion procedure for the transaction. Assume there are two Resources that are involved in a single transaction. When a request to commit arrives, the VisiTransact Transaction Service will initiate a two phase commit procedure to coordinate the completion.
If the transaction completes by successfully executing the two phase commit procedure without failure, the originator is notified with the outcome. If the transaction cannot complete due to a specific reason—for example, when one of the Resources is not available in the commit phase of the two phase procedure—the VisiTransact Transaction Service cannot complete the transaction and it will place the transaction in a Retry Queue for later attempts. When a transaction is placed in the Retry Queue, the transaction is not dispatched immediately for completion. There is a programmed delay between each retry attempt to prevent degradation of system performance. The minimum time between retry attempts is 15 seconds and the maximum is 900 seconds. The first retry attempt will start after 15 seconds and for the subsequent attempts, the delay is increased until it reaches 900 seconds. After that, the retry attempts are every 900 seconds. If a retry attempt is made due to a timeout or a recovery, the first retry attempt is dispatched immediately without waiting for the 15 seconds delay. During retry attempts, the VisiTransact Transaction Service executes only those portions of a transaction that have not yet been completed. The transaction remains in the Retry Queue until it completes or until a “Stop Completion” command is issued by the VisiBroker Console. If you query from the Console for a list of transactions, the transactions with several retry attempts are highlighted.
Retry attempt scenarios are as follows:
A transaction timeout occurs. If a timeout period has been specified for a transaction and the transaction does not complete within this limit, the transaction is placed in the Retry Queue. If the transaction has entered the completion stage when the timeout expires, the timeout will be ignored by the VisiTransact Transaction Service. You can set the default timeout for the VisiTransact Transaction Service at the command line.
A Resource is unavailable. A Resource that is involved in the transaction is temporarily not available due to a communication failure or because the Resource server is down. The transaction is placed in the Retry Queue until it completes.
The VisiTransact Transaction Service recovers and decision records show transactions are incomplete. During recovery, the information is gathered from the transaction log about the transactions that were incomplete when the VisiTransact Transaction Service went down. If the decision records indicate that the transaction has not completed yet, they are placed in the Retry Queue for completion.
The number of times a transaction has to be retried can be configured using the property:
vbroker.ots.completionRetryAttempts=n.
By configuring this property and setting it to an integer value "n", you can change the number of retries.
If n is set to a value less than or equal to 0, the transaction is retried for ever. This is the default behavior. If it is set to a value greater than 0, the transaction is put into the retry queue, and during each attempt the transaction service will try to run the transaction to completion. If it fails, the transaction is put into the retry queue no more than n number of times. Note that "n" includes the original attempt in the count. So if for example you do not want the transaction to be retried after a failure, you must set "n" to 1. If you do want the transaction to be retried only once after a failure, you must set "n" to 2.
How does the VisiTransact Transaction Service ensure checked behavior?
The VisiTransact Transaction Service implements full Distributed Transaction Processing (DTP) checked behavior to provide an extra level of transaction integrity. Checked behavior protects against loss to data integrity by ensuring that all transactional requests made by the application have completed their processing before the transaction is committed. This guarantees that a commit will not succeed unless all transaction participants have completed the processing of their transactional requests. Checked behavior occurs by default when all requests are synchronous.
Checked behavior is enforced for VisiTransact-managed transactions involved with deferred synchronous requests: transactions are rolled back if there are pending replies when a commit() is issued. If the request handler of a transactional object makes a deferred synchronous request and replies before the deferred synchronous request returns, the transaction is marked for rollback.
VisiTransact does not enforce checked behavior on one-way requests.
The example below shows the client code for checked behavior when you have a deferred synchronous request and the reply returns after commit() is invoked. Checked behavior is successful—the transaction is rolled back.
...
// get reference to the Current
...

// begin a transaction
current->begin();

// create a dynamic request
CORBA::Request_var bankRequest = bank->_request("withdraw");
CORBA::NVList_ptr arguments = bankRequest->arguments();

CORBA::Any_var amt = new CORBA::Any();
*amt<<= ((float)1000.00);

arguments->add_value("amount", amt, CORBA::ARG_IN);

...

//invoke deferred synchronous request
bankRequest->send_deferred();

//forget to get the response
// commit the txn
try
{
current->commit(0);
}
catch(CORBA::TRANSACTION_ROLLEDBACK& e)
{
cerr << "SUCCESS, commit check worked()" << endl;
}
...
The example below shows the client code for checked behavior when you have a deferred synchronous request and the reply returns before commit() is invoked. Checked behavior is successful—the transaction is committed.
...
// case where request arrived before commit
current->begin();

cerr << " === Invoking a dii deferred sync request" << endl;
bankRequest->send_deferred();

try {
//wait for reply
bankRequest->get_response();
current->commit(0);
}
catch(CORBA::TRANSACTION_ROLLEDBACK& e)
{
cerr << "FAILURE, TRANSACTION_ROLLEDBACK not expected" << endl;
}

}
Heuristic completion
Heuristic completion is when a transaction attempts to complete and one of its participating Resources makes a heuristic decision during the completion stage. An heuristic decision is a unilateral decision made by one or more Resources to commit or rollback updates without regard to the outcome determined by the transaction manager.
Heuristic decisions typically only occur during unusual circumstances that prevent normal processing, such as a network failure, or if the coordinator does not complete the two-phase commit process in a timely manner. When a heuristic decision is made there is a risk the decision is different from the outcome determined by the transaction manager, resulting in a loss of data integrity.
The types of heuristic outcome exceptions that are returned by the resources are:
HeuristicRollback - The commit operation on Resource reports that a heuristic decision was made and that all relevant updates have been rolled back.
HeuristicCommit - The rollback operation on Resource reports that a heuristic decision was made and all relevant updates have been committed.
HeuristicMixed - The Resource has committed some relevant updates, and rolled back others.
HeuristicHazard - The Resource does not know the result of at least one relevant update (the disposition of all relevant updates is not known). For the updates that are known, either all have been committed or all have been rolled back.
A Resource can make a heuristic decision at any point during two-phase commit. For example, if the Terminator does not complete the two-phase commit in a timely manner, a Resource can elect to make a heuristic decision. A heuristic decision is a way that a Resource object can break guarantees it made during the two-phase commit process (that is, when it returned VoteCommit during prepare()).
However, if a Resource has replied VoteCommit to the Terminator, and then subsequently makes a heuristic decision, it is still responsible for reporting its action regarding the transaction. The following may occur when the Terminator eventually requests that the Resource rollback or commit:
The heuristic decision may be consistent with the outcome. If this is the case, the transaction can be completed normally, and the Resource may “forget” about the transaction and the heuristic decision. The Terminator does not need to be informed of the heuristic decision since it was consistent with the outcome of the transaction.
The heuristic decision may differ from the outcome. In this case, the Resource consults its record of the heuristic outcome (which it previously placed in the stable storage), and returns one of the heuristic outcome exceptions (HeuristicCommit, HeuristicRollback, HeuristicMixed or HeuristicHazard) when completion continues.
Enabling heuristic reporting to your application
A transaction originator can request to receive heuristic reporting by setting the report_heuristics parameter of the commit() method to true. Notice the following code sample shows the commit() method as commit(1) for C++.
Handling heuristic reporting
...
if (bank->withdraw(10,444)) //invoke the withdraw method.
{
try
{
current->commit(1); //The parameter 1 requests the server to
//return the heuristic outcomes if there are any.
}
catch (const CosTransactions::NoTransaction& e)
{
//commit was issued when there is no transaction
//Handle it.

}
catch (const CosTransactions::HeuristicMixed& e)
{
//Heuristic decision was made. Some of the relevant updates
//have been committed and others may have rolled back.
//Handle it.
}
catch (const CosTransaction::HeuristicHazard& e)
{
//Heuristic decision was made. The relevant updates that
//have been made either all have been committed or rolledback.
//Handle it.
}
}
else
{
current->rollback();
}
A Resource can handle heuristic reporting programmatically, or can require the intervention of a system administrator.
OTS exceptions
Additional OTS exceptions are:
SubtransactionsUnavailable – This exception is raised if the client thread already has an associated transaction and the transaction service implementation does not support nested transactions.
NotSubtransaction – This exception is raised if the current transaction is not a subtransaction.
Inactive – This exception is raised in a few scenarios whereby no action is taken when the current context is not right for the command issued.
NotPrepared – This exception is raised when a transaction is not prepared (for two-phase commit transactions only).
NoTransaction – This exception is raised when there is no transaction associated with the client thread.
Unavailable – This exception is raised when the application can't get hold of propagation context.
SynchronizationUnavailable – This exception is raised if the system does not support synchronization.