private bool ProcessReadBytes(int bytesRead)
        {
            if (bytesRead <= 0)
            {
                Multiplexer.Trace("EOF", physicalName);
                RecordConnectionFailed(ConnectionFailureType.SocketClosed);
                return(false);
            }

            Interlocked.Exchange(ref lastReadTickCount, Environment.TickCount);

            // reset unanswered write timestamp
            VolatileWrapper.Write(ref firstUnansweredWriteTickCount, 0);

            ioBufferBytes += bytesRead;
            Multiplexer.Trace("More bytes available: " + bytesRead + " (" + ioBufferBytes + ")", physicalName);
            int offset = 0, count = ioBufferBytes;
            int handled = ProcessBuffer(ioBuffer, ref offset, ref count);

            Multiplexer.Trace("Processed: " + handled, physicalName);
            if (handled != 0)
            {
                // read stuff
                if (count != 0)
                {
                    Multiplexer.Trace("Copying remaining bytes: " + count, physicalName);
                    //  if anything was left over, we need to copy it to
                    // the start of the buffer so it can be used next time
                    Buffer.BlockCopy(ioBuffer, offset, ioBuffer, 0, count);
                }
                ioBufferBytes = count;
            }
            return(true);
        }
        public void BeginConnect(TextWriter log)
        {
            VolatileWrapper.Write(ref firstUnansweredWriteTickCount, 0);
            var endpoint = this.Bridge.ServerEndPoint.EndPoint;

            Multiplexer.Trace("Connecting...", physicalName);
            this.socketToken = Multiplexer.SocketManager.BeginConnect(endpoint, this, Multiplexer, log);
        }
        public void CheckForStaleConnection(ref SocketManager.ManagerState managerState)
        {
            int firstUnansweredWrite = VolatileWrapper.Read(ref firstUnansweredWriteTickCount);

            DebugEmulateStaleConnection(ref firstUnansweredWrite);

            int now = Environment.TickCount;

            if (firstUnansweredWrite != 0 && (now - firstUnansweredWrite) > this.Multiplexer.RawConfig.ResponseTimeout)
            {
                this.RecordConnectionFailed(ConnectionFailureType.SocketFailure, ref managerState, origin: "CheckForStaleConnection");
            }
        }
        public void RecordConnectionFailed(ConnectionFailureType failureType, ref SocketManager.ManagerState managerState, Exception innerException = null, [CallerMemberName] string origin = null)
        {
            IdentifyFailureType(innerException, ref failureType);

            managerState = SocketManager.ManagerState.RecordConnectionFailed_OnInternalError;
            if (failureType == ConnectionFailureType.InternalFailure)
            {
                OnInternalError(innerException, origin);
            }

            // stop anything new coming in...
            Bridge.Trace("Failed: " + failureType);
            bool isCurrent;

            PhysicalBridge.State oldState;
            int @in = -1, ar = -1;

            managerState = SocketManager.ManagerState.RecordConnectionFailed_OnDisconnected;
            Bridge.OnDisconnected(failureType, this, out isCurrent, out oldState);
            if (oldState == PhysicalBridge.State.ConnectedEstablished)
            {
                try
                {
                    @in = GetAvailableInboundBytes(out ar);
                }
                catch { /* best effort only */ }
            }

            if (isCurrent && Interlocked.CompareExchange(ref failureReported, 1, 0) == 0)
            {
                managerState = SocketManager.ManagerState.RecordConnectionFailed_ReportFailure;
                int now = Environment.TickCount, lastRead = VolatileWrapper.Read(ref lastReadTickCount), lastWrite = VolatileWrapper.Read(ref lastWriteTickCount),
                    lastBeat       = VolatileWrapper.Read(ref lastBeatTickCount);
                int unansweredRead = VolatileWrapper.Read(ref firstUnansweredWriteTickCount);

                var exMessage = new StringBuilder(failureType + " on " + Format.ToString(Bridge.ServerEndPoint.EndPoint) + "/" + connectionType);
                var data      = new List <Tuple <string, string> >
                {
                    Tuple.Create("FailureType", failureType.ToString()),
                    Tuple.Create("EndPoint", Format.ToString(Bridge.ServerEndPoint.EndPoint))
                };
                Action <string, string, string> add = (lk, sk, v) =>
                {
                    data.Add(Tuple.Create(lk, v));
                    exMessage.Append(", " + sk + ": " + v);
                };

                add("Origin", "origin", origin);
                add("Input-Buffer", "input-buffer", ioBufferBytes.ToString());
                add("Outstanding-Responses", "outstanding", GetSentAwaitingResponseCount().ToString());
                add("Last-Read", "last-read", unchecked (now - lastRead) / 1000 + "s ago");
                add("Last-Write", "last-write", unchecked (now - lastWrite) / 1000 + "s ago");
                add("Unanswered-Write", "unanswered-write", unchecked (now - unansweredRead) / 1000 + "s ago");
                add("Keep-Alive", "keep-alive", Bridge.ServerEndPoint.WriteEverySeconds + "s");
                add("Pending", "pending", Bridge.GetPendingCount().ToString());
                add("Previous-Physical-State", "state", oldState.ToString());

                if (@in >= 0)
                {
                    add("Inbound-Bytes", "in", @in.ToString());
                    add("Active-Readers", "ar", ar.ToString());
                }

                add("Last-Heartbeat", "last-heartbeat", (lastBeat == 0 ? "never" : (unchecked (now - lastBeat) / 1000 + "s ago")) + (Bridge.IsBeating ? " (mid-beat)" : ""));
                add("Last-Multiplexer-Heartbeat", "last-mbeat", Multiplexer.LastHeartbeatSecondsAgo + "s ago");
                add("Last-Global-Heartbeat", "global", ConnectionMultiplexer.LastGlobalHeartbeatSecondsAgo + "s ago");
#if FEATURE_SOCKET_MODE_POLL
                var mgr = Bridge.Multiplexer.SocketManager;
                add("SocketManager-State", "mgr", mgr.State.ToString());
                add("Last-Error", "err", mgr.LastErrorTimeRelative());
#endif

                var ex = innerException == null
                    ? new RedisConnectionException(failureType, exMessage.ToString())
                    : new RedisConnectionException(failureType, exMessage.ToString(), innerException);

                foreach (var kv in data)
                {
                    ex.Data["Redis-" + kv.Item1] = kv.Item2;
                }

                managerState = SocketManager.ManagerState.RecordConnectionFailed_OnConnectionFailed;
                Bridge.OnConnectionFailed(this, failureType, ex);
            }

            // cleanup
            managerState = SocketManager.ManagerState.RecordConnectionFailed_FailOutstanding;
            lock (outstanding)
            {
                Bridge.Trace(outstanding.Count != 0, "Failing outstanding messages: " + outstanding.Count);
                while (outstanding.Count != 0)
                {
                    var next = outstanding.Dequeue();
                    Bridge.Trace("Failing: " + next);
                    next.Fail(failureType, innerException);
                    Bridge.CompleteSyncOrAsync(next);
                }
            }

            // burn the socket
            managerState = SocketManager.ManagerState.RecordConnectionFailed_ShutdownSocket;
            Multiplexer.SocketManager?.Shutdown(socketToken);
        }
        internal void OnHeartbeat(bool ifConnectedOnly)
        {
            bool runThisTime = false;

            try
            {
                runThisTime = !isDisposed && Interlocked.CompareExchange(ref beating, 1, 0) == 0;
                if (!runThisTime)
                {
                    return;
                }

                uint index          = (uint)Interlocked.Increment(ref profileLogIndex);
                long newSampleCount = Interlocked.Read(ref operationCount);
                Interlocked.Exchange(ref profileLog[index % ProfileLogSamples], newSampleCount);
                Interlocked.Exchange(ref profileLastLog, newSampleCount);
                Trace("OnHeartbeat: " + (State)state);
                switch (state)
                {
                case (int)State.Connecting:
                    int connectTimeMilliseconds = unchecked (Environment.TickCount - VolatileWrapper.Read(ref connectStartTicks));
                    if (connectTimeMilliseconds >= Multiplexer.RawConfig.ConnectTimeout)
                    {
                        LastException = ExceptionFactory.UnableToConnect("ConnectTimeout");
                        Trace("Aborting connect");
                        // abort and reconnect
                        var   snapshot = physical;
                        bool  isCurrent;
                        State oldState;
                        OnDisconnected(ConnectionFailureType.UnableToConnect, snapshot, out isCurrent, out oldState);
                        using (snapshot) { }     // dispose etc
                        TryConnect(null);
                    }
                    if (!ifConnectedOnly)
                    {
                        AbortUnsent();
                    }
                    break;

                case (int)State.ConnectedEstablishing:
                case (int)State.ConnectedEstablished:
                    var tmp = physical;
                    if (tmp != null)
                    {
                        if (state == (int)State.ConnectedEstablished)
                        {
                            tmp.Bridge.ServerEndPoint.ClearUnselectable(UnselectableFlags.DidNotRespond);
                        }
                        tmp.OnHeartbeat();
                        int writeEverySeconds  = ServerEndPoint.WriteEverySeconds,
                            checkConfigSeconds = Multiplexer.RawConfig.ConfigCheckSeconds;

                        if (state == (int)State.ConnectedEstablished && ConnectionType == ConnectionType.Interactive &&
                            checkConfigSeconds > 0 && ServerEndPoint.LastInfoReplicationCheckSecondsAgo >= checkConfigSeconds &&
                            ServerEndPoint.CheckInfoReplication())
                        {
                            // that serves as a keep-alive, if it is accepted
                        }
                        else if (writeEverySeconds > 0 && tmp.LastWriteSecondsAgo >= writeEverySeconds)
                        {
                            Trace("OnHeartbeat - overdue");
                            if (state == (int)State.ConnectedEstablished)
                            {
                                KeepAlive();
                            }
                            else
                            {
                                bool  ignore;
                                State oldState;
                                OnDisconnected(ConnectionFailureType.SocketFailure, tmp, out ignore, out oldState);
                            }
                        }
                        else if (!queue.Any() && tmp.GetSentAwaitingResponseCount() != 0)
                        {
                            // there's a chance this is a dead socket; sending data will shake that
                            // up a bit, so if we have an empty unsent queue and a non-empty sent
                            // queue, test the socket
                            KeepAlive();
                        }
                    }
                    break;

                case (int)State.Disconnected:
                    if (!ifConnectedOnly)
                    {
                        AbortUnsent();
                        Multiplexer.Trace("Resurrecting " + this.ToString());
                        GetConnection(null);
                    }
                    break;

                default:
                    if (!ifConnectedOnly)
                    {
                        AbortUnsent();
                    }
                    break;
                }
            }
            catch (Exception ex)
            {
                OnInternalError(ex);
                Trace("OnHeartbeat error: " + ex.Message);
            }
            finally
            {
                if (runThisTime)
                {
                    Interlocked.Exchange(ref beating, 0);
                }
            }
        }