// 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
            }
        }
            protected override bool SetResultCore(PhysicalConnection connection, Message message, RawResult result)
            {
                var tran = message as TransactionMessage;

                if (tran != null)
                {
                    var bridge  = connection.Bridge;
                    var wrapped = tran.InnerOperations;
                    switch (result.Type)
                    {
                    case ResultType.SimpleString:
                        if (tran.IsAborted && result.IsEqual(RedisLiterals.BytesOK))
                        {
                            connection.Multiplexer.Trace("Acknowledging UNWATCH (aborted electively)");
                            SetResult(message, false);
                            return(true);
                        }
                        break;

                    case ResultType.MultiBulk:
                        if (!tran.IsAborted)
                        {
                            var arr = result.GetItems();
                            if (arr == null)
                            {
                                connection.Multiplexer.Trace("Server aborted due to failed WATCH");
                                foreach (var op in wrapped)
                                {
                                    op.Wrapped.Cancel();
                                    bridge.CompleteSyncOrAsync(op.Wrapped);
                                }
                                SetResult(message, false);
                                return(true);
                            }
                            else if (wrapped.Length == arr.Length)
                            {
                                connection.Multiplexer.Trace("Server committed; processing nested replies");
                                for (int i = 0; i < arr.Length; i++)
                                {
                                    if (wrapped[i].Wrapped.ComputeResult(connection, arr[i]))
                                    {
                                        bridge.CompleteSyncOrAsync(wrapped[i].Wrapped);
                                    }
                                }
                                SetResult(message, true);
                                return(true);
                            }
                        }
                        break;
                    }
                    // even if we didn't fully understand the result, we still need to do something with
                    // the pending tasks
                    foreach (var op in wrapped)
                    {
                        op.Wrapped.Fail(ConnectionFailureType.ProtocolFailure, null);
                        bridge.CompleteSyncOrAsync(op.Wrapped);
                    }
                }
                return(false);
            }
Пример #3
0
            public bool TryParse(RawResult result, out T[] pairs)
            {
                switch (result.Type)
                {
                case ResultType.MultiBulk:
                    var arr = result.GetItems();
                    if (arr == null)
                    {
                        pairs = null;
                    }
                    else
                    {
                        int count = arr.Length / 2;
                        if (count == 0)
                        {
                            pairs = nix;
                        }
                        else
                        {
                            pairs = new T[count];
                            int offset = 0;
                            for (int i = 0; i < pairs.Length; i++)
                            {
                                pairs[i] = Parse(arr[offset++], arr[offset++]);
                            }
                        }
                    }
                    return(true);

                default:
                    pairs = null;
                    return(false);
                }
            }
Пример #4
0
 protected override bool SetResultCore(PhysicalConnection connection, Message message, RawResult result)
 {
     switch (result.Type)
     {
     case ResultType.MultiBulk:
         var            arr = result.GetItems();
         RedisChannel[] final;
         if (arr.Length == 0)
         {
             final = RedisChannel.EmptyArray;
         }
         else
         {
             final = new RedisChannel[arr.Length];
             byte[] channelPrefix = connection.ChannelPrefix;
             for (int i = 0; i < final.Length; i++)
             {
                 final[i] = result.AsRedisChannel(channelPrefix);
             }
         }
         SetResult(message, final);
         return(true);
     }
     return(false);
 }
Пример #5
0
 protected override bool SetResultCore(PhysicalConnection connection, Message message, RawResult result)
 {
     if (result.Type == ResultType.MultiBulk)
     {
         var  items = result.GetItems();
         long count;
         if (items.Length >= 3 && items[2].TryGetInt64(out count))
         {
             connection.SubscriptionCount = count;
             return(true);
         }
     }
     return(false);
 }
Пример #6
0
 protected override bool SetResultCore(PhysicalConnection connection, Message message, RawResult result)
 {
     switch (result.Type)
     {
     case ResultType.MultiBulk:
         var  arr = result.GetItems();
         long i64;
         if (arr.Length == 2 && arr[1].Type == ResultType.MultiBulk && arr[0].TryGetInt64(out i64))
         {
             var keysResult = new ScanResult(i64, arr[1].GetItemsAsKeys());
             SetResult(message, keysResult);
             return(true);
         }
         break;
     }
     return(false);
 }
Пример #7
0
        // 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(), result.Type));

                case ResultType.MultiBulk:
                    if (result.IsNull)
                    {
                        return(NullArray);
                    }
                    var items = result.GetItems();
                    if (items.Length == 0)
                    {
                        return(EmptyArray);
                    }
                    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
            }
        }
