// internally, this is very similar to RawResult, except it is designed to be usable
        // outside of the IO-processing pipeline: the buffers are standalone, etc

        internal static RedisResult TryCreate(PhysicalConnection connection, RawResult result)
        {
            try
            {
                switch (result.Type)
                {
                    case ResultType.Integer:
                    case ResultType.SimpleString:
                    case ResultType.BulkString:
                        return new SingleRedisResult(result.AsRedisValue());
                    case ResultType.MultiBulk:
                        var items = result.GetItems();
                        var arr = new RedisResult[items.Length];
                        for (int i = 0; i < arr.Length; i++)
                        {
                            var next = TryCreate(connection, items[i]);
                            if (next == null) return null; // means we didn't understand
                            arr[i] = next;
                        }
                        return new ArrayRedisResult(arr);
                    case ResultType.Error:
                        return new ErrorRedisResult(result.GetString());
                    default:
                        return null;
                }
            } catch(Exception ex)
            {
                connection?.OnInternalError(ex);
                return null; // will be logged as a protocol fail by the processor
            }
        }
Пример #2
0
        private bool WriteMessageToServer(PhysicalConnection connection, Message message)
        {
            if (message == null) return true;

            try
            {
                var cmd = message.Command;
                bool isMasterOnly = message.IsMasterOnly();
                if (isMasterOnly && serverEndPoint.IsSlave && (serverEndPoint.SlaveReadOnly || !serverEndPoint.AllowSlaveWrites))
                {
                    throw ExceptionFactory.MasterOnly(multiplexer.IncludeDetailInExceptions, message.Command, message, ServerEndPoint);
                }

                SelectDatabase(connection, message);

                if (!connection.TransactionActive)
                {
                    var readmode = connection.GetReadModeCommand(isMasterOnly);
                    if (readmode != null)
                    {
                        connection.Enqueue(readmode);
                        readmode.WriteTo(connection);
                        readmode.SetRequestSent();
                        IncrementOpCount();
                    }

                    if (message.IsAsking)
                    {
                        var asking = ReusableAskingCommand;
                        connection.Enqueue(asking);
                        asking.WriteImpl(connection);
                        asking.SetRequestSent();
                        IncrementOpCount();
                    }
                }
                switch (cmd)
                {
                    case RedisCommand.WATCH:
                    case RedisCommand.MULTI:
                        connection.TransactionActive = true;
                        break;
                    case RedisCommand.UNWATCH:
                    case RedisCommand.EXEC:
                    case RedisCommand.DISCARD:
                        connection.TransactionActive = false;
                        break;
                }

                connection.Enqueue(message);
                message.WriteImpl(connection);
                message.SetRequestSent();
                IncrementOpCount();

                // some commands smash our ability to trust the database; some commands
                // demand an immediate flush
                switch (cmd)
                {
                    case RedisCommand.EVAL:
                    case RedisCommand.EVALSHA:
                        if(!serverEndPoint.GetFeatures().ScriptingDatabaseSafe)
                        {
                            connection.SetUnknownDatabase();
                        }
                        break;
                    case RedisCommand.DISCARD:
                    case RedisCommand.EXEC:
                        connection.SetUnknownDatabase();
                        break;
                }
                return true;
            }
            catch (RedisCommandException ex)
            {
                Trace("Write failed: " + ex.Message);
                message.Fail(ConnectionFailureType.ProtocolFailure, ex);
                CompleteSyncOrAsync(message);
                // this failed without actually writing; we're OK with that... unless there's a transaction

                if (connection != null && connection.TransactionActive)
                {
                    // we left it in a broken state; need to kill the connection
                    connection.RecordConnectionFailed(ConnectionFailureType.ProtocolFailure, ex);
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                Trace("Write failed: " + ex.Message);
                message.Fail(ConnectionFailureType.InternalFailure, ex);
                CompleteSyncOrAsync(message);

                // we're not sure *what* happened here; probably an IOException; kill the connection
                if(connection != null) connection.RecordConnectionFailed(ConnectionFailureType.InternalFailure, ex);
                return false;
            }
        }
Пример #3
0
 private void SelectDatabase(PhysicalConnection connection, Message message)
 {
     int db = message.Db;
     if (db >= 0)
     {
         var sel = connection.GetSelectDatabaseCommand(db, message);
         if (sel != null)
         {
             connection.Enqueue(sel);
             sel.WriteImpl(connection);
             sel.SetRequestSent();
             IncrementOpCount();
         }
     }
 }
Пример #4
0
 private PhysicalConnection GetConnection(TextWriter log)
 {
     if (state == (int)State.Disconnected)
     {
         try
         {
             if (!multiplexer.IsDisposed)
             {
                 Multiplexer.LogLocked(log, "Connecting {0}...", Name);
                 Multiplexer.Trace("Connecting...", Name);
                 if (ChangeState(State.Disconnected, State.Connecting))
                 {
                     Interlocked.Increment(ref socketCount);
                     Interlocked.Exchange(ref connectStartTicks, Environment.TickCount);
                     // separate creation and connection for case when connection completes synchronously
                     // in that case PhysicalConnection will call back to PhysicalBridge, and most of  PhysicalBridge methods assumes that physical is not null;
                     physical = new PhysicalConnection(this);
                     physical.BeginConnect(log);
                 }
             }
             return null;
         }
         catch (Exception ex)
         {
             Multiplexer.LogLocked(log, "Connect {0} failed: {1}", Name, ex.Message);
             Multiplexer.Trace("Connect failed: " + ex.Message, Name);
             ChangeState(State.Disconnected);
             OnInternalError(ex);
             throw;
         }
     }
     return physical;
 }
Пример #5
0
        /// <summary>
        /// This writes a message **directly** to the output stream; note
        /// that this ignores the queue, so should only be used *either*
        /// from the regular dequeue loop, *or* from the "I've just
        /// connected" handshake (when there is no dequeue loop) - otherwise,
        /// you can pretty much assume you're going to destroy the stream
        /// </summary>
        internal bool WriteMessageDirect(PhysicalConnection tmp, Message next)
        {
            Trace("Writing: " + next);
            if (next is IMultiMessage)
            {
                SelectDatabase(tmp, next); // need to switch database *before* the transaction
                foreach (var subCommand in ((IMultiMessage)next).GetMessages(tmp))
                {
                    if (!WriteMessageToServer(tmp, subCommand))
                    {
                        // we screwed up; abort; note that WriteMessageToServer already
                        // killed the underlying connection
                        Trace("Unable to write to server");
                        next.Fail(ConnectionFailureType.ProtocolFailure, null);
                        CompleteSyncOrAsync(next);
                        return false;
                    }
                }

                next.SetRequestSent();

                return true;
            }
            else
            {
                return WriteMessageToServer(tmp, next);
            }
        }
Пример #6
0
        internal void RemovePhysical(PhysicalConnection connection)
        {
#pragma warning disable 0420
            Interlocked.CompareExchange(ref physical, null, connection);
#pragma warning restore 0420
        }
Пример #7
0
 internal void OnFullyEstablished(PhysicalConnection connection)
 {
     Trace("OnFullyEstablished");
     if (physical == connection && !isDisposed && ChangeState(State.ConnectedEstablishing, State.ConnectedEstablished))
     {
         reportNextFailure = reconfigureNextFailure = true;
         Interlocked.Exchange(ref failConnectCount, 0);
         serverEndPoint.OnFullyEstablished(connection);
         multiplexer.RequestWrite(this, true);
         if(connectionType == ConnectionType.Interactive) serverEndPoint.CheckInfoReplication();
     }
     else
     {
         try { connection.Dispose(); } catch { }
     }
 }
Пример #8
0
        internal void OnDisconnected(ConnectionFailureType failureType, PhysicalConnection connection, out bool isCurrent, out State oldState)
        {
            Trace("OnDisconnected");

            // if the next thing in the pipe is a PING, we can tell it that we failed (this really helps spot doomed connects)
            // note that for simplicity we haven't removed it from the queue; that's OK
            int count;
            var ping = queue.PeekPing(out count);
            if (ping != null)
            {
                Trace("Marking PING as failed (queue length: " + count + ")");
                ping.Fail(failureType, null);
                CompleteSyncOrAsync(ping);
            }
            oldState = default(State); // only defined when isCurrent = true
            if (isCurrent = (physical == connection))
            {
                Trace("Bridge noting disconnect from active connection" + (isDisposed ? " (disposed)" : ""));
                oldState = ChangeState(State.Disconnected);
                physical = null;

                if (!isDisposed && Interlocked.Increment(ref failConnectCount) == 1)
                {
                    GetConnection(null); // try to connect immediately
                }
            }
            else if (physical == null)
            {
                Trace("Bridge noting disconnect (already terminated)");
            }
            else
            {
                Trace("Bridge noting disconnect, but from different connection");
            }
        }
Пример #9
0
 internal void OnConnectionFailed(PhysicalConnection connection, ConnectionFailureType failureType, Exception innerException)
 {
     if (reportNextFailure)
     {
         reportNextFailure = false; // until it is restored
         var endpoint = serverEndPoint.EndPoint;
         multiplexer.OnConnectionFailed(endpoint, connectionType, failureType, innerException, reconfigureNextFailure);
     }
 }
Пример #10
0
 internal void OnConnected(PhysicalConnection connection, TextWriter log)
 {
     Trace("OnConnected");
     if (physical == connection && !isDisposed && ChangeState(State.Connecting, State.ConnectedEstablishing))
     {
         serverEndPoint.OnEstablishing(connection, log);
     }
     else
     {
         try
         {
             connection.Dispose();
         }
         catch
         { }
     }
 }
Пример #11
0
 public void Dispose()
 {
     isDisposed = true;
     using (var tmp = physical)
     {
         physical = null;
     }
 }
 private PhysicalConnection GetConnection()
 {
     if (state == (int)State.Disconnected)
     {
         try
         {
             if (!multiplexer.IsDisposed)
             {
                 Multiplexer.Trace("Connecting...", Name);
                 if (ChangeState(State.Disconnected, State.Connecting))
                 {
                     Interlocked.Increment(ref socketCount);
                     physical = new PhysicalConnection(this);
                 }
             }
             return null;
         }
         catch (Exception ex)
         {
             Multiplexer.Trace("Connect failed: " + ex.Message, Name);
             ChangeState(State.Disconnected);
             OnInternalError(ex);
             throw;
         }
     }
     return physical;
 }