InternalTransaction.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 / fx / src / tx / System / Transactions / InternalTransaction.cs / 1305376 / InternalTransaction.cs

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

namespace System.Transactions 
{ 
    using System;
    using System.Collections; 
    using System.Diagnostics;
    using System.Globalization;
    using System.Runtime.Serialization;
    using System.Threading; 
    using System.Transactions.Diagnostics;
 
 
    // InternalTransaction
    // 
    // This class holds the state and all data common to a transaction instance
    class InternalTransaction : IDisposable
    {
        // This variable manages the state of the transaction it should be one of the 
        // static elements of TransactionState derived from TransactionState.
        protected TransactionState transactionState; 
        internal TransactionState State 
        {
            get 
            {
                return transactionState;
            }
            set 
            {
                transactionState = value; 
            } 
        }
 
        // This variable holds the state that the transaction will promote to.  By
        // default it uses the straight forward TransactionStatePromoted.  If the
        // transaction has a promotable single phase enlistment however it must use
        // a different state so that it is promoted correctly. 
        internal TransactionState promoteState;
 
#if DEBUG 
        // Keep a history of th transaction states
        internal const int MaxStateHist = 20; 
        internal TransactionState[] stateHistory = new TransactionState [MaxStateHist];
        internal int currentStateHist;
#endif
 
        // Finalized object see class definition for the use of this object
        internal FinalizedObject finalizedObject; 
 
        internal int transactionHash;
        internal int TransactionHash 
        {
            get
            {
                return this.transactionHash; 
            }
        } 
 

        internal static int nextHash; 

        // timeout stores a relative timeout for the transaction.  absoluteTimeout stores
        // the actual time in ticks.
        private long absoluteTimeout; 
        internal long AbsoluteTimeout
        { 
            get 
            {
                return this.absoluteTimeout; 
            }
        }

        // record the current number of ticks active when the transaction is created. 
        private Int64 creationTime;
        internal Int64 CreationTime 
        { 
            get
            { 
                return this.creationTime;
            }
            set
            { 
                this.creationTime = value;
            } 
        } 

        // The goal for the LTM is to only allocate as few heap objects as possible for a given 
        // transaction and all of its enlistments.  To accomplish this, enlistment objects are
        // held in system arrays.  The transaction contains one enlistment for the single durable
        // enlistment it can handle and a small array of volatile enlistments.  If the number of
        // enlistments for a given transaction exceeds the capacity of the current array a new 
        // larger array will be created and the contents of the old array will be copied into it.
        // Heuristic data based on TransactionType can be created to avoid this sort of copy 
        // operation repeatedly for a given type of transaction.  So if a transaction of a specific 
        // type continually causes the array size to be increased the LTM could start
        // allocating a larger array initially for transactions of that type. 
        internal InternalEnlistment durableEnlistment;
        internal VolatileEnlistmentSet phase0Volatiles;
        internal VolatileEnlistmentSet phase1Volatiles;
 
        // This member stores the number of phase 0 volatiles for the last wave
        internal int phase0VolatileWaveCount; 
 
        // These members are used for promoted waves of dependent blocking clones.  The Ltm
        // does not register individually for each blocking clone created in phase 0.  Instead 
        // it multiplexes a single phase 0 blocking clone only created after phase 0 has started.
        internal Oletx.OletxDependentTransaction phase0WaveDependentClone;
        internal int phase0WaveDependentCloneCount;
 
        // These members are used for keeping track of aborting dependent clones if we promote
        // BEFORE we get an aborting dependent clone or a Ph1 volatile enlistment.  If we 
        // promote before we get either of these, then we never create a Ph1 volatile enlistment 
        // on the distributed TM.  If we promote AFTER an aborting dependent clone or Ph1 volatile
        // enlistment is created, then we create a Ph1 volatile enlistment on the distributed TM 
        // as part of promotion, so these won't be used.  In that case, the Ph1 volatile enlistment
        // on the distributed TM takes care of checking to make sure all the aborting dependent
        // clones have completed as part of its Prepare processing.  These are used in conjunction with
        // phase1volatiles.dependentclones. 
        internal Oletx.OletxDependentTransaction abortingDependentClone;
        internal int abortingDependentCloneCount; 
 
        // When the size of the volatile enlistment array grows increase it by this amount.
        internal const int volatileArrayIncrement = 8; 

        // Data maintained for TransactionTable participation
        internal Bucket tableBucket;
        internal int bucketIndex; 

        // Delegate to fire on transaction completion 
        internal TransactionCompletedEventHandler transactionCompletedDelegate; 