Пример #8
0
            protected override bool SetResultCore(PhysicalConnection connection, Message message, RawResult result)
            {
                long unixTime, micros;

                switch (result.Type)
                {
                case ResultType.Integer:
                    if (result.TryGetInt64(out unixTime))
                    {
                        var time = RedisBase.UnixEpoch.AddSeconds(unixTime);
                        SetResult(message, time);
                        return(true);
                    }
                    break;

                case ResultType.MultiBulk:
                    var arr = result.GetItems();
                    switch (arr.Length)
                    {
                    case 1:
                        if (arr[0].TryGetInt64(out unixTime))
                        {
                            var time = RedisBase.UnixEpoch.AddSeconds(unixTime);
                            SetResult(message, time);
                            return(true);
                        }
                        break;

                    case 2:
                        if (arr[0].TryGetInt64(out unixTime) && arr[1].TryGetInt64(out micros))
                        {
                            var time = RedisBase.UnixEpoch.AddSeconds(unixTime).AddTicks(micros * 10);         // datetime ticks are 100ns
                            SetResult(message, time);
                            return(true);
                        }
                        break;
                    }
                    break;
                }
                return(false);
            }
Пример #9
0
            protected override bool SetResultCore(PhysicalConnection connection, Message message, RawResult result)
            {
                bool happy;

                switch (message.Command)
                {
                case RedisCommand.ECHO:
                    happy = result.Type == ResultType.BulkString && (!establishConnection || result.IsEqual(connection.Multiplexer.UniqueId));
                    break;

                case RedisCommand.PING:
                    happy = result.Type == ResultType.SimpleString && result.IsEqual(RedisLiterals.BytesPONG);
                    break;

                case RedisCommand.TIME:
                    happy = result.Type == ResultType.MultiBulk && result.GetItems().Length == 2;
                    break;

                case RedisCommand.EXISTS:
                    happy = result.Type == ResultType.Integer;
                    break;

                default:
                    happy = true;
                    break;
                }
                if (happy)
                {
                    if (establishConnection)
                    {
                        connection.Bridge.OnFullyEstablished(connection);
                    }
                    SetResult(message, happy);
                    return(true);
                }
                else
                {
                    connection.RecordConnectionFailed(ConnectionFailureType.ProtocolFailure);
                    return(false);
                }
            }
 protected override bool SetResultCore(PhysicalConnection connection, Message message, RawResult result)
 {
     switch (result.Type)
     {
     case ResultType.MultiBulk:
         var            parts = result.GetItems();
         CommandTrace[] arr   = new CommandTrace[parts.Length];
         for (int i = 0; i < parts.Length; i++)
         {
             var subParts = parts[i].GetItems();
             if (!subParts[0].TryGetInt64(out long uniqueid) || !subParts[1].TryGetInt64(out long time) || !subParts[2].TryGetInt64(out long duration))
             {
                 return(false);
             }
             arr[i] = new CommandTrace(uniqueid, time, duration, subParts[3].GetItemsAsValues());
         }
         SetResult(message, arr);
         return(true);
     }
     return(false);
 }
Пример #11
0
            protected override bool SetResultCore(PhysicalConnection connection, Message message, RawResult result)
            {
                if (result.IsNull)
                {
                    SetResult(message, false); // lots of ops return (nil) when they mean "no"
                    return(true);
                }
                switch (result.Type)
                {
                case ResultType.SimpleString:
                    if (result.IsEqual(RedisLiterals.BytesOK))
                    {
                        SetResult(message, true);
                    }
                    else
                    {
                        SetResult(message, result.GetBoolean());
                    }
                    return(true);

                case ResultType.Integer:
                case ResultType.BulkString:
                    SetResult(message, result.GetBoolean());
                    return(true);

                case ResultType.MultiBulk:
                    var items = result.GetItems();
                    if (items.Length == 1)
                    {     // treat an array of 1 like a single reply (for example, SCRIPT EXISTS)
                        SetResult(message, items[0].GetBoolean());
                        return(true);
                    }
                    break;
                }
                return(false);
            }
