TransactionWaitAsyncResult.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.ServiceModel.Activities / System / ServiceModel / Activities / Dispatcher / TransactionWaitAsyncResult.cs / 1305376 / TransactionWaitAsyncResult.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------

namespace System.ServiceModel.Activities.Dispatcher 
{
    using System.Runtime; 
    using System.Transactions; 
    using System.Threading;
 
    sealed class TransactionWaitAsyncResult : AsyncResult
    {
        static Action timerCallback;
 
        DependentTransaction dependentTransaction;
        IOThreadTimer timer; 
 
        [Fx.Tag.SynchronizationObject(Blocking = false)]
        object thisLock; 

        internal TransactionWaitAsyncResult(Transaction transaction, PersistenceContext persistenceContext, TimeSpan timeout, AsyncCallback callback, object state)
            : base(callback, state)
        { 
            bool completeSelf = false;
            TransactionException exception = null; 
            this.PersistenceContext = persistenceContext; 
            this.thisLock = new object();
 
            if (null != transaction)
            {
                // We want an "blocking" dependent transaction because we want to ensure the transaction
                // does not commit successfully while we are still waiting in the queue for the PC transaction 
                // lock.
                this.dependentTransaction = transaction.DependentClone(DependentCloneOption.BlockCommitUntilComplete); 
            } 
            else
            { 
                this.dependentTransaction = null;
            }

            // Put a lock around this and Complete() in case the transaction we are queueing up behind 
            // finishes and we end up calling Complete() before we actually finish constructing this
            // object by creating the DependentClone and setting up the IOThreadTimer. 
            lock (ThisLock) 
            {
                if (persistenceContext.QueueForTransactionLock(transaction, this)) 
                {
                    // If we were given a transaction in our constructor, we need to
                    // create a volatile enlistment on it and complete the
                    // dependent clone that we created. This will allow the transaction to commit 
                    // successfully when the time comes.
                    if (null != transaction) 
                    { 
                        // We are not going async, so we need to complete our dependent clone now.
                        this.dependentTransaction.Complete(); 

                        exception = this.CreateVolatileEnlistment(transaction);
                    }
                    completeSelf = true; 
                }
                else 
                { 
                    // If the timeout value is not TimeSpan.MaxValue, start a timer.
                    if (timeout != TimeSpan.MaxValue) 
                    {
                        this.timer = new IOThreadTimer(TimeoutCallbackAction, this, true);
                        this.timer.Set(timeout);
                    } 
                }
            } 
 
            // We didn't want to call Complete while holding the lock.
            if (completeSelf) 
            {
                base.Complete(true, exception);
            }
        } 

        internal PersistenceContext PersistenceContext { get; set; } 
 
        internal Transaction Transaction
        { 
            get
            {
                return this.dependentTransaction;
            } 
        }
 
        object ThisLock 
        {
            get 
            {
                return this.thisLock;
            }
        } 

        internal static Action TimeoutCallbackAction 
        { 
            get
            { 
                if (timerCallback == null)
                {
                    timerCallback = new Action(TimeoutCallback);
                } 
                return timerCallback;
            } 
        } 

        // Returns true if this TransactionWaitAsyncResult was completed and has NOT timed out. 
        // Returns false if this TransactionWaitAsyncResult has timed out.
        internal bool Complete()
        {
            Exception exception = null; 

            // Lock to prevent completion while we are still in the process of constructing this object. 
            lock (ThisLock) 
            {
                // If we have a timer, but it has already expired, return false. 
                if ((this.timer != null) && (!this.timer.Cancel()))
                {
                    return false;
                } 

                // If we have a dependent transaction, complete it now. 
                if (this.dependentTransaction != null) 
                {
                    // If we were given a transaction in our constructor, we need to 
                    // create a volatile enlistment on it and complete the
                    // dependent clone that we created. This will allow the transaction to commit
                    // successfully when the time comes.
                    exception = this.CreateVolatileEnlistment(this.dependentTransaction); 
                    this.dependentTransaction.Complete();
                } 
            } 

            // Indicate that we are complete. 
            Complete(false, exception);

            return true;
        } 

        TransactionException CreateVolatileEnlistment(Transaction transactionToEnlist) 
        { 
            TransactionException result = null;
            PersistenceContextEnlistment enlistment = null; 
            int key = transactionToEnlist.GetHashCode();
            lock (PersistenceContext.Enlistments)
            {
                try 
                {
                    if (!PersistenceContext.Enlistments.TryGetValue(key, out enlistment)) 
                    { 
                        enlistment = new PersistenceContextEnlistment(this.PersistenceContext, transactionToEnlist);
                        transactionToEnlist.EnlistVolatile(enlistment, EnlistmentOptions.None); 
                        // We don't save of the Enlistment object returned from EnlistVolatile. We don't need
                        // it here. When our PersistenceContextEnlistment object gets notified on Prepare,
                        // Commit, Rollback, or InDoubt, it is provided with the Enlistment object.
                        PersistenceContext.Enlistments.Add(key, enlistment); 
                    }
                    else 
                    { 
                        enlistment.AddToEnlistment(this.PersistenceContext);
                    } 
                }
                catch (TransactionException txException)
                {
                    result = txException; 

                    // We own the lock but failed to create enlistment.  Manually wake up the next waiter. 
                    // We only handle TransactionException, in case of other exception that failed to create enlistment, 
                    // It will fallback to Timeout.  This is safe to avoid multiple waiters owning same lock.
                    this.PersistenceContext.ScheduleNextTransactionWaiter(); 
                }
            }
            return result;
        } 

        static void TimeoutCallback(object state) 
        { 
            TransactionWaitAsyncResult thisPtr = (TransactionWaitAsyncResult)state;
            Fx.Assert(null != thisPtr, "TransactionWaitAsyncResult.TimeoutCallback called with an object that is not a TransactionWaitAsyncResult."); 

            // As a general policy, we are not going to rollback the transaction because of this timeout. Instead, we are letting
            // the caller make the decision to rollback or not based on exception we are throwing. It could be that they could
            // tolerate the timeout and try something else and still commit the transaction. 
            if (thisPtr.dependentTransaction != null)
            { 
                thisPtr.dependentTransaction.Complete(); 
            }
 
            thisPtr.Complete(false, new TimeoutException(SR.TransactionPersistenceTimeout));
        }

        public static void End(IAsyncResult result) 
        {
            AsyncResult.End(result); 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK