What is a dependent transaction?

 

A dependent transaction is a special clone of an ITransaction.  It guarantees that the transaction will not commit, even after Commit() is called on the root transaction, until the dependent transaction votes that it is ready. 

 

Dependent transactions are created by calling DependentClone on ICommittableTransactions or ITransactions.  After you create a dependent transaction, you can vote on whether the transaction should commit or not by calling Complete().  When you call Complete() on the dependent transaction, you are voting that you are ready for the transaction to commit. The Complete call can be called before or after Commit() is called on the root ICommittableTransaction.

 

There are two types of dependent transactions, the first of which will block (hold up) the commit process of the transaction until Complete() is called on the dependent transaction.  This means that even after Commit() is called on the root ICommittableTransaction, the transaction will not commit until Complete() is called.  The second type will abort the transaction if Commit() is called on the ICommittableTransaction before the dependent transaction has completed.

 

When do you use dependent transactions?


One place you may use blocking dependent transactions are in applications that queue off asynchronous work for a transaction and want the commit processing to wait until all of the work is complete.

 

A good example for non-blocking dependent transactions are applications that are doing synchronous work and want to make sure the transaction does not accidentally commit before the work is done.

 

 

How do you create dependent transactions?

 

IDependentTransaction is an interface that derives from ITransaction and implements one additional method called Complete().

 

To create an IDependentTransaction you call DependentClone on an ITransaction and pass in a Boolean called delayCommit.  If delayCommit is true, you will get a blocking dependent transaction that will hold up commit until you call Complete().  If delayCommit is false, a non-blocking transaction is returned that will roll the transaction back if Commit() is called before Complete().

 

 

Async Threading Example:

 

void Foo()

{

            // Create a transaction and then a new dependent clone for each worker thread

            ICommittableTransaction myTx = Transaction.Create();

 

            // Create a new dependent blocking clone and then pass it to each worker thread

            for(int i; i < numberOfThreads; i++)

            {

                IDependentTransaction depTx = myTx.DependentClone( true );

                ThreadPool.QueueUserWorkItem( new WaitCallback( AsyncWork ), depTx );

            }

 

            // At this point commit can be called on the transaction

            myTx.Commit();

}

 

 

void AsyncWork( object state )

{

    IDependentTransaction depTx = (IDependentTransaction) state;

 

   // Do the transactional work here.

   if (workWasSuccessful)

    {

        depTx.Complete();

    }

    Else

    {

        depTx.Rollback();

    }

}