        // If this transaction get's promoted keep a reference to the promoted transaction 
        private Oletx.OletxTransaction promotedTransaction;
        internal Oletx.OletxTransaction PromotedTransaction
        {
            get 
            {
                return this.promotedTransaction; 
            } 
            set
            { 
                Debug.Assert( this.promotedTransaction == null, "A transaction can only be promoted once!" );
                this.promotedTransaction = value;
            }
        } 

 
        // If there was an exception that happened during promotion save that exception so that it 
        // can be used as an inner exception to the transaciton aborted exception.
        internal Exception innerException = null; 

        // Note the number of Transaction objects supported by this object
        internal int cloneCount;
 
        // The number of enlistments on this transaction.
        internal int enlistmentCount = 0; 
 
        // Manual Reset event for IAsyncResult support
        internal ManualResetEvent asyncResultEvent; 

        // Store the callback and state for the caller of BeginCommit
        internal bool asyncCommit;
        internal AsyncCallback asyncCallback; 
        internal object asyncState;
 
        // Flag to indicate if we need to be pulsed for tx completion 
        internal bool needPulse;
 
        // Store the transaction information object
        internal TransactionInformation transactionInformation;

        // Store a reference to the owning Committable Transaction 
        internal CommittableTransaction committableTransaction;
 
        // Store a reference to the outcome source 
        internal Transaction outcomeSource;
 
        // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) )
        private static object classSyncObject;
        internal static object ClassSyncObject
        { 
            get
            { 
                if( classSyncObject == null ) 
                {
                    object o = new object(); 
                    Interlocked.CompareExchange( ref classSyncObject, o, null );
                }
                return classSyncObject;
            } 
        }
 
        static string instanceIdentifier; 
        static internal string InstanceIdentifier
        { 
            get
            {
                if( instanceIdentifier == null )
                { 
                    lock( ClassSyncObject )
                    { 
                        if( instanceIdentifier == null ) 
                        {
                            string temp = Guid.NewGuid().ToString() + ":"; 
                            Thread.MemoryBarrier();
                            instanceIdentifier = temp;
                        }
                    } 
                }
                return instanceIdentifier; 
            } 
        }
 
        // The trace identifier for the internal transaction.
        private TransactionTraceIdentifier traceIdentifier;
        internal TransactionTraceIdentifier TransactionTraceId
        { 
            get
            { 
                if( this.traceIdentifier == TransactionTraceIdentifier.Empty ) 
                {
                    lock( this ) 
                    {
                        if( this.traceIdentifier == TransactionTraceIdentifier.Empty )
                        {
                            TransactionTraceIdentifier temp = new TransactionTraceIdentifier( 
                                InstanceIdentifier + Convert.ToString( this.transactionHash, CultureInfo.InvariantCulture ),
                                0 ); 
                            Thread.MemoryBarrier(); 
                            this.traceIdentifier = temp;
                        } 
                    }
                }
                return this.traceIdentifier;
            } 
        }
 
        internal ITransactionPromoter promoter; 

        // Construct an internal transaction 
        internal InternalTransaction( TimeSpan timeout, CommittableTransaction committableTransaction )
        {
            if( !TransactionManager._platformValidated ) TransactionManager.ValidatePlatform();
 
            // Calculate the absolute timeout for this transaction
            this.absoluteTimeout = TransactionManager.TransactionTable.TimeoutTicks( timeout ); 
 
            // Start the transaction off as active
            TransactionState._TransactionStateActive.EnterState( this ); 

            // Until otherwise noted this transaction uses normal promotion.
            this.promoteState = TransactionState._TransactionStatePromoted;
 
            // Keep a reference to the commitable transaction
            this.committableTransaction = committableTransaction; 
            this.outcomeSource = committableTransaction; 

            // Initialize the hash 
            this.transactionHash = TransactionManager.TransactionTable.Add( this );
        }

 
        // Construct an internal transaction
        internal InternalTransaction( Transaction outcomeSource, Oletx.OletxTransaction distributedTx ) 
        { 
            if( !TransactionManager._platformValidated ) TransactionManager.ValidatePlatform();
 
            this.promotedTransaction = distributedTx;

            this.absoluteTimeout = long.MaxValue;
 
            // Store the initial creater as it will be the source of outcome events
            this.outcomeSource = outcomeSource; 
 
            // Initialize the hash
            this.transactionHash = TransactionManager.TransactionTable.Add( this ); 

            // Start the transaction off as active
            TransactionState._TransactionStateNonCommittablePromoted.EnterState( this );
 
            // Until otherwise noted this transaction uses normal promotion.
            this.promoteState = TransactionState._TransactionStateNonCommittablePromoted; 
        } 

 
        // Construct an internal transaction
        internal InternalTransaction( Transaction outcomeSource, ITransactionPromoter promoter )
        {
            if( !TransactionManager._platformValidated ) TransactionManager.ValidatePlatform(); 

            this.absoluteTimeout = long.MaxValue; 
 
            // Store the initial creater as it will be the source of outcome events
            this.outcomeSource = outcomeSource; 

            // Initialize the hash
            this.transactionHash = TransactionManager.TransactionTable.Add( this );
 
            // Save the transaction promoter.
            this.promoter = promoter; 
 
            // This transaction starts in a special state.
            TransactionState._TransactionStateSubordinateActive.EnterState( this ); 

            // This transaction promotes through delegation
            this.promoteState = TransactionState._TransactionStateDelegatedSubordinate;
         } 

 
        internal static void DistributedTransactionOutcome( InternalTransaction tx, TransactionStatus status ) 
        {
            FinalizedObject fo = null; 

            lock( tx )
            {
                if ( null == tx.innerException ) 
                {
                    tx.innerException = tx.PromotedTransaction.InnerException; 
                } 

                switch (status) 
                {
                    case TransactionStatus.Committed :
                    {
                        tx.State.ChangeStatePromotedCommitted( tx ); 
                        break;
                    } 
 
                    case TransactionStatus.Aborted :
                    { 
                        tx.State.ChangeStatePromotedAborted( tx );
                        break;
                    }
 
                    case TransactionStatus.InDoubt :
                    { 
                        tx.State.InDoubtFromDtc( tx ); 
                        break;
                    } 

                    default :
                    {
                        Debug.Assert( false, "InternalTransaction.DistributedTransactionOutcome - Unexpected TransactionStatus" ); 
                        TransactionException.CreateInvalidOperationException( SR.GetString( SR.TraceSourceLtm ),
                            "", 
                            null 
                            );
                        break; 
                    }

                }
 
                fo = tx.finalizedObject;
            } 
 
            if( null != fo )
            { 
                fo.Dispose();
            }
        }
 
