SqlCommandAsyncResult.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.Activities.DurableInstancing / System / Activities / DurableInstancing / SqlCommandAsyncResult.cs / 1610140 / SqlCommandAsyncResult.cs

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

namespace System.Activities.DurableInstancing 
{
    using System.Data; 
    using System.Data.SqlClient; 
    using System.Globalization;
    using System.Linq; 
    using System.Runtime;
    using System.Transactions;

    sealed class SqlCommandAsyncResult : AsyncResult 
    {
 
        static readonly TimeSpan MaximumOpenTimeout = TimeSpan.FromMinutes(2); 

        static readonly RetryErrorCode[] retryErrorCodes = 
            {
                new RetryErrorCode(-2, RetryErrorOptions.RetryBeginOrEnd | RetryErrorOptions.RetryWhenTransaction), // SqlError: Timeout
                new RetryErrorCode(53, RetryErrorOptions.RetryBeginOrEnd | RetryErrorOptions.RetryWhenTransaction), //A network-related or instance-specific error occurred while establishing a connection to SQL Server.
                new RetryErrorCode(64, RetryErrorOptions.RetryBeginOrEnd | RetryErrorOptions.RetryWhenTransaction), //A transport-level error has occurred when receiving results from the server (TCP Provider, error: 0 - The specified network name is no longer available). 
                new RetryErrorCode(121, RetryErrorOptions.RetryBeginOrEnd), //  A transport-level error has occurred
                new RetryErrorCode(1205, RetryErrorOptions.RetryBeginOrEnd), // Deadlock 
                new RetryErrorCode(1222, RetryErrorOptions.RetryBeginOrEnd | RetryErrorOptions.RetryWhenTransaction), // Lock Request Timeout 
                new RetryErrorCode(3910, RetryErrorOptions.RetryOnBegin | RetryErrorOptions.RetryWhenTransaction), // Transaction context in use by another session.
                new RetryErrorCode(8645, RetryErrorOptions.RetryBeginOrEnd | RetryErrorOptions.RetryWhenTransaction), // A timeout occurred while waiting for memory resources 
                new RetryErrorCode(8641, RetryErrorOptions.RetryBeginOrEnd | RetryErrorOptions.RetryWhenTransaction), // Could not perform the operation because the requested memory grant was not available
                new RetryErrorCode(10054, RetryErrorOptions.RetryBeginOrEnd | RetryErrorOptions.RetryWhenTransaction), // Severed tcp connection drawn from the pool
                new RetryErrorCode(233, RetryErrorOptions.RetryBeginOrEnd | RetryErrorOptions.RetryWhenTransaction) // Severed shared memory/named pipe connection drawn from the pool
            }; 
        const int maximumRetries = 4;
        static AsyncCompletion onExecuteReaderCallback = new AsyncCompletion(OnExecuteReader); 
        static AsyncCompletion onRetryCommandCallback = new AsyncCompletion(OnRetryCommand); 
        string connectionString;
        DependentTransaction dependentTransaction; 
        int retryCount;

        SqlCommand sqlCommand;
        SqlDataReader sqlDataReader; 
        TimeoutHelper timeoutHelper;
 
        public SqlCommandAsyncResult(SqlCommand sqlCommand, string connectionString, DependentTransaction dependentTransaction, 
            TimeSpan timeout, int retryCount, AsyncCallback callback, object state)
            : base(callback, state) 
        {
            long openTimeout = Math.Min(timeout.Ticks, SqlCommandAsyncResult.MaximumOpenTimeout.Ticks);
            this.sqlCommand = sqlCommand;
            this.connectionString = connectionString; 
            this.dependentTransaction = dependentTransaction;
            this.timeoutHelper = new TimeoutHelper(TimeSpan.FromTicks(openTimeout)); 
            this.retryCount = retryCount; 
        }
 
        [Flags]
        enum RetryErrorOptions
        {
            RetryOnBegin = 1, 
            RetryOnEnd = 2,
            RetryWhenTransaction = 4, 
            RetryBeginOrEnd = RetryOnBegin | RetryOnEnd 
        }
 
        public static SqlDataReader End(IAsyncResult result)
        {
            SqlCommandAsyncResult SqlCommandAsyncResult = AsyncResult.End(result);
            return SqlCommandAsyncResult.sqlDataReader; 
        }
 
