Ejemplo n.º 1
0
        internal Task ValidateAndReconnect(Action beforeDisconnect, int timeout)
        {
            Task runningReconnect = _currentReconnectionTask;

            // This loop in the end will return not completed reconnect task or null
            while (runningReconnect != null && runningReconnect.IsCompleted)
            {
                // clean current reconnect task (if it is the same one we checked
                Interlocked.CompareExchange <Task>(ref _currentReconnectionTask, null, runningReconnect);
                // make sure nobody started new task (if which case we did not clean it)
                runningReconnect = _currentReconnectionTask;
            }
            if (runningReconnect == null)
            {
                if (_connectRetryCount > 0)
                {
                    SqlInternalConnectionTds tdsConn = GetOpenTdsConnection();
                    if (tdsConn._sessionRecoveryAcknowledged)
                    {
                        TdsParserStateObject stateObj = tdsConn.Parser._physicalStateObj;
                        if (!stateObj.ValidateSNIConnection())
                        {
                            if (tdsConn.Parser._sessionPool != null)
                            {
                                if (tdsConn.Parser._sessionPool.ActiveSessionsCount > 0)
                                {
                                    // >1 MARS session
                                    if (beforeDisconnect != null)
                                    {
                                        beforeDisconnect();
                                    }
                                    OnError(SQL.CR_UnrecoverableClient(ClientConnectionId), true, null);
                                }
                            }
                            SessionData cData = tdsConn.CurrentSessionData;
                            cData.AssertUnrecoverableStateCountIsCorrect();
                            if (cData._unrecoverableStatesCount == 0)
                            {
                                bool callDisconnect = false;
                                lock (_reconnectLock)
                                {
                                    runningReconnect = _currentReconnectionTask; // double check after obtaining the lock
                                    if (runningReconnect == null)
                                    {
                                        if (cData._unrecoverableStatesCount == 0)
                                        { // could change since the first check, but now is stable since connection is know to be broken
                                            _originalConnectionId = ClientConnectionId;
                                            _recoverySessionData  = cData;
                                            if (beforeDisconnect != null)
                                            {
                                                beforeDisconnect();
                                            }
                                            try
                                            {
                                                _supressStateChangeForReconnection = true;
                                                tdsConn.DoomThisConnection();
                                            }
                                            catch (SqlException)
                                            {
                                            }
                                            runningReconnect = Task.Run(() => ReconnectAsync(timeout));
                                            // if current reconnect is not null, somebody already started reconnection task - some kind of race condition
                                            Debug.Assert(_currentReconnectionTask == null, "Duplicate reconnection tasks detected");
                                            _currentReconnectionTask = runningReconnect;
                                        }
                                    }
                                    else
                                    {
                                        callDisconnect = true;
                                    }
                                }
                                if (callDisconnect && beforeDisconnect != null)
                                {
                                    beforeDisconnect();
                                }
                            }
                            else
                            {
                                if (beforeDisconnect != null)
                                {
                                    beforeDisconnect();
                                }
                                OnError(SQL.CR_UnrecoverableServer(ClientConnectionId), true, null);
                            }
                        } // ValidateSNIConnection
                    }     // sessionRecoverySupported
                }         // connectRetryCount>0
            }
            else
            { // runningReconnect = null
                if (beforeDisconnect != null)
                {
                    beforeDisconnect();
                }
            }
            return(runningReconnect);
        }
Ejemplo n.º 2
0
        internal Task ValidateAndReconnect(Action beforeDisconnect, int timeout)
        {
            Task runningReconnect = _currentReconnectionTask;

            // This loop in the end will return not completed reconnect task or null
            while (runningReconnect != null && runningReconnect.IsCompleted)
            {
                // clean current reconnect task (if it is the same one we checked
                Interlocked.CompareExchange <Task>(ref _currentReconnectionTask, null, runningReconnect);
                // make sure nobody started new task (if which case we did not clean it)
                runningReconnect = _currentReconnectionTask;
            }
            if (runningReconnect == null)
            {
                if (_connectRetryCount > 0)
                {
                    SqlInternalConnectionTds tdsConn = GetOpenTdsConnection();
                    if (tdsConn._sessionRecoveryAcknowledged)
                    {
                        TdsParser tdsParser = tdsConn.Parser;
                        if (!tdsParser._physicalStateObj.ValidateSNIConnection())
                        {
                            if ((tdsParser._sessionPool != null) && (tdsParser._sessionPool.ActiveSessionsCount > 0))
                            {
                                // >1 MARS session
                                beforeDisconnect?.Invoke();
                                OnError(SQL.CR_UnrecoverableClient(ClientConnectionId), true, null);
                            }

                            SessionData cData = tdsConn.CurrentSessionData;
                            cData.AssertUnrecoverableStateCountIsCorrect();
                            if (cData._unrecoverableStatesCount == 0)
                            {
                                TaskCompletionSource <object> reconnectCompletionSource = new TaskCompletionSource <object>();
                                runningReconnect = Interlocked.CompareExchange(ref _currentReconnectionTask, reconnectCompletionSource.Task, null);
                                if (runningReconnect == null)
                                {
                                    if (cData._unrecoverableStatesCount == 0)
                                    { // could change since the first check, but now is stable since connection is know to be broken
                                        _originalConnectionId = ClientConnectionId;
                                        _recoverySessionData  = cData;
                                        beforeDisconnect?.Invoke();
                                        try
                                        {
                                            _supressStateChangeForReconnection = true;
                                            tdsConn.DoomThisConnection();
                                        }
                                        catch (SqlException)
                                        {
                                        }
                                        Task.Run(() => ReconnectAsync(timeout).ContinueWith(t => {
                                            if (t.IsFaulted)
                                            {
                                                reconnectCompletionSource.SetException(t.Exception);
                                            }
                                            else if (t.IsCanceled)
                                            {
                                                reconnectCompletionSource.SetCanceled();
                                            }
                                            else
                                            {
                                                reconnectCompletionSource.SetResult(null);
                                            }
                                        }));
                                        runningReconnect = reconnectCompletionSource.Task;
                                    }
                                }
                                else
                                {
                                    beforeDisconnect?.Invoke();
                                }
                            }
                            else
                            {
                                beforeDisconnect?.Invoke();
                                OnError(SQL.CR_UnrecoverableServer(ClientConnectionId), true, null);
                            }
                        } // ValidateSNIConnection
                    }     // sessionRecoverySupported
                }         // connectRetryCount>0
            }
            else
            { // runningReconnect = null
                beforeDisconnect?.Invoke();
            }
            return(runningReconnect);
        }