        #region Outcome Events
 
        // Signal Waiters anyone waiting for transaction outcome. 
        internal void SignalAsyncCompletion()
        { 
            if( this.asyncResultEvent != null )
            {
                this.asyncResultEvent.Set();
            } 

            if( this.asyncCallback != null ) 
            { 
                System.Threading.Monitor.Exit( this ); // Don't hold a lock calling user code.
                try 
                {
                    this.asyncCallback( this.committableTransaction );
                }
                finally 
                {
#pragma warning disable 0618 
                    //@ 
                    System.Threading.Monitor.Enter(this);
#pragma warning restore 0618 
                }
            }
        }
 

        // Fire completion to anyone registered for outcome 
        internal void FireCompletion( ) 
        {
            TransactionCompletedEventHandler eventHandlers = this.transactionCompletedDelegate; 

            if( eventHandlers != null )
            {
                TransactionEventArgs args = new TransactionEventArgs(); 
                args.transaction = this.outcomeSource.InternalClone();
 
                eventHandlers( args.transaction, args ); 
            }
        } 


        #endregion
 

        #region IDisposable Members 
 
        // FXCop wants us to dispose nextLink, which is another InternalTransaction, and thus disposable.  But we don't
        // want to do that here.  That link is for the list of all InternalTransactions. 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed")]
        public void Dispose()
        {
            if( this.promotedTransaction != null ) 
            {
                // If there is a promoted transaction dispose it. 
                this.promotedTransaction.Dispose(); 
            }
        } 

        #endregion
    }
 

 
    // Finalized Object 
    //
    // This object is created if the InternalTransaction needs some kind of finalization.  An 
    // InternalTransaction will only need finalization if it is promoted so having a finalizer
    // would only hurt performance for the unpromoted case.  When the Ltm does promote it creates this
    // object which is finalized and will handle the necessary cleanup.
    sealed class FinalizedObject : IDisposable 
    {
        // Keep the identifier separate.  Since it is a struct it wont be finalized out from under 
        // this object. 
        Guid identifier;
 
        InternalTransaction internalTransaction;

        internal FinalizedObject( InternalTransaction internalTransaction, Guid identifier )
        { 
            this.internalTransaction = internalTransaction;
            this.identifier = identifier; 
        } 

 
        private void Dispose( bool disposing )
        {
            if( disposing )
            { 
                GC.SuppressFinalize(this);
            } 
 
            // We need to remove the entry for the transaction from the static
            // LightweightTransactionManager.PromotedTransactionTable. 
            Hashtable promotedTransactionTable = TransactionManager.PromotedTransactionTable;
            lock( promotedTransactionTable )
            {
                WeakReference weakRef = (WeakReference) promotedTransactionTable[ this.identifier ]; 
                if ( null != weakRef )
                { 
                    if( weakRef.Target != null ) 
                    {
                        weakRef.Target = null; 
                    }
                }

                promotedTransactionTable.Remove( this.identifier ); 
            }
        } 
 

        public void Dispose() 
        {
            Dispose(true);
        }
 

        ~FinalizedObject() 
        { 
            Dispose(false);
        } 
    }
}


// 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