TransactionManager.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 / TransactionManager.cs / 1305376 / TransactionManager.cs

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

using System; 
using System.Collections; 
using System.Collections.Generic;
using System.Collections.Specialized; 
using System.Configuration;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices; 
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary; 
using System.Security; 
using System.Security.Permissions;
using System.Threading; 
using System.Transactions.Configuration;
using System.Transactions.Diagnostics;
using System.Xml;
using System.Xml.Serialization; 

[assembly:BestFitMapping(false)] 
#pragma warning disable 618 
[assembly:SecurityPermissionAttribute(SecurityAction.RequestMinimum)]
#pragma warning restore 618 

// No external data is ever passed to PrivilegedConfigurationManager.GetSection
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts",
            Scope="member", 
            Target="System.Configuration.PrivilegedConfigurationManager.GetSection(System.String):System.Object")]
 
namespace System.Transactions 
{
    public delegate Transaction HostCurrentTransactionCallback(); 

    public delegate void TransactionStartedEventHandler(object sender, TransactionEventArgs e);

    public static class TransactionManager 
    {
        // Revovery Information Version 
        private const Int32 recoveryInformationVersion1 = 1; 
        private const Int32 currentRecoveryVersion = recoveryInformationVersion1;
 
        // Record if the platform has been validated.
        internal static bool _platformValidated;

        // Hashtable of promoted transactions, keyed by identifier guid.  This is used by 
        // FindPromotedTransaction to support transaction equivalence when a transaction is
        // serialized and then deserialized back in this app-domain. 
        private static Hashtable promotedTransactionTable; 

        // Sorted Table of transaction timeouts 
        private static TransactionTable transactionTable;

        private static TransactionStartedEventHandler distributedTransactionStartedDelegate;
        public static event TransactionStartedEventHandler DistributedTransactionStarted 
        {
            [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] 
            add 
            {
                if( !TransactionManager._platformValidated ) TransactionManager.ValidatePlatform(); 

                lock( ClassSyncObject )
                {
                    TransactionManager.distributedTransactionStartedDelegate = (TransactionStartedEventHandler)System.Delegate.Combine(TransactionManager.distributedTransactionStartedDelegate, value); 
                    if( value != null )
                    { 
                        ProcessExistingTransactions( value ); 
                    }
                } 
            }

            [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
            remove 
            {
                if( !TransactionManager._platformValidated ) TransactionManager.ValidatePlatform(); 
 
                lock ( ClassSyncObject )
                { 
                    TransactionManager.distributedTransactionStartedDelegate = (TransactionStartedEventHandler)System.Delegate.Remove (TransactionManager.distributedTransactionStartedDelegate, value);
                }
            }
        } 

 
        internal static void ProcessExistingTransactions( TransactionStartedEventHandler eventHandler ) 
        {
            lock( PromotedTransactionTable ) 
            {
                foreach( DictionaryEntry entry in PromotedTransactionTable )
                {
                    WeakReference weakRef = (WeakReference)entry.Value; 
                    Transaction tx = (Transaction)weakRef.Target;
                    if( tx != null ) 
                    { 
                        TransactionEventArgs args = new TransactionEventArgs();
                        args.transaction = tx.InternalClone(); 
                        eventHandler( args.transaction, args );
                    }
                }
            } 
        }
 
 
        internal static void FireDistributedTransactionStarted( Transaction transaction )
        { 
            TransactionStartedEventHandler localStartedEventHandler = null;
            lock( ClassSyncObject )
            {
                localStartedEventHandler = TransactionManager.distributedTransactionStartedDelegate; 
            }
 
            if ( null != localStartedEventHandler ) 
            {
                TransactionEventArgs args = new TransactionEventArgs(); 
                args.transaction = transaction.InternalClone();
                localStartedEventHandler(args.transaction, args);
            }
        } 

 
        // Data storage for current delegate 
        internal static HostCurrentTransactionCallback currentDelegate = null;
        internal static bool currentDelegateSet = false; 

        // CurrentDelegate
        //
        // Store a delegate to be used to query for an external current transaction. 
        public static HostCurrentTransactionCallback HostCurrentCallback
        { 
            // get_HostCurrentCallback is used from get_CurrentTransaction, which doesn't have any permission requirements. 
            // We don't expose what is returned from this property in that case.  But we don't want just anybody being able
            // to retrieve the value. 
            [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
            get
            {
                if( !TransactionManager._platformValidated ) TransactionManager.ValidatePlatform(); 

                // Note do not add trace notifications to this method.  It is called 
                // at the startup of SQLCLR and tracing has too much working set overhead. 
                return currentDelegate;
            } 

            [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
            set
            { 
                if( !TransactionManager._platformValidated ) TransactionManager.ValidatePlatform();
 
                // Note do not add trace notifications to this method.  It is called 
                // at the startup of SQLCLR and tracing has too much working set overhead.
                if( value == null ) 
                {
                    throw new ArgumentNullException( "value" );
                }
 
                lock( ClassSyncObject )
                { 
                    if( currentDelegateSet ) 
                    {
                        throw new InvalidOperationException( SR.GetString( SR.CurrentDelegateSet )); 
                    }
                    currentDelegateSet = true;
                }
 
                currentDelegate = value;
            } 
        } 

 
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
        static public Enlistment Reenlist(
            Guid resourceManagerIdentifier,
            byte[] recoveryInformation, 
            IEnlistmentNotification enlistmentNotification
            ) 
        { 
            if( resourceManagerIdentifier == Guid.Empty )
            { 
                throw new ArgumentException( SR.GetString( SR.BadResourceManagerId ), "resourceManagerIdentifier" );
            }

            if ( null == recoveryInformation ) 
            {
                throw new ArgumentNullException( "recoveryInformation" ); 
            } 

            if ( null == enlistmentNotification ) 
            {
                throw new ArgumentNullException( "enlistmentNotification" );
            }
 
            if( !TransactionManager._platformValidated ) TransactionManager.ValidatePlatform();
 
            if ( DiagnosticTrace.Verbose ) 
            {
                MethodEnteredTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ), 
                    "TransactionManager.Reenlist"
                    );
            }
 
            if ( DiagnosticTrace.Information )
            { 
                ReenlistTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ), 
                    resourceManagerIdentifier
                    ); 
            }

