internal ClusterNode(ClusterConfiguration configuration, string raw, EndPoint origin) { // http://redis.io/commands/cluster-nodes this.configuration = configuration; this.raw = raw; var parts = raw.Split(StringSplits.Space); var flags = parts[2].Split(StringSplits.Comma); endpoint = Format.TryParseEndPoint(parts[1]); nodeId = parts[0]; isSlave = flags.Contains("slave"); isNoAddr = flags.Contains("noaddr"); parentNodeId = string.IsNullOrWhiteSpace(parts[3]) ? null : parts[3]; List <SlotRange> slots = null; for (int i = 8; i < parts.Length; i++) { SlotRange range; if (SlotRange.TryParse(parts[i], out range)) { if (slots == null) { slots = new List <SlotRange>(parts.Length - i); } slots.Add(range); } } this.slots = slots == null ? NoSlots : slots.AsReadOnly(); this.isConnected = parts[7] == "connected"; // Can be "connected" or "disconnected" }
/// <summary> /// Adds a new endpoint to the list /// </summary> public void Add(string hostAndPort) { var endpoint = Format.TryParseEndPoint(hostAndPort); if (endpoint == null) { throw new ArgumentException(); } Add(endpoint); }
/// <summary> /// Adds a new endpoint to the list /// </summary> /// <param name="hostAndPort">The host:port string to add an endpoint for to the collection.</param> public void Add(string hostAndPort) { var endpoint = Format.TryParseEndPoint(hostAndPort); if (endpoint == null) { throw new ArgumentException($"Could not parse host and port from '{hostAndPort}'", nameof(hostAndPort)); } Add(endpoint); }
internal ClusterNode(ClusterConfiguration configuration, string raw, EndPoint origin) { // http://redis.io/commands/cluster-nodes this.configuration = configuration; this.Raw = raw; var parts = raw.Split(StringSplits.Space); var flags = parts[2].Split(StringSplits.Comma); // redis 4 changes the format of "cluster nodes" - adds @... to the endpoint var ep = parts[1]; int at = ep.IndexOf('@'); if (at >= 0) { ep = ep.Substring(0, at); } EndPoint = Format.TryParseEndPoint(ep); if (flags.Contains("myself")) { IsMyself = true; if (EndPoint == null) { // Unconfigured cluster nodes might report themselves as endpoint ":{port}", // hence the origin fallback value to make sure that we can address them EndPoint = origin; } } NodeId = parts[0]; IsSlave = flags.Contains("slave"); IsNoAddr = flags.Contains("noaddr"); ParentNodeId = string.IsNullOrWhiteSpace(parts[3]) ? null : parts[3]; List <SlotRange> slots = null; for (int i = 8; i < parts.Length; i++) { SlotRange range; if (SlotRange.TryParse(parts[i], out range)) { if (slots == null) { slots = new List <SlotRange>(parts.Length - i); } slots.Add(range); } } this.Slots = slots?.AsReadOnly() ?? NoSlots; this.IsConnected = parts[7] == "connected"; // Can be "connected" or "disconnected" }
// true if ready to be completed (i.e. false if re-issued to another server) public virtual bool SetResult(PhysicalConnection connection, Message message, RawResult result) { if (result.IsError) { var bridge = connection.Bridge; var server = bridge.ServerEndPoint; bool log = !message.IsInternalCall; bool isMoved = result.AssertStarts(MOVED); if (isMoved || result.AssertStarts(ASK)) { log = false; string[] parts = result.GetString().Split(StringSplits.Space, 3); int hashSlot; EndPoint endpoint; if (Format.TryParseInt32(parts[1], out hashSlot) && (endpoint = Format.TryParseEndPoint(parts[2])) != null) { // no point sending back to same server, and no point sending to a dead server if (!Equals(server.EndPoint, endpoint)) { if (bridge.Multiplexer.TryResend(hashSlot, message, endpoint, isMoved)) { connection.Multiplexer.Trace(message.Command + " re-issued to " + endpoint, isMoved ? "MOVED" : "ASK"); return(false); } } } } string err = result.GetString(); if (log) { bridge.Multiplexer.OnErrorMessage(server.EndPoint, err); } connection.Multiplexer.Trace("Completed with error: " + err + " (" + GetType().Name + ")", ToString()); ServerFail(message, err); } else { bool coreResult = SetResultCore(connection, message, result); if (coreResult) { connection.Multiplexer.Trace("Completed with success: " + result.ToString() + " (" + GetType().Name + ")", ToString()); } else { UnexpectedResponse(message, result); } } return(true); }
internal ClusterNode(ClusterConfiguration configuration, string raw, EndPoint origin) { // http://redis.io/commands/cluster-nodes this.configuration = configuration; this.raw = raw; var parts = raw.Split(StringSplits.Space); var flags = parts[2].Split(StringSplits.Comma); endpoint = Format.TryParseEndPoint(parts[1]); if (flags.Contains("myself")) { isMyself = true; if (endpoint == null) { // Unconfigured cluster nodes might report themselves as endpoint ":{port}", // hence the origin fallback value to make sure that we can address them endpoint = origin; } } nodeId = parts[0]; isSlave = flags.Contains("slave"); isNoAddr = flags.Contains("noaddr"); parentNodeId = string.IsNullOrWhiteSpace(parts[3]) ? null : parts[3]; List <SlotRange> slots = null; for (int i = 8; i < parts.Length; i++) { SlotRange range; if (SlotRange.TryParse(parts[i], out range)) { if (slots == null) { slots = new List <SlotRange>(parts.Length - i); } slots.Add(range); } } this.slots = slots == null ? NoSlots : slots.AsReadOnly(); this.isConnected = parts[7] == "connected"; // Can be "connected" or "disconnected" }
internal ClusterNode(ClusterConfiguration configuration, string raw, EndPoint origin) { this.configuration = configuration; this.raw = raw; var parts = raw.Split(StringSplits.Space); var flags = parts[2].Split(StringSplits.Comma); if (flags.Contains("myself")) { endpoint = origin; } else { endpoint = Format.TryParseEndPoint(parts[1]); } nodeId = parts[0]; isSlave = flags.Contains("slave"); parentNodeId = string.IsNullOrWhiteSpace(parts[3]) ? null : parts[3]; List <SlotRange> slots = null; for (int i = 8; i < parts.Length; i++) { SlotRange range; if (SlotRange.TryParse(parts[i], out range)) { if (slots == null) { slots = new List <SlotRange>(parts.Length - i); } slots.Add(range); } } this.slots = slots == null ? NoSlots : slots.AsReadOnly(); }
private void DoParse(string configuration, bool ignoreUnknown) { if (configuration == null) { throw new ArgumentNullException(nameof(configuration)); } if (string.IsNullOrWhiteSpace(configuration)) { throw new ArgumentException("is empty", configuration); } Clear(); // break it down by commas var arr = configuration.Split(StringSplits.Comma); Dictionary <string, string> map = null; foreach (var paddedOption in arr) { var option = paddedOption.Trim(); if (string.IsNullOrWhiteSpace(option)) { continue; } // check for special tokens int idx = option.IndexOf('='); if (idx > 0) { var key = option.Substring(0, idx).Trim(); var value = option.Substring(idx + 1).Trim(); switch (OptionKeys.TryNormalize(key)) { case OptionKeys.SyncTimeout: SyncTimeout = OptionKeys.ParseInt32(key, value, minValue: 1); break; case OptionKeys.AllowAdmin: AllowAdmin = OptionKeys.ParseBoolean(key, value); break; case OptionKeys.AbortOnConnectFail: AbortOnConnectFail = OptionKeys.ParseBoolean(key, value); break; case OptionKeys.ResolveDns: ResolveDns = OptionKeys.ParseBoolean(key, value); break; case OptionKeys.ServiceName: ServiceName = value; break; case OptionKeys.ClientName: ClientName = value; break; case OptionKeys.ChannelPrefix: ChannelPrefix = value; break; case OptionKeys.ConfigChannel: ConfigurationChannel = value; break; case OptionKeys.KeepAlive: KeepAlive = OptionKeys.ParseInt32(key, value); break; case OptionKeys.ConnectTimeout: ConnectTimeout = OptionKeys.ParseInt32(key, value); break; case OptionKeys.ConnectRetry: ConnectRetry = OptionKeys.ParseInt32(key, value); break; case OptionKeys.ConfigCheckSeconds: ConfigCheckSeconds = OptionKeys.ParseInt32(key, value); break; case OptionKeys.Version: DefaultVersion = OptionKeys.ParseVersion(key, value); break; case OptionKeys.Password: Password = value; break; case OptionKeys.TieBreaker: TieBreaker = value; break; case OptionKeys.Ssl: Ssl = OptionKeys.ParseBoolean(key, value); break; case OptionKeys.SslHost: SslHost = value; break; case OptionKeys.HighPrioritySocketThreads: HighPrioritySocketThreads = OptionKeys.ParseBoolean(key, value); break; case OptionKeys.WriteBuffer: WriteBuffer = OptionKeys.ParseInt32(key, value); break; case OptionKeys.Proxy: Proxy = OptionKeys.ParseProxy(key, value); break; case OptionKeys.ResponseTimeout: ResponseTimeout = OptionKeys.ParseInt32(key, value, minValue: 1); break; case OptionKeys.DefaultDatabase: defaultDatabase = OptionKeys.ParseInt32(key, value); break; case OptionKeys.PreserveAsyncOrder: PreserveAsyncOrder = OptionKeys.ParseBoolean(key, value); break; #if !CORE_CLR case OptionKeys.SslProtocols: SslProtocols = OptionKeys.ParseSslProtocols(key, value); break; #endif default: if (!string.IsNullOrEmpty(key) && key[0] == '$') { RedisCommand cmd; var cmdName = option.Substring(1, idx - 1); if (Enum.TryParse(cmdName, true, out cmd)) { if (map == null) { map = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); } map[cmdName] = value; } } else { if (!ignoreUnknown) { OptionKeys.Unknown(key); } } break; } } else { var ep = Format.TryParseEndPoint(option); if (ep != null && !endpoints.Contains(ep)) { endpoints.Add(ep); } } } if (map != null && map.Count != 0) { CommandMap = CommandMap.Create(map); } }
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); } }
/// <summary> /// Attempt to parse a string into an EndPoint /// </summary> public static EndPoint TryParse(string endpoint) { return(Format.TryParseEndPoint(endpoint)); }
internal static ClientInfo[] Parse(string input) { if (input == null) { return(null); } var clients = new List <ClientInfo>(); using (var reader = new StringReader(input)) { string line; while ((line = reader.ReadLine()) != null) { var client = new ClientInfo(); client.Raw = line; string[] tokens = line.Split(StringSplits.Space); for (int i = 0; i < tokens.Length; i++) { string tok = tokens[i]; int idx = tok.IndexOf('='); if (idx < 0) { continue; } string key = tok.Substring(0, idx), value = tok.Substring(idx + 1); switch (key) { case "addr": client.Address = Format.TryParseEndPoint(value); break; case "age": client.AgeSeconds = Format.ParseInt32(value); break; case "idle": client.IdleSeconds = Format.ParseInt32(value); break; case "db": client.Database = Format.ParseInt32(value); break; case "name": client.Name = value; break; case "sub": client.SubscriptionCount = Format.ParseInt32(value); break; case "psub": client.PatternSubscriptionCount = Format.ParseInt32(value); break; case "multi": client.TransactionCommandLength = Format.ParseInt32(value); break; case "cmd": client.LastCommand = value; break; case "flags": client.FlagsRaw = value; ClientFlags flags = ClientFlags.None; AddFlag(ref flags, value, ClientFlags.SlaveMonitor, 'O'); AddFlag(ref flags, value, ClientFlags.Slave, 'S'); AddFlag(ref flags, value, ClientFlags.Master, 'M'); AddFlag(ref flags, value, ClientFlags.Transaction, 'x'); AddFlag(ref flags, value, ClientFlags.Blocked, 'b'); AddFlag(ref flags, value, ClientFlags.TransactionDoomed, 'd'); AddFlag(ref flags, value, ClientFlags.Closing, 'c'); AddFlag(ref flags, value, ClientFlags.Unblocked, 'u'); AddFlag(ref flags, value, ClientFlags.CloseASAP, 'A'); client.Flags = flags; break; case "id": client.Id = Format.ParseInt64(value); break; } } clients.Add(client); } } return(clients.ToArray()); }
/// <summary> /// Attempt to parse a string into an EndPoint /// </summary> /// <param name="endpoint">The endpoint string to parse.</param> public static EndPoint TryParse(string endpoint) => Format.TryParseEndPoint(endpoint);