SAFplus

Transaction (Txn)

A transaction allows multiple operations to occur across the cluster (or multiple clusters) in an all-or-nothing manner. Transactions are:

All operations (event, messaging, log etc) should support transactions (it is recommended to use c++ optional parameter). This allows the entire system to have the consistency property, if desired. For example:

   1 myMessage = queue.dequeue();
   2 message.send(destUid, myMessage);
   3 log.info("Message Sent");

If the system fails after line 1, the message is lost. If it fails after line 2, the logs do not properly describe what happened.

To solve these issues use transactions:

   1 Txn txn;
   2 myMessage = queue.dequeue(txn);
   3 message.send(destUid, myMessage,txn);
   4 log.info("Message Sent",txn);
   5 
   6 if (reallyDoIt)
   7   {
   8   txn.commit();
   9   }
  10 else
  11   {
  12   txn.abort();
  13   }

Operational walkthrough

Given the code example above the follows describes what happens.

When a transaction is created, a unique handle is allocated for it. By default, this transaction handle is linked to the process, so a process death will abort() the transaction. But the user can construct a handle of a different type and then pass that handle into the transaction constructor to implement different behavior.

When an API call is made, the operation is carried as far as possible (into the application process) to ensure that it will succeed during a commit. But the operation does not actually occur. So in the message.send() example, the message is actually sent to the destination during the message.send API call. At the destination, a txn object with the same handle is created inside the SAFplus lib within the destination application process if it does not already exist (look up by txn id).

Next, one of 2 behaviors occur:

  1. Destination application is transaction aware:
    • The destination application calls (message, txn) = msg.Recv(), and it can see by the txn that we are in the validate stage. It then calls msg.validate(message, txn, true/false) to ok or nok the message.
  2. Destination application is not transaction aware:
    • This object is invisible to the application. A txn msg queue handler object is created TxnMsgQueueHandler tq(msg,txn). bool result = tq.validate() is called which checks basic items like whether application is capable of receiving this message.

Next, transactional log.info() is called. This allocates the required space in the log's shared memory, but marks the log entry as "unconfirmed". (An unconfirmed log entry will be not shown...) A txn log handler object is created that points to this log entry and it is added to the txn.

When txn.commit() or txn.abort() occurs, an ioc message is broadcast to all nodes/processes in the cluster. All processes receive this message and look up the transaction by id. The transaction handler library calls txn.commit() or txn.abort() if the transaction exists in its process space.

Txn.commit()/abort() iterates through its list of transaction operations and calls commit or abort on each operation. The commit/abort function call also releases (frees) the transaction operation.

So in this case, the TxnMsgQueueHandler.commit() and the TxnLogHandler.commit() is called. TxnMsgQueueHandler.commit() passes the message to the user application, and TxnLogHandler.commit() marks the log entry as "confirmed".

Object Structure

A Transaction is a class containing a Handle and a list of TransactionOperations.

A TransactionOperation is an abstract base class that provides 3 operations:

bool validate(Transaction& t); // Return true/false if this operation is valid. The parent Transaction is supplied so this operation can ensure that there are no conflicting operations. Validate also reserves any resources required to ensure that the operation will succeed. void commit(); // make the operation happen void abort(); // do not do the operation, and free any resources reserved.

SAFplus: Transaction (last edited 2014-02-28 03:10:36 by AndrewStone)