        public void StartCommand() 
        {
            StartCommandInternal(true); 
        }

        static bool OnExecuteReader(IAsyncResult result)
        { 
            SqlCommandAsyncResult thisPtr = (SqlCommandAsyncResult)(result.AsyncState);
            return thisPtr.CompleteExecuteReader(result); 
        } 

        static bool OnRetryCommand(IAsyncResult childPtr) 
        {
            SqlCommandAsyncResult parentPtr = (SqlCommandAsyncResult)(childPtr.AsyncState);
            parentPtr.sqlDataReader = SqlCommandAsyncResult.End(childPtr);
            return true; 
        }
 
        static bool ShouldRetryForSqlError(int error, RetryErrorOptions retryErrorOptions) 
        {
            if (Transaction.Current != null) 
            {
                retryErrorOptions |= RetryErrorOptions.RetryWhenTransaction;
            }
            return SqlCommandAsyncResult.retryErrorCodes.Any(x => x.ErrorCode == error && (x.RetryErrorOptions & retryErrorOptions) == retryErrorOptions); 
        }
 
        static void StartCommandCallback(object state) 
        {
            SqlCommandAsyncResult thisPtr = (SqlCommandAsyncResult) state; 
            try
            {
                // this can throw on the [....] path - we need to signal the callback
                thisPtr.StartCommandInternal(false); 
            }
            catch (Exception e) 
            { 
                if (Fx.IsFatal(e))
                { 
                    throw;
                }

                if (thisPtr.sqlCommand.Connection != null) 
                {
                    thisPtr.sqlCommand.Connection.Close(); 
                } 

                thisPtr.Complete(false, e); 
            }
        }
        bool CheckRetryCount()
        { 
            return (++this.retryCount < maximumRetries);
        } 
 
        bool CheckRetryCountAndTimer()
        { 
            return (this.CheckRetryCount() && !this.HasOperationTimedOut());
        }

        bool CompleteExecuteReader(IAsyncResult result) 
        {
            bool completeSelf = true; 
 
            try
            { 
                this.sqlDataReader = this.sqlCommand.EndExecuteReader(result);
            }
            catch (SqlException exception)
            { 
                if (TD.SqlExceptionCaughtIsEnabled())
                { 
                    TD.SqlExceptionCaught(exception.Number.ToString(CultureInfo.InvariantCulture), exception.Message); 
                }
 
                if (this.sqlDataReader != null)
                {
                    this.sqlDataReader.Close();
                } 

                if (this.sqlCommand.Connection != null) 
                { 
                    this.sqlCommand.Connection.Close();
                } 

                // If we completed [....] then any retry is done by the original caller.
                if (!result.CompletedSynchronously)
                { 
                    if (this.CheckRetryCountAndTimer() && ShouldRetryForSqlError(exception.Number, RetryErrorOptions.RetryOnEnd))
                    { 
                        if (this.EnqueueRetry()) 
                        {
                            if (TD.RetryingSqlCommandDueToSqlErrorIsEnabled()) 
                            {
                                TD.RetryingSqlCommandDueToSqlError(exception.Number.ToString(CultureInfo.InvariantCulture));
                            }
                            completeSelf = false; 
                        }
                    } 
                } 

                if (completeSelf) 
                {
                    if (this.retryCount == maximumRetries && TD.MaximumRetriesExceededForSqlCommandIsEnabled())
                    {
                        TD.MaximumRetriesExceededForSqlCommand(); 
                    }
 
                    throw; 
                }
            } 

            return completeSelf;
        }
 
        bool EnqueueRetry()
        { 
            bool result = false; 

            int delay = this.GetRetryDelay(); 

            if (this.timeoutHelper.RemainingTime().TotalMilliseconds > delay)
            {
                this.sqlCommand.Dispose(); 
                IOThreadTimer iott = new IOThreadTimer(StartCommandCallback, new SqlCommandAsyncResult(CloneSqlCommand(this.sqlCommand), this.connectionString, this.dependentTransaction,
                    this.timeoutHelper.RemainingTime(), this.retryCount, this.PrepareAsyncCompletion(onRetryCommandCallback), this), false); 
                iott.Set(delay); 

                if (TD.QueingSqlRetryIsEnabled()) 
                {
                    TD.QueingSqlRetry(delay.ToString(CultureInfo.InvariantCulture));
                }
 
                result = true;
            } 
 
            return result;
        } 