Пример #12
0
        void MatchResult(RawResult result)
        {
            // check to see if it could be an out-of-band pubsub message
            if (connectionType == ConnectionType.Subscription && result.Type == ResultType.MultiBulk)
            {   // out of band message does not match to a queued message
                var items = result.GetItems();
                if (items.Length >= 3 && items[0].IsEqual(message))
                {
                    // special-case the configuration change broadcasts (we don't keep that in the usual pub/sub registry)
                    var configChanged = Multiplexer.ConfigurationChangedChannel;
                    if (configChanged != null && items[1].IsEqual(configChanged))
                    {
                        EndPoint blame = null;
                        try
                        {
                            if (!items[2].IsEqual(RedisLiterals.ByteWildcard))
                            {
                                blame = Format.TryParseEndPoint(items[2].GetString());
                            }
                        }
                        catch { /* no biggie */ }
                        Multiplexer.Trace("Configuration changed: " + Format.ToString(blame), physicalName);
                        Multiplexer.ReconfigureIfNeeded(blame, true, "broadcast");
                    }

                    // invoke the handlers
                    var channel = items[1].AsRedisChannel(ChannelPrefix, RedisChannel.PatternMode.Literal);
                    Multiplexer.Trace("MESSAGE: " + channel, physicalName);
                    if (!channel.IsNull)
                    {
                        Multiplexer.OnMessage(channel, channel, items[2].AsRedisValue());
                    }
                    return; // AND STOP PROCESSING!
                }
                else if (items.Length >= 4 && items[0].IsEqual(pmessage))
                {
                    var channel = items[2].AsRedisChannel(ChannelPrefix, RedisChannel.PatternMode.Literal);
                    Multiplexer.Trace("PMESSAGE: " + channel, physicalName);
                    if (!channel.IsNull)
                    {
                        var sub = items[1].AsRedisChannel(ChannelPrefix, RedisChannel.PatternMode.Pattern);
                        Multiplexer.OnMessage(sub, channel, items[3].AsRedisValue());
                    }
                    return; // AND STOP PROCESSING!
                }

                // if it didn't look like "[p]message", then we still need to process the pending queue
            }
            Multiplexer.Trace("Matching result...", physicalName);
            Message msg;

            lock (outstanding)
            {
                Multiplexer.Trace(outstanding.Count == 0, "Nothing to respond to!", physicalName);
                msg = outstanding.Dequeue();
            }

            Multiplexer.Trace("Response to: " + msg.ToString(), physicalName);
            if (msg.ComputeResult(this, result))
            {
                Bridge.CompleteSyncOrAsync(msg);
            }
        }
        void MatchResult(RawResult result)
        {
            // check to see if it could be an out-of-band pubsub message
            if (connectionType == ConnectionType.Subscription && result.Type == ResultType.MultiBulk)
            {   // out of band message does not match to a queued message
                var items = result.GetItems();
                if (items.Length >= 3 && items[0].IsEqual(message))
                {
                    // special-case the configuration change broadcasts (we don't keep that in the usual pub/sub registry)
                    var configChanged = multiplexer.ConfigurationChangedChannel;
                    if (configChanged != null && items[1].IsEqual(configChanged))
                    {
                        EndPoint blame = null;
                        try
                        {
                            if (!items[2].IsEqual(RedisLiterals.ByteWildcard))
                            {
                                blame = Format.TryParseEndPoint(items[2].GetString());
                            }
                        }
                        catch { /* no biggie */ }
                        multiplexer.Trace("Configuration changed: " + Format.ToString(blame), physicalName);
                        multiplexer.ReconfigureIfNeeded(blame, true, "broadcast");
                    }

                    // invoke the handlers
                    var channel = items[1].AsRedisChannel(ChannelPrefix, RedisChannel.PatternMode.Literal);
                    multiplexer.Trace("MESSAGE: " + channel, physicalName);
                    if (!channel.IsNull)
                    {
                        multiplexer.OnMessage(channel, channel, items[2].AsRedisValue());
                    }
                    return; // AND STOP PROCESSING!
                }
                else if (items.Length >= 4 && items[0].IsEqual(pmessage))
                {
                    var channel = items[2].AsRedisChannel(ChannelPrefix, RedisChannel.PatternMode.Literal);
                    multiplexer.Trace("PMESSAGE: " + channel, physicalName);
                    if (!channel.IsNull)
                    {
                        var sub = items[1].AsRedisChannel(ChannelPrefix, RedisChannel.PatternMode.Pattern);
                        multiplexer.OnMessage(sub, channel, items[3].AsRedisValue());
                    }
                    return; // AND STOP PROCESSING!
                }

                // if it didn't look like "[p]message", then we still need to process the pending queue
            }
            multiplexer.Trace("Matching result...", physicalName);
            Message msg;
            lock (outstanding)
            {
                multiplexer.Trace(outstanding.Count == 0, "Nothing to respond to!", physicalName);
                msg = outstanding.Dequeue();
            }

            multiplexer.Trace("Response to: " + msg.ToString(), physicalName);
            if (msg.ComputeResult(this, result))
            {
                bridge.CompleteSyncOrAsync(msg);
            }
        }