            // Put the recovery information into a stream.
            MemoryStream stream = new MemoryStream( recoveryInformation ); 
            int recoveryInformationVersion = 0;
            string nodeName = null; 
            byte [] resourceManagerRecoveryInformation = null; 

            try 
            {
                BinaryReader reader = new BinaryReader( stream );
                recoveryInformationVersion = reader.ReadInt32();
 
                if( recoveryInformationVersion == TransactionManager.recoveryInformationVersion1 )
                { 
                    nodeName = reader.ReadString(); 

                    resourceManagerRecoveryInformation = reader.ReadBytes( recoveryInformation.Length - checked ((int)stream.Position) ); 
                }
                else
                {
                    if ( DiagnosticTrace.Error ) 
                    {
                        TransactionExceptionTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ), 
                            SR.GetString( SR.UnrecognizedRecoveryInformation ) 
                            );
                    } 
                    throw new ArgumentException( SR.GetString( SR.UnrecognizedRecoveryInformation ), "recoveryInformation" );
                }
            }
            catch( System.IO.EndOfStreamException e ) 
            {
                if ( DiagnosticTrace.Error ) 
                { 
                    TransactionExceptionTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ),
                        SR.GetString( SR.UnrecognizedRecoveryInformation ) 
                        );
                }
                throw new ArgumentException( SR.GetString( SR.UnrecognizedRecoveryInformation ), "recoveryInformation", e);
            } 
            catch( System.FormatException e )
            { 
                if ( DiagnosticTrace.Error ) 
                {
                    TransactionExceptionTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ), 
                        SR.GetString( SR.UnrecognizedRecoveryInformation )
                        );
                }
                throw new ArgumentException( SR.GetString( SR.UnrecognizedRecoveryInformation ), "recoveryInformation", e); 
            }
            finally 
            { 
                stream.Close();
            } 

            Oletx.OletxTransactionManager transactionManager = CheckTransactionManager(nodeName);

            // Now ask the Transaction Manager to reenlist. 
            object syncRoot = new object();
            Enlistment returnValue = new Enlistment( enlistmentNotification, syncRoot ); 
            EnlistmentState._EnlistmentStatePromoted.EnterState( returnValue.InternalEnlistment ); 

            returnValue.InternalEnlistment.PromotedEnlistment = 
                transactionManager.ReenlistTransaction(
                    resourceManagerIdentifier,
                    resourceManagerRecoveryInformation,
                    (RecoveringInternalEnlistment)returnValue.InternalEnlistment 
                    );
 
            if ( DiagnosticTrace.Verbose ) 
            {
                MethodExitedTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ), 
                    "TransactionManager.Reenlist"
                    );
            }
 
            return returnValue;
        } 
 

        private static Oletx.OletxTransactionManager CheckTransactionManager(string nodeName) 
        {
            Oletx.OletxTransactionManager tm = DistributedTransactionManager;
            if( !((tm.NodeName == null && (nodeName == null || nodeName.Length == 0)) ||
                  (tm.NodeName != null && tm.NodeName.Equals(nodeName))) ) 
            {
                throw new ArgumentException( SR.GetString(SR.InvalidRecoveryInformation), "recoveryInformation" ); 
            } 
            return tm;
        } 


        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
        static public void RecoveryComplete( 
            Guid resourceManagerIdentifier
            ) 
        { 
            if( resourceManagerIdentifier == Guid.Empty )
            { 
                throw new ArgumentException( SR.GetString( SR.BadResourceManagerId ), "resourceManagerIdentifier" );
            }

            if ( DiagnosticTrace.Verbose ) 
            {
                MethodEnteredTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ), 
                    "TransactionManager.RecoveryComplete" 
                    );
            } 

            if ( DiagnosticTrace.Information )
            {
                RecoveryCompleteTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ), 
                    resourceManagerIdentifier
                    ); 
            } 

            DistributedTransactionManager.ResourceManagerRecoveryComplete( resourceManagerIdentifier ); 

            if ( DiagnosticTrace.Verbose )
            {
                MethodExitedTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ), 
                    "TransactionManager.RecoveryComplete"
                    ); 
            } 
        }
 

        // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) )
        private static object classSyncObject;
 
        // Helper object for static synchronization
        static object ClassSyncObject 
        { 
            get
            { 
                if( classSyncObject == null )
                {
                    object o = new object();
                    Interlocked.CompareExchange( ref classSyncObject, o, null ); 
                }
                return classSyncObject; 
            } 
        }
 

        internal static System.Transactions.IsolationLevel DefaultIsolationLevel
        {
            get 
            {
                if ( DiagnosticTrace.Verbose ) 
                { 
                    MethodEnteredTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ),
                        "TransactionManager.get_DefaultIsolationLevel" 
                        );
                    MethodExitedTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ),
                        "TransactionManager.get_DefaultIsolationLevel"
                        ); 
                }
 
                return IsolationLevel.Serializable; 
            }
        } 


        static DefaultSettingsSection defaultSettings;
        static DefaultSettingsSection DefaultSettings 
        {
            get 
            { 
                if( defaultSettings == null )
                { 
                    defaultSettings = DefaultSettingsSection.GetSection();
                }

                return defaultSettings; 
            }
        } 
 

        static MachineSettingsSection machineSettings; 
        static MachineSettingsSection MachineSettings
        {
            get
            { 
                if( machineSettings == null )
                { 
                    machineSettings = MachineSettingsSection.GetSection(); 
                }
 
                return machineSettings;
            }
        }
 

        private static bool _defaultTimeoutValidated; 
        private static TimeSpan _defaultTimeout; 
        public static TimeSpan DefaultTimeout
        { 
            get
            {
                if( !TransactionManager._platformValidated ) TransactionManager.ValidatePlatform();
 
                if ( DiagnosticTrace.Verbose )
                { 
                    MethodEnteredTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ), 
                        "TransactionManager.get_DefaultTimeout"
                        ); 
                }

                if( !_defaultTimeoutValidated )
                { 
                    _defaultTimeout = ValidateTimeout( DefaultSettings.Timeout );
                    // If the timeout value got adjusted, it must have been greater than MaximumTimeout. 
                    if ( _defaultTimeout != DefaultSettings.Timeout ) 
                    {
                        if ( DiagnosticTrace.Warning ) 
                        {
                            ConfiguredDefaultTimeoutAdjustedTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ) );
                        }
                    } 
                    _defaultTimeoutValidated = true;
                } 
 
                if ( DiagnosticTrace.Verbose )
                { 
                    MethodExitedTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ),
                        "TransactionManager.get_DefaultTimeout"
                        );
                } 
                return _defaultTimeout;
            } 
        } 

 
        private static bool _cachedMaxTimeout;
        private static TimeSpan _maximumTimeout;
        public static TimeSpan MaximumTimeout
        { 
            get
            { 
                if( !TransactionManager._platformValidated ) TransactionManager.ValidatePlatform(); 

                if( DiagnosticTrace.Verbose ) 
                {
                    MethodEnteredTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ),
                        "TransactionManager.get_DefaultMaximumTimeout"
                        ); 
                }
 
                if( !_cachedMaxTimeout ) 
                {
                    lock( ClassSyncObject ) 
                    {
                        if( !_cachedMaxTimeout )
                        {
                            TimeSpan temp = MachineSettings.MaxTimeout; 
                            Thread.MemoryBarrier();
                            _maximumTimeout = temp; 
                            _cachedMaxTimeout = true; 
                        }
                    } 
                }

                if( DiagnosticTrace.Verbose )
                { 
                    MethodExitedTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ),
                        "TransactionManager.get_DefaultMaximumTimeout" 
                        ); 
                }
 
                return _maximumTimeout;
            }
        }
 

        // This routine writes the "header" for the recovery information, based on the 
        // type of the calling object and its provided parameter collection.  This information 
        // we be read back by the static Reenlist method to create the necessary transaction
        // manager object with the right parameters in order to do a ReenlistTransaction call. 
        internal static byte[] GetRecoveryInformation(
            string startupInfo,
            byte[] resourceManagerRecoveryInformation
            ) 
        {
            if ( DiagnosticTrace.Verbose ) 
            { 
                MethodEnteredTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ),
                    "TransactionManager.GetRecoveryInformation" 
                    );
            }

            MemoryStream stream = new MemoryStream(); 
            byte[] returnValue = null;
 
            try 
            {
                // Manually write the recovery information 
                BinaryWriter writer = new BinaryWriter( stream );

                writer.Write( TransactionManager.currentRecoveryVersion );
                if( startupInfo != null ) 
                {
                    writer.Write( startupInfo ); 
                } 
                else
                { 
                    writer.Write( "" );
                }
                writer.Write( resourceManagerRecoveryInformation );
                writer.Flush(); 
                returnValue = stream.ToArray();
            } 
            finally 
            {
                stream.Close(); 
            }

            if ( DiagnosticTrace.Verbose )
            { 
                MethodExitedTraceRecord.Trace( SR.GetString( SR.TraceSourceBase ),
                    "TransactionManager.GetRecoveryInformation" 
                    ); 
            }
 
            return returnValue;
        }

        internal static byte[] ConvertToByteArray( object thingToConvert ) 
        {
            MemoryStream streamToWrite = new MemoryStream(); 
            byte[] returnValue = null; 

            try 
            {
                // First seralize the type to the stream.
                IFormatter formatter = new BinaryFormatter();
                formatter.Serialize( streamToWrite, thingToConvert ); 

                returnValue = new byte[ streamToWrite.Length ]; 
 
                streamToWrite.Position = 0;
                streamToWrite.Read( returnValue, 0, Convert.ToInt32( streamToWrite.Length, CultureInfo.InvariantCulture ) ); 
            }
            finally
            {
                streamToWrite.Close(); 
            }
 
            return returnValue; 
       }
 
        /// 
        /// This static function throws an ArgumentOutOfRange if the specified IsolationLevel is not within
        /// the range of valid values.
        ///  
        /// 
        /// The IsolationLevel value to validate. 
        ///  
        internal static void ValidateIsolationLevel( IsolationLevel transactionIsolationLevel )
        { 
            switch ( transactionIsolationLevel )
            {
                case IsolationLevel.Serializable:
                case IsolationLevel.RepeatableRead: 
                case IsolationLevel.ReadCommitted:
                case IsolationLevel.ReadUncommitted: 
                case IsolationLevel.Unspecified: 
                case IsolationLevel.Chaos:
                case IsolationLevel.Snapshot: 
                    break;
                default:
                {
                    throw new ArgumentOutOfRangeException( "transactionIsolationLevel" ); 
                }
            } 
        } 

 
        /// 
        /// This static function throws an ArgumentOutOfRange if the specified TimeSpan does not meet
        /// requirements of a valid transaction timeout.  Timeout values must be positive.
        ///  
        /// 
        /// The TimeSpan value to validate. 
        ///  
        internal static TimeSpan ValidateTimeout( TimeSpan transactionTimeout )
        { 
            if ( transactionTimeout < TimeSpan.Zero )
            {
                throw new ArgumentOutOfRangeException( "transactionTimeout" );
            } 

            if ( TransactionManager.MaximumTimeout != TimeSpan.Zero ) 
            { 
                if ( transactionTimeout > TransactionManager.MaximumTimeout || transactionTimeout == TimeSpan.Zero )
                { 
                    return TransactionManager.MaximumTimeout;
                }
            }
 
            return transactionTimeout;
        } 
 

        internal static Transaction FindPromotedTransaction( 
            Guid transactionIdentifier
            )
        {
            Hashtable promotedTransactionTable = PromotedTransactionTable; 
                WeakReference weakRef = (WeakReference) promotedTransactionTable[ transactionIdentifier ];
                if ( null != weakRef ) 
                { 
                Transaction tx = weakRef.Target as Transaction;
                    if ( null != tx ) 
                    {
                        return tx.InternalClone();
                    }
                    else  // an old, moldy weak reference.  Let's get rid of it. 
                    {
                        lock( promotedTransactionTable ) 
                        { 
                            promotedTransactionTable.Remove( transactionIdentifier );
                        } 
                    }
                }

            return null; 
        }
 
 
        internal static Transaction FindOrCreatePromotedTransaction(
            Guid transactionIdentifier, 
            Oletx.OletxTransaction oletx
            )
        {
            Transaction tx = null; 
            Hashtable promotedTransactionTable = PromotedTransactionTable;
            lock(promotedTransactionTable) 
            { 
                WeakReference weakRef = (WeakReference) promotedTransactionTable[ transactionIdentifier ];
                if ( null != weakRef ) 
                {
                    tx = weakRef.Target as Transaction;
                    if ( null != tx )
                    { 
                        // If we found a transaction then dispose the oletx
                        oletx.Dispose(); 
                        return tx.InternalClone(); 
                    }
                    else  // an old, moldy weak reference.  Let's get rid of it. 
                    {
                        lock( promotedTransactionTable )
                        {
                            promotedTransactionTable.Remove( transactionIdentifier ); 
                        }
                    } 
                } 

                tx = new Transaction( oletx ); 

                // Since we are adding this reference to the table create an object that will clean that
                // entry up.
                tx.internalTransaction.finalizedObject = new FinalizedObject( tx.internalTransaction, oletx.Identifier ); 

                weakRef = new WeakReference( tx, false ); 
                promotedTransactionTable[ oletx.Identifier ] = weakRef; 
            }
            oletx.savedLtmPromotedTransaction = tx; 

            TransactionManager.FireDistributedTransactionStarted( tx );

            return tx; 
        }
 
 
        // Table for promoted transactions
        internal static Hashtable PromotedTransactionTable 
        {
            get
            {
                if( promotedTransactionTable == null ) 
                {
                    lock( ClassSyncObject ) 
                    { 
                        if( promotedTransactionTable == null )
                        { 
                            Hashtable temp = new Hashtable( 100 );
                            Thread.MemoryBarrier();
                            promotedTransactionTable = temp;
                        } 
                    }
                } 
 
                return promotedTransactionTable;
            } 
        }


        // Table for transaction timeouts 
        internal static TransactionTable TransactionTable
        { 
            get 
            {
                if( transactionTable == null ) 
                {
                    lock( ClassSyncObject )
                    {
                        if( transactionTable == null ) 
                        {
                            TransactionTable temp = new TransactionTable(); 
                            Thread.MemoryBarrier(); 
                            transactionTable = temp;
                        } 
                    }
                }

                return transactionTable; 
            }
        } 
 

        // Fault in a DistributedTransactionManager if one has not already been created. 
        internal static Oletx.OletxTransactionManager distributedTransactionManager;
        internal static Oletx.OletxTransactionManager DistributedTransactionManager
        {
            get 
            {
                // If the distributed transaction manager is not configured, throw an exception 
                if( distributedTransactionManager == null ) 
                {
                    lock( ClassSyncObject ) 
                    {
                        if( distributedTransactionManager == null )
                        {
                            Oletx.OletxTransactionManager temp = new Oletx.OletxTransactionManager( 
                                DefaultSettings.DistributedTransactionManagerName);
                            Thread.MemoryBarrier(); 
                            distributedTransactionManager = temp; 
                        }
                    } 
                }

                return distributedTransactionManager;
            } 
        }
 
 
        internal static void ValidatePlatform()
        { 
            if ( PlatformID.Win32NT != Environment.OSVersion.Platform )
            {
                throw new PlatformNotSupportedException( SR.GetString( SR.OnlySupportedOnWinNT ) );
            } 

            // Note that this is purposly not synchronized because who cares if there is a ---- to set it. 
            _platformValidated = true; 
        }
 
    }
}

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