Search:

Search all manuals
Search this manual
Manual
Couchbase Server Manual 2.0
Community Wiki and Resources
Download Couchbase Server 2.0
Couchbase Developer Guide 2.0
Client Libraries
Couchbase Server Forum
Additional Resources
Community Wiki
Community Forums
Couchbase SDKs
Parent Section
9.9 View and Query Pattern Samples
Chapter Sections
Chapters

9.9.12. Simulating Multi-phase Transactions

The technique in Section 9.9.11, “Simulating Transactions” will work if your data will allow the use of a view to effectively roll-up the changes into a single operation. However, if your data and document structure do not allow it then you can use a multi-phase transaction process to perform the operation in a number of distinct stages.

Warning

This method is not reliant on views, but the document structure and update make it easy to find out if there are 'hanging' or trailing transactions that need to be processed without additional document updates. Using views and the Observe operation to monitor changes could lead to long wait times during the transaction process while the view index is updated.

To employ this method, you use a similar transaction record as in the previous example, but use the transaction record to record each stage of the update process.

Start with the same two account records:

JSON
{
   "type" : "account",
   "account" : "James",
   "value" : 100,
   "transactions" : []
}

The record explicitly contains a transactions field which contains an array of all the currently active transactions on this record.

The corresponding record for the other account:

JSON
{
   "type" : "account",
   "account" : "Alice",
   "value" : 200,
   "transactions" : []
}

Now perform the following operations in sequence:

  1. Create a new transaction record that records the transaction information:

    JSON
    {
         "type" : "transaction",
         "fromacct" : "Alice",
         "toacct" : "James",
         "value" : 100,
         "status" : "waiting"
    }

    The core of the transaction record is the same, the difference is the use of a status field which will be used to monitor the progress of the transaction.

    Record the ID of the transaction, for example, transact_20120717163.

  2. Set the value of the status field in the transaction document to 'pending':

    JSON
    {
         "type" : "transaction",
         "fromacct" : "Alice",
         "toacct" : "James",
         "value" : 100,
         "status" : "pending"
    }
  3. Find all transaction records in the pending state using a suitable view:

    Javascript
    function(doc, meta) 
    {
      if (doc.type && doc.status &&
          doc.type == "transaction" && doc.status == "pending" ) 
      {
        emit([doc.fromacct,doc.toacct], doc.value);
      }
    }
  4. Update the record identified in toacct with the transaction information, ensuring that the transaction is not already pending:

    JSON
    {
       "type" : "account",
       "account" : "Alice",
       "value" : 100,
       "transactions" : ["transact_20120717163"]
    }

    Repeat on the other account:

    JSON
    {
       "type" : "account",
       "account" : "James",
       "value" : 200,
       "transactions" : ["transact_20120717163"]
    }
  5. Update the transaction record to mark that the records have been updated:

    JSON
    {
         "type" : "transaction",
         "fromacct" : "Alice",
         "toacct" : "James",
         "value" : 100,
         "status" : "committed"
    }
  6. Find all transaction records in the committed state using a suitable view:

    Javascript
    function(doc, meta) 
    {
      if (doc.type && doc.status && 
          doc.type == "transaction" && doc.status == "committed" ) 
      {
        emit([doc.fromacct, doc.toacct], doc.value);
      }
    }

    Update the source account record noted in the transaction and remove the transaction ID:

    JSON
    {
       "type" : "account",
       "account" : "Alice",
       "value" : 100,
       "transactions" : []
    }

    Repeat on the other account:

    JSON
    {
       "type" : "account",
       "account" : "James",
       "value" : 200,
       "transactions" : []
    }
  7. Update the transaction record state to 'done'. This will remove the transaction from the two views used to identify unapplied, or uncommitted transactions.

Within this process, although there are multiple steps required, you can identify at each step whether a particular operation has taken place or not.

For example, if the transaction record is marked as 'pending', but the corresponding account records do not contain the transaction ID, then the record still needs to be updated. Since the account record can be updated using a single atomic operation, it is easy to determine if the record has been updated or not.

The result is that any sweep process that accesses the views defined in each step can determine whether the record needs updating. Equally, if an operation fails, a record of the transaction, and whether the update operation has been applied, also exists, allowing the changes to be reversed and backed out.