Пример #14
0
            protected override bool SetResultCore(PhysicalConnection connection, Message message, RawResult result)
            {
                var server = connection.Bridge.ServerEndPoint;

                switch (result.Type)
                {
                case ResultType.BulkString:
                    if (message != null && message.Command == RedisCommand.INFO)
                    {
                        string info = result.GetString(), line;
                        if (string.IsNullOrWhiteSpace(info))
                        {
                            SetResult(message, true);
                            return(true);
                        }
                        using (var reader = new StringReader(info))
                        {
                            while ((line = reader.ReadLine()) != null)
                            {
                                if (string.IsNullOrWhiteSpace(line) || line.StartsWith("# "))
                                {
                                    continue;
                                }

                                string val;
                                if ((val = Extract(line, "role:")) != null)
                                {
                                    switch (val)
                                    {
                                    case "master":
                                        server.IsSlave = false;
                                        server.Multiplexer.Trace("Auto-configured role: master");
                                        break;

                                    case "slave":
                                        server.IsSlave = true;
                                        server.Multiplexer.Trace("Auto-configured role: slave");
                                        break;
                                    }
                                }
                                else if ((val = Extract(line, "redis_version:")) != null)
                                {
                                    Version version;
                                    if (Version.TryParse(val, out version))
                                    {
                                        server.Version = version;
                                        server.Multiplexer.Trace("Auto-configured version: " + version);
                                    }
                                }
                                else if ((val = Extract(line, "redis_mode:")) != null)
                                {
                                    switch (val)
                                    {
                                    case "standalone":
                                        server.ServerType = ServerType.Standalone;
                                        server.Multiplexer.Trace("Auto-configured server-type: standalone");
                                        break;

                                    case "cluster":
                                        server.ServerType = ServerType.Cluster;
                                        server.Multiplexer.Trace("Auto-configured server-type: cluster");
                                        break;

                                    case "sentinel":
                                        server.ServerType = ServerType.Sentinel;
                                        server.Multiplexer.Trace("Auto-configured server-type: sentinel");
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    SetResult(message, true);
                    return(true);

                case ResultType.MultiBulk:
                    if (message != null && message.Command == RedisCommand.CONFIG)
                    {
                        var arr   = result.GetItems();
                        int count = arr.Length / 2;

                        byte[] timeout = (byte[])RedisLiterals.timeout,
                        databases       = (byte[])RedisLiterals.databases,
                        slave_read_only = (byte[])RedisLiterals.slave_read_only,
                        yes             = (byte[])RedisLiterals.yes,
                        no = (byte[])RedisLiterals.no;

                        long i64;
                        for (int i = 0; i < count; i++)
                        {
                            var key = arr[i * 2];
                            if (key.IsEqual(timeout) && arr[(i * 2) + 1].TryGetInt64(out i64))
                            {
                                // note the configuration is in seconds
                                int timeoutSeconds = checked ((int)i64), targetSeconds;
                                if (timeoutSeconds > 0)
                                {
                                    if (timeoutSeconds >= 60)
                                    {
                                        targetSeconds = timeoutSeconds - 20;     // time to spare...
                                    }
                                    else
                                    {
                                        targetSeconds = (timeoutSeconds * 3) / 4;
                                    }
                                    server.Multiplexer.Trace("Auto-configured timeout: " + targetSeconds + "s");
                                    server.WriteEverySeconds = targetSeconds;
                                }
                            }
                            else if (key.IsEqual(databases) && arr[(i * 2) + 1].TryGetInt64(out i64))
                            {
                                int dbCount = checked ((int)i64);
                                server.Multiplexer.Trace("Auto-configured databases: " + dbCount);
                                server.Databases = dbCount;
                            }
                            else if (key.IsEqual(slave_read_only))
                            {
                                var val = arr[(i * 2) + 1];
                                if (val.IsEqual(yes))
                                {
                                    server.SlaveReadOnly = true;
                                    server.Multiplexer.Trace("Auto-configured slave-read-only: true");
                                }
                                else if (val.IsEqual(no))
                                {
                                    server.SlaveReadOnly = false;
                                    server.Multiplexer.Trace("Auto-configured slave-read-only: false");
                                }
                            }
                        }
                    }
                    SetResult(message, true);
                    return(true);
                }
                return(false);
            }