        static SqlCommand CloneSqlCommand(SqlCommand command)
        {
            //We do not want to use SqlCommand.Clone here because we do not want to replicate the parameters 
            SqlCommand newCommand = new SqlCommand()
            { 
                CommandType = command.CommandType, 
                CommandText = command.CommandText,
            }; 

            SqlParameter[] tempParameterList = new SqlParameter[command.Parameters.Count];
            for (int i = 0; i < command.Parameters.Count; i++)
            { 
                tempParameterList[i] = command.Parameters[i];
            } 
            command.Parameters.Clear(); 
            newCommand.Parameters.AddRange(tempParameterList);
 
            return newCommand;
        }

        int GetRetryDelay() 
        {
            return 1000; 
        } 

        bool HasOperationTimedOut() 
        {
            return (this.timeoutHelper.RemainingTime() <= TimeSpan.Zero);
        }
 
        void StartCommandInternal(bool synchronous)
        { 
            if (!this.HasOperationTimedOut()) 
            {
                try 
                {
                    IAsyncResult result;

                    using (this.PrepareTransactionalCall(this.dependentTransaction)) 
                    {
                        AsyncCallback wrappedCallback = this.PrepareAsyncCompletion(onExecuteReaderCallback); 
                        this.sqlCommand.Connection = StoreUtilities.CreateConnection(this.connectionString); 
                        if (!this.HasOperationTimedOut())
                        { 
                            result = this.sqlCommand.BeginExecuteReader(wrappedCallback, this, CommandBehavior.CloseConnection);
                        }
                        else
                        { 
                            this.sqlCommand.Connection.Close();
                            this.Complete(synchronous, new TimeoutException(SR.TimeoutOnSqlOperation(this.timeoutHelper.OriginalTimeout.ToString()))); 
                            return; 
                        }
                    } 

                    if (this.CheckSyncContinue(result))
                    {
                        if (this.CompleteExecuteReader(result)) 
                        {
                            this.Complete(synchronous); 
                        } 
                    }
                    return; 
                }
                catch (SqlException exception)
                {
                    if (TD.SqlExceptionCaughtIsEnabled()) 
                    {
                        TD.SqlExceptionCaught(exception.Number.ToString(CultureInfo.InvariantCulture), exception.Message); 
                    } 

                    if (this.sqlCommand.Connection != null) 
                    {
                        this.sqlCommand.Connection.Close();
                    }
 
                    if (!this.CheckRetryCount() || !ShouldRetryForSqlError(exception.Number, RetryErrorOptions.RetryOnBegin))
                    { 
                        throw; 
                    }
 
                    if (TD.RetryingSqlCommandDueToSqlErrorIsEnabled())
                    {
                        TD.RetryingSqlCommandDueToSqlError(exception.Number.ToString(CultureInfo.InvariantCulture));
                    } 
                }
                catch (InvalidOperationException) 
                { 
                    if (!this.CheckRetryCount())
                    { 
                        throw;
                    }
                }
 
                if (this.EnqueueRetry())
                { 
                    return; 
                }
            } 

            if (this.HasOperationTimedOut())
            {
                if (TD.TimeoutOpeningSqlConnectionIsEnabled()) 
                {
                    TD.TimeoutOpeningSqlConnection(this.timeoutHelper.OriginalTimeout.ToString()); 
                } 
            }
            else 
            {
                if (TD.MaximumRetriesExceededForSqlCommandIsEnabled())
                {
                    TD.MaximumRetriesExceededForSqlCommand(); 
                }
            } 
 
            this.Complete(synchronous, new TimeoutException(SR.TimeoutOnSqlOperation(this.timeoutHelper.OriginalTimeout.ToString())));
        } 

        class RetryErrorCode
        {
            public RetryErrorCode(int code, RetryErrorOptions retryErrorOptions) 
            {
                this.ErrorCode = code; 
                this.RetryErrorOptions = retryErrorOptions; 
            }
 
            public int ErrorCode
            {
                get;
                private set; 
            }
 
            public RetryErrorOptions RetryErrorOptions 
            {
                get; 
                private set;
            }
        }
    } 
}

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