diff --git a/.editorconfig b/.editorconfig index 6934b4a38..a00642936 100644 --- a/.editorconfig +++ b/.editorconfig @@ -138,23 +138,73 @@ csharp_space_between_method_call_empty_parameter_list_parentheses = false csharp_preserve_single_line_statements = true csharp_preserve_single_line_blocks = true -# IDE0090: Use 'new(...)' -dotnet_diagnostic.IDE0090.severity = silent -# RCS1037: Remove trailing white-space. -dotnet_diagnostic.RCS1037.severity = error +# IDE preferences +dotnet_diagnostic.IDE0090.severity = silent # IDE0090: Use 'new(...)' + +#Roslynator preferences +dotnet_diagnostic.RCS1037.severity = error # RCS1037: Remove trailing white-space. +dotnet_diagnostic.RCS1098.severity = none # RCS1098: Constant values should be placed on right side of comparisons. + +dotnet_diagnostic.RCS1194.severity = none # RCS1194: Implement exception constructors. +dotnet_diagnostic.RCS1229.severity = none # RCS1229: Use async/await when necessary. +dotnet_diagnostic.RCS1233.severity = none # RCS1233: Use short-circuiting operator. +dotnet_diagnostic.RCS1234.severity = none # RCS1234: Duplicate enum value. + +# StyleCop preferences +dotnet_diagnostic.SA0001.severity = none # SA0001: XML comment analysis is disabled + +dotnet_diagnostic.SA1101.severity = none # SA1101: Prefix local calls with this +dotnet_diagnostic.SA1108.severity = none # SA1108: Block statements should not contain embedded comments +dotnet_diagnostic.SA1122.severity = none # SA1122: Use string.Empty for empty strings +dotnet_diagnostic.SA1127.severity = none # SA1127: Generic type constraints should be on their own line +dotnet_diagnostic.SA1128.severity = none # SA1128: Put constructor initializers on their own line +dotnet_diagnostic.SA1132.severity = none # SA1132: Do not combine fields +dotnet_diagnostic.SA1133.severity = none # SA1133: Do not combine attributes + +dotnet_diagnostic.SA1200.severity = none # SA1200: Using directives should be placed correctly +dotnet_diagnostic.SA1201.severity = none # SA1201: Elements should appear in the correct order +dotnet_diagnostic.SA1202.severity = none # SA1202: Elements should be ordered by access +dotnet_diagnostic.SA1203.severity = none # SA1203: Constants should appear before fields + +dotnet_diagnostic.SA1306.severity = none # SA1306: Field names should begin with lower-case letter +dotnet_diagnostic.SA1309.severity = none # SA1309: Field names should not begin with underscore +dotnet_diagnostic.SA1310.severity = silent # SA1310: Field names should not contain underscore +dotnet_diagnostic.SA1311.severity = none # SA1311: Static readonly fields should begin with upper-case letter +dotnet_diagnostic.SA1312.severity = none # SA1312: Variable names should begin with lower-case letter + +dotnet_diagnostic.SA1401.severity = silent # SA1401: Fields should be private +dotnet_diagnostic.SA1402.severity = suggestion # SA1402: File may only contain a single type + +dotnet_diagnostic.SA1503.severity = silent # SA1503: Braces should not be omitted +dotnet_diagnostic.SA1516.severity = silent # SA1516: Elements should be separated by blank line + +dotnet_diagnostic.SA1600.severity = none # SA1600: Elements should be documented +dotnet_diagnostic.SA1601.severity = none # SA1601: Partial elements should be documented +dotnet_diagnostic.SA1602.severity = none # SA1602: Enumeration items should be documented +dotnet_diagnostic.SA1615.severity = none # SA1615: Element return value should be documented +dotnet_diagnostic.SA1623.severity = none # SA1623: Property summary documentation should match accessors +dotnet_diagnostic.SA1633.severity = none # SA1633: File should have header +dotnet_diagnostic.SA1642.severity = none # SA1642: Constructor summary documentation should begin with standard text +dotnet_diagnostic.SA1643.severity = none # SA1643: Destructor summary documentation should begin with standard text + + +# To Fix: +dotnet_diagnostic.SA1204.severity = none # SA1204: Static elements should appear before instance elements +dotnet_diagnostic.SA1214.severity = none # SA1214: Readonly fields should appear before non-readonly fields +dotnet_diagnostic.SA1304.severity = none # SA1304: Non-private readonly fields should begin with upper-case letter +dotnet_diagnostic.SA1307.severity = none # SA1307: Accessible fields should begin with upper-case letter +dotnet_diagnostic.SA1308.severity = suggestion # SA1308: Variable names should not be prefixed +dotnet_diagnostic.SA1131.severity = none # SA1131: Use readable conditions +dotnet_diagnostic.SA1405.severity = none # SA1405: Debug.Assert should provide message text +dotnet_diagnostic.SA1501.severity = none # SA1501: Statement should not be on a single line +dotnet_diagnostic.SA1502.severity = suggestion # SA1502: Element should not be on a single line +dotnet_diagnostic.SA1513.severity = none # SA1513: Closing brace should be followed by blank line +dotnet_diagnostic.SA1515.severity = none # SA1515: Single-line comment should be preceded by blank line +dotnet_diagnostic.SA1611.severity = suggestion # SA1611: Element parameters should be documented +dotnet_diagnostic.SA1649.severity = suggestion # SA1649: File name should match first type name -# RCS1098: Constant values should be placed on right side of comparisons. -dotnet_diagnostic.RCS1098.severity = none -# RCS1194: Implement exception constructors. -dotnet_diagnostic.RCS1194.severity = none -# RCS1229: Use async/await when necessary. -dotnet_diagnostic.RCS1229.severity = none -# RCS1233: Use short-circuiting operator. -dotnet_diagnostic.RCS1233.severity = none -# RCS1234: Duplicate enum value. -dotnet_diagnostic.RCS1234.severity = none \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index 43dd33169..ff720e26a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -33,10 +33,13 @@ true true + + + diff --git a/Directory.Packages.props b/Directory.Packages.props index 9ef9afb25..49d37a3ae 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -20,6 +20,7 @@ + diff --git a/src/StackExchange.Redis/APITypes/ClientKillFilter.cs b/src/StackExchange.Redis/APITypes/ClientKillFilter.cs index b5c5e845c..3d1883549 100644 --- a/src/StackExchange.Redis/APITypes/ClientKillFilter.cs +++ b/src/StackExchange.Redis/APITypes/ClientKillFilter.cs @@ -113,7 +113,7 @@ public ClientKillFilter WithSkipMe(bool? skipMe) /// /// Set the MaxAgeInSeconds filter. /// - /// Age of connection in seconds + /// Age of connection in seconds. public ClientKillFilter WithMaxAgeInSeconds(long? maxAgeInSeconds) { MaxAgeInSeconds = maxAgeInSeconds; @@ -123,9 +123,9 @@ public ClientKillFilter WithMaxAgeInSeconds(long? maxAgeInSeconds) internal List ToList(bool withReplicaCommands) { var parts = new List(15) - { - RedisLiterals.KILL - }; + { + RedisLiterals.KILL, + }; if (Id != null) { parts.Add(RedisLiterals.ID); diff --git a/src/StackExchange.Redis/APITypes/GeoRadiusOptions.cs b/src/StackExchange.Redis/APITypes/GeoRadiusOptions.cs index f9f182f5b..d21254fcd 100644 --- a/src/StackExchange.Redis/APITypes/GeoRadiusOptions.cs +++ b/src/StackExchange.Redis/APITypes/GeoRadiusOptions.cs @@ -13,22 +13,26 @@ public enum GeoRadiusOptions /// No Options. /// None = 0, + /// /// Redis will return the coordinates of any results. /// WithCoordinates = 1, + /// /// Redis will return the distance from center for all results. /// WithDistance = 2, + /// /// Redis will return the geo hash value as an integer. (This is the score in the sorted set). /// WithGeoHash = 4, + /// /// Populates the commonly used values from the entry (the integer hash is not returned as it is not commonly useful). /// - Default = WithCoordinates | WithDistance + Default = WithCoordinates | WithDistance, } internal static class GeoRadiusOptionsExtensions diff --git a/src/StackExchange.Redis/APITypes/GeoRadiusResult.cs b/src/StackExchange.Redis/APITypes/GeoRadiusResult.cs index d4cdbe8f8..952ca1625 100644 --- a/src/StackExchange.Redis/APITypes/GeoRadiusResult.cs +++ b/src/StackExchange.Redis/APITypes/GeoRadiusResult.cs @@ -23,7 +23,7 @@ public readonly struct GeoRadiusResult /// /// The hash value of the matched member as an integer. (The key in the sorted set). /// - /// Note that this is not the same as the hash returned from GeoHash + /// Note that this is not the same as the hash returned from GeoHash. public long? Hash { get; } /// diff --git a/src/StackExchange.Redis/APITypes/GeoSearchShape.cs b/src/StackExchange.Redis/APITypes/GeoSearchShape.cs index 68f1ee754..7d85c3bfa 100644 --- a/src/StackExchange.Redis/APITypes/GeoSearchShape.cs +++ b/src/StackExchange.Redis/APITypes/GeoSearchShape.cs @@ -3,7 +3,7 @@ namespace StackExchange.Redis; /// -/// A Shape that you can use for a GeoSearch +/// A Shape that you can use for a GeoSearch. /// public abstract class GeoSearchShape { @@ -18,9 +18,9 @@ public abstract class GeoSearchShape internal abstract int ArgCount { get; } /// - /// constructs a + /// constructs a . /// - /// + /// The geography unit to use. public GeoSearchShape(GeoUnit unit) { Unit = unit; @@ -30,7 +30,7 @@ public GeoSearchShape(GeoUnit unit) } /// -/// A circle drawn on a map bounding +/// A circle drawn on a map bounding. /// public class GeoSearchCircle : GeoSearchShape { @@ -41,7 +41,7 @@ public class GeoSearchCircle : GeoSearchShape /// /// The radius of the circle. /// The distance unit the circle will use, defaults to Meters. - public GeoSearchCircle(double radius, GeoUnit unit = GeoUnit.Meters) : base (unit) + public GeoSearchCircle(double radius, GeoUnit unit = GeoUnit.Meters) : base(unit) { _radius = radius; } @@ -49,9 +49,8 @@ public GeoSearchCircle(double radius, GeoUnit unit = GeoUnit.Meters) : base (uni internal override int ArgCount => 3; /// - /// Gets the s for this shape + /// Gets the s for this shape. /// - /// internal override void AddArgs(List args) { args.Add(RedisLiterals.BYRADIUS); @@ -61,7 +60,7 @@ internal override void AddArgs(List args) } /// -/// A box drawn on a map +/// A box drawn on a map. /// public class GeoSearchBox : GeoSearchShape { diff --git a/src/StackExchange.Redis/APITypes/LatencyHistoryEntry.cs b/src/StackExchange.Redis/APITypes/LatencyHistoryEntry.cs index 2303c6e49..003708e6a 100644 --- a/src/StackExchange.Redis/APITypes/LatencyHistoryEntry.cs +++ b/src/StackExchange.Redis/APITypes/LatencyHistoryEntry.cs @@ -3,7 +3,7 @@ namespace StackExchange.Redis; /// -/// A latency entry as reported by the built-in LATENCY HISTORY command +/// A latency entry as reported by the built-in LATENCY HISTORY command. /// public readonly struct LatencyHistoryEntry { @@ -30,12 +30,12 @@ protected override bool TryParse(in RawResult raw, out LatencyHistoryEntry parse } /// - /// The time at which this entry was recorded + /// The time at which this entry was recorded. /// public DateTime Timestamp { get; } /// - /// The latency recorded for this event + /// The latency recorded for this event. /// public int DurationMilliseconds { get; } diff --git a/src/StackExchange.Redis/APITypes/LatencyLatestEntry.cs b/src/StackExchange.Redis/APITypes/LatencyLatestEntry.cs index 67e416dc8..d1bc70e42 100644 --- a/src/StackExchange.Redis/APITypes/LatencyLatestEntry.cs +++ b/src/StackExchange.Redis/APITypes/LatencyLatestEntry.cs @@ -3,7 +3,7 @@ namespace StackExchange.Redis; /// -/// A latency entry as reported by the built-in LATENCY LATEST command +/// A latency entry as reported by the built-in LATENCY LATEST command. /// public readonly struct LatencyLatestEntry { @@ -31,22 +31,22 @@ protected override bool TryParse(in RawResult raw, out LatencyLatestEntry parsed } /// - /// The name of this event + /// The name of this event. /// public string EventName { get; } /// - /// The time at which this entry was recorded + /// The time at which this entry was recorded. /// public DateTime Timestamp { get; } /// - /// The latency recorded for this event + /// The latency recorded for this event. /// public int DurationMilliseconds { get; } /// - /// The max latency recorded for all events + /// The max latency recorded for all events. /// public int MaxDurationMilliseconds { get; } diff --git a/src/StackExchange.Redis/APITypes/StreamPendingMessageInfo.cs b/src/StackExchange.Redis/APITypes/StreamPendingMessageInfo.cs index 95f545ca5..32cbbcc8d 100644 --- a/src/StackExchange.Redis/APITypes/StreamPendingMessageInfo.cs +++ b/src/StackExchange.Redis/APITypes/StreamPendingMessageInfo.cs @@ -1,5 +1,4 @@ - -namespace StackExchange.Redis; +namespace StackExchange.Redis; /// /// Describes properties of a pending message. diff --git a/src/StackExchange.Redis/BufferReader.cs b/src/StackExchange.Redis/BufferReader.cs index 5691217f9..22b36ccb6 100644 --- a/src/StackExchange.Redis/BufferReader.cs +++ b/src/StackExchange.Redis/BufferReader.cs @@ -41,7 +41,8 @@ private bool FetchNextSegment() _current = _iterator.Current.Span; OffsetThisSpan = 0; RemainingThisSpan = _current.Length; - } while (IsEmpty); // skip empty segments, they don't help us! + } + while (IsEmpty); // skip empty segments, they don't help us! return true; } @@ -59,7 +60,7 @@ public BufferReader(scoped in ReadOnlySequence buffer) } /// - /// Note that in results other than success, no guarantees are made about final state; if you care: snapshot + /// Note that in results other than success, no guarantees are made about final state; if you care: snapshot. /// public ConsumeResult TryConsumeCRLF() { @@ -82,6 +83,7 @@ public ConsumeResult TryConsumeCRLF() return result; } } + public bool TryConsume(int count) { if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); @@ -102,7 +104,8 @@ public bool TryConsume(int count) // consume all of this span _totalConsumed += available; count -= available; - } while (FetchNextSegment()); + } + while (FetchNextSegment()); return false; } @@ -127,13 +130,18 @@ public ReadOnlySequence ConsumeAsBuffer(int count) if (!TryConsumeAsBuffer(count, out var buffer)) throw new EndOfStreamException(); return buffer; } + public ReadOnlySequence ConsumeToEnd() { var from = SnapshotPosition(); var result = _buffer.Slice(from); - while (FetchNextSegment()) { } // consume all + while (FetchNextSegment()) + { + // consume all + } return result; } + public bool TryConsumeAsBuffer(int count, out ReadOnlySequence buffer) { var from = SnapshotPosition(); @@ -146,6 +154,7 @@ public bool TryConsumeAsBuffer(int count, out ReadOnlySequence buffer) buffer = _buffer.Slice(from, to); return true; } + public void Consume(int count) { if (!TryConsume(count)) throw new EndOfStreamException(); @@ -163,13 +172,14 @@ public void Consume(int count) if (found >= 0) return totalSkipped + found; totalSkipped += span.Length; - } while (reader.FetchNextSegment()); + } + while (reader.FetchNextSegment()); return -1; } + internal static int FindNextCrLf(BufferReader reader) // very deliberately not ref; want snapshot { // is it in the current span? (we need to handle the offsets differently if so) - int totalSkipped = 0; bool haveTrailingCR = false; do diff --git a/src/StackExchange.Redis/ChannelMessageQueue.cs b/src/StackExchange.Redis/ChannelMessageQueue.cs index 3bf7635f3..e58fb393b 100644 --- a/src/StackExchange.Redis/ChannelMessageQueue.cs +++ b/src/StackExchange.Redis/ChannelMessageQueue.cs @@ -52,12 +52,12 @@ internal ChannelMessage(ChannelMessageQueue queue, in RedisChannel channel, in R public RedisValue Message { get; } /// - /// Checks if 2 messages are .Equal() + /// Checks if 2 messages are .Equal(). /// public static bool operator ==(ChannelMessage left, ChannelMessage right) => left.Equals(right); /// - /// Checks if 2 messages are not .Equal() + /// Checks if 2 messages are not .Equal(). /// public static bool operator !=(ChannelMessage left, ChannelMessage right) => !left.Equals(right); } @@ -72,6 +72,7 @@ internal ChannelMessage(ChannelMessageQueue queue, in RedisChannel channel, in R public sealed class ChannelMessageQueue : IAsyncEnumerable { private readonly Channel _queue; + /// /// The Channel that was subscribed for this queue. /// @@ -202,7 +203,8 @@ internal static void Combine(ref ChannelMessageQueue? head, ChannelMessageQueue { old = Volatile.Read(ref head); queue._next = old; - } while (Interlocked.CompareExchange(ref head, queue, old) != old); + } + while (Interlocked.CompareExchange(ref head, queue, old) != old); } } @@ -226,7 +228,8 @@ internal static void Remove(ref ChannelMessageQueue? head, ChannelMessageQueue q } bool found; - do // if we fail due to a conflict, re-do from start + // if we fail due to a conflict, re-do from start + do { var current = Volatile.Read(ref head); if (current == null) return; // no queue? nothing to do @@ -261,9 +264,11 @@ internal static void Remove(ref ChannelMessageQueue? head, ChannelMessageQueue q } previous = current; current = Volatile.Read(ref previous!._next); - } while (current != null); + } + while (current != null); } - } while (found); + } + while (found); } internal static int Count(ref ChannelMessageQueue? head) diff --git a/src/StackExchange.Redis/ClientInfo.cs b/src/StackExchange.Redis/ClientInfo.cs index 215403fe8..f04058495 100644 --- a/src/StackExchange.Redis/ClientInfo.cs +++ b/src/StackExchange.Redis/ClientInfo.cs @@ -156,7 +156,7 @@ public sealed class ClientInfo /// /// A unique 64-bit client ID (introduced in Redis 2.8.12). /// - public long Id { get;private set; } + public long Id { get; private set; } /// /// Format the object as a string. @@ -217,7 +217,7 @@ internal static bool TryParse(string? input, [NotNullWhen(true)] out ClientInfo[ { var client = new ClientInfo { - Raw = line + Raw = line, }; string[] tokens = line.Split(StringSplits.Space); for (int i = 0; i < tokens.Length; i++) @@ -285,7 +285,7 @@ private class ClientInfoProcessor : ResultProcessor { protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) { - switch(result.Resp2TypeBulkString) + switch (result.Resp2TypeBulkString) { case ResultType.BulkString: var raw = result.GetString(); diff --git a/src/StackExchange.Redis/ClusterConfiguration.cs b/src/StackExchange.Redis/ClusterConfiguration.cs index 83ab19501..0ce256c95 100644 --- a/src/StackExchange.Redis/ClusterConfiguration.cs +++ b/src/StackExchange.Redis/ClusterConfiguration.cs @@ -247,7 +247,7 @@ internal ClusterNode? this[string nodeId] /// The slot ID to get a node by. public ClusterNode? GetBySlot(int slot) { - foreach(var node in Nodes) + foreach (var node in Nodes) { if (!node.IsReplica && node.ServesSlot(slot)) return node; } @@ -265,7 +265,7 @@ internal ClusterNode? this[string nodeId] /// Represents the configuration of a single node in a cluster configuration. /// /// - public sealed class ClusterNode : IEquatable, IComparable, IComparable + public sealed class ClusterNode : IEquatable, IComparable, IComparable { private readonly ClusterConfiguration configuration; private IList? children; @@ -421,7 +421,8 @@ public int CompareTo(ClusterNode? other) if (IsReplica != other.IsReplica) return IsReplica ? 1 : -1; // primaries first - if (IsReplica) // both replicas? compare by parent, so we get primaries A, B, C and then replicas of A, B, C + // both replicas? compare by parent, so we get primaries A, B, C and then replicas of A, B, C + if (IsReplica) { int i = string.CompareOrdinal(ParentNodeId, other.ParentNodeId); if (i != 0) return i; @@ -457,16 +458,16 @@ public override string ToString() if (Parent is ClusterNode parent) sb.Append(" at ").Append(parent.EndPoint); } var childCount = Children.Count; - switch(childCount) + switch (childCount) { case 0: break; case 1: sb.Append(", 1 replica"); break; default: sb.Append(", ").Append(childCount).Append(" replicas"); break; } - if(Slots.Count != 0) + if (Slots.Count != 0) { sb.Append(", slots: "); - foreach(var slot in Slots) + foreach (var slot in Slots) { sb.Append(slot).Append(' '); } diff --git a/src/StackExchange.Redis/CommandBytes.cs b/src/StackExchange.Redis/CommandBytes.cs index d9c96a3ab..19a69549b 100644 --- a/src/StackExchange.Redis/CommandBytes.cs +++ b/src/StackExchange.Redis/CommandBytes.cs @@ -54,7 +54,6 @@ public override int GetHashCode() public bool Equals(in CommandBytes other) => _0 == other._0 && _1 == other._1 && _2 == other._2 && _3 == other._3; // note: don't add == operators; with the implicit op above, that invalidates "==null" compiler checks (which should report a failure!) - public static implicit operator CommandBytes(string value) => new CommandBytes(value); public override unsafe string ToString() @@ -181,10 +180,16 @@ private static unsafe int UpperCasifyUnicode(int oldLen, byte* bPtr) char* workspace = stackalloc char[MaxChars]; int charCount = Encoding.GetChars(bPtr, oldLen, workspace, MaxChars); char* c = workspace; - for (int i = 0; i < charCount; i++) *c = char.ToUpperInvariant(*c++); + for (int i = 0; i < charCount; i++) + { + *c = char.ToUpperInvariant(*c++); + } int newLen = Encoding.GetBytes(workspace, charCount, bPtr, MaxLength); // don't forget to zero any shrink - for (int i = newLen; i < oldLen; i++) bPtr[i] = 0; + for (int i = newLen; i < oldLen; i++) + { + bPtr[i] = 0; + } return newLen; } diff --git a/src/StackExchange.Redis/CommandMap.cs b/src/StackExchange.Redis/CommandMap.cs index 0a42d3e34..67b6f1a9e 100644 --- a/src/StackExchange.Redis/CommandMap.cs +++ b/src/StackExchange.Redis/CommandMap.cs @@ -41,7 +41,7 @@ public sealed class CommandMap RedisCommand.BGREWRITEAOF, RedisCommand.BGSAVE, RedisCommand.CLIENT, RedisCommand.CLUSTER, RedisCommand.CONFIG, RedisCommand.DBSIZE, RedisCommand.DEBUG, RedisCommand.FLUSHALL, RedisCommand.FLUSHDB, RedisCommand.INFO, RedisCommand.LASTSAVE, RedisCommand.MONITOR, RedisCommand.REPLICAOF, - RedisCommand.SAVE, RedisCommand.SHUTDOWN, RedisCommand.SLAVEOF, RedisCommand.SLOWLOG, RedisCommand.SYNC, RedisCommand.TIME + RedisCommand.SAVE, RedisCommand.SHUTDOWN, RedisCommand.SLAVEOF, RedisCommand.SLOWLOG, RedisCommand.SYNC, RedisCommand.TIME, }); /// @@ -80,20 +80,27 @@ public sealed class CommandMap /// The commands available to SSDB. /// /// - public static CommandMap SSDB { get; } = Create(new HashSet { - "ping", - "get", "set", "del", "incr", "incrby", "mget", "mset", "keys", "getset", "setnx", - "hget", "hset", "hdel", "hincrby", "hkeys", "hvals", "hmget", "hmset", "hlen", - "zscore", "zadd", "zrem", "zrange", "zrangebyscore", "zincrby", "zdecrby", "zcard", - "llen", "lpush", "rpush", "lpop", "rpop", "lrange", "lindex" - }, true); + public static CommandMap SSDB { get; } = Create( + new HashSet + { + "ping", + "get", "set", "del", "incr", "incrby", "mget", "mset", "keys", "getset", "setnx", + "hget", "hset", "hdel", "hincrby", "hkeys", "hvals", "hmget", "hmset", "hlen", + "zscore", "zadd", "zrem", "zrange", "zrangebyscore", "zincrby", "zdecrby", "zcard", + "llen", "lpush", "rpush", "lpop", "rpop", "lrange", "lindex", + }, + true); /// /// The commands available to Sentinel. /// /// - public static CommandMap Sentinel { get; } = Create(new HashSet { - "auth", "hello", "ping", "info", "role", "sentinel", "subscribe", "shutdown", "psubscribe", "unsubscribe", "punsubscribe" }, true); + public static CommandMap Sentinel { get; } = Create( + new HashSet + { + "auth", "hello", "ping", "info", "role", "sentinel", "subscribe", "shutdown", "psubscribe", "unsubscribe", "punsubscribe", + }, + true); /// /// Create a new , customizing some commands. @@ -195,8 +202,9 @@ internal void AssertAvailable(RedisCommand command) internal CommandBytes GetBytes(string command) { if (command == null) return default; - if(Enum.TryParse(command, true, out RedisCommand cmd)) - { // we know that one! + if (Enum.TryParse(command, true, out RedisCommand cmd)) + { + // we know that one! return map[(int)cmd]; } return new CommandBytes(command); diff --git a/src/StackExchange.Redis/CommandTrace.cs b/src/StackExchange.Redis/CommandTrace.cs index 061f252b9..aedd05fea 100644 --- a/src/StackExchange.Redis/CommandTrace.cs +++ b/src/StackExchange.Redis/CommandTrace.cs @@ -14,7 +14,7 @@ internal CommandTrace(long uniqueId, long time, long duration, RedisValue[] argu UniqueId = uniqueId; Time = RedisBase.UnixEpoch.AddSeconds(time); // duration = The amount of time needed for its execution, in microseconds. - // A tick is equal to 100 nanoseconds, or one ten-millionth of a second. + // A tick is equal to 100 nanoseconds, or one ten-millionth of a second. // So 1 microsecond = 10 ticks Duration = TimeSpan.FromTicks(duration * 10); Arguments = arguments; @@ -42,7 +42,7 @@ internal CommandTrace(long uniqueId, long time, long duration, RedisValue[] argu public long UniqueId { get; } /// - /// Deduces a link to the redis documentation about the specified command + /// Deduces a link to the redis documentation about the specified command. /// public string? GetHelpUrl() { @@ -73,18 +73,18 @@ private class CommandTraceProcessor : ResultProcessor { protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) { - switch(result.Resp2TypeArray) + switch (result.Resp2TypeArray) { case ResultType.Array: var parts = result.GetItems(); CommandTrace[] arr = new CommandTrace[parts.Length]; int i = 0; - foreach(var item in parts) + foreach (var item in parts) { var subParts = item.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()!); + arr[i++] = new CommandTrace(uniqueid, time, duration, subParts[3].GetItemsAsValues()!); } SetResult(message, arr); return true; diff --git a/src/StackExchange.Redis/Condition.cs b/src/StackExchange.Redis/Condition.cs index 0dcccf59c..308c87c11 100644 --- a/src/StackExchange.Redis/Condition.cs +++ b/src/StackExchange.Redis/Condition.cs @@ -483,7 +483,7 @@ internal override bool TryValidate(in RawResult result, out bool value) { case RedisType.SortedSet: var parsedValue = result.AsRedisValue(); - value = (parsedValue.IsNull != expectedResult); + value = parsedValue.IsNull != expectedResult; ConnectionMultiplexer.TraceWithoutContext("exists: " + parsedValue + "; expected: " + expectedResult + "; voting: " + value); return true; @@ -633,7 +633,7 @@ internal override bool TryValidate(in RawResult result, out bool value) } else { - value = (parsed.IsNull != expectedResult); + value = parsed.IsNull != expectedResult; ConnectionMultiplexer.TraceWithoutContext("exists: " + parsed + "; expected: " + expectedResult + "; voting: " + value); } return true; diff --git a/src/StackExchange.Redis/Configuration/AzureOptionsProvider.cs b/src/StackExchange.Redis/Configuration/AzureOptionsProvider.cs index e66b0b210..6e38e15a9 100644 --- a/src/StackExchange.Redis/Configuration/AzureOptionsProvider.cs +++ b/src/StackExchange.Redis/Configuration/AzureOptionsProvider.cs @@ -1,7 +1,7 @@ -using StackExchange.Redis.Maintenance; -using System; +using System; using System.Net; using System.Threading.Tasks; +using StackExchange.Redis.Maintenance; namespace StackExchange.Redis.Configuration { diff --git a/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs b/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs index 359b5f5f6..703adbcac 100644 --- a/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs +++ b/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs @@ -31,7 +31,7 @@ public class DefaultOptionsProvider /// /// The current list of providers to match (potentially modified from defaults via . /// - private static LinkedList KnownProviders { get; set; } = new (BuiltInProviders); + private static LinkedList KnownProviders { get; set; } = new(BuiltInProviders); /// /// Adds a provider to match endpoints against. The last provider added has the highest priority. @@ -143,9 +143,9 @@ public static DefaultOptionsProvider GetProvider(EndPoint endpoint) /// /// Controls how often the connection heartbeats. A heartbeat includes: - /// - Evaluating if any messages have timed out - /// - Evaluating connection status (checking for failures) - /// - Sending a server message to keep the connection alive if needed + /// - Evaluating if any messages have timed out. + /// - Evaluating connection status (checking for failures). + /// - Sending a server message to keep the connection alive if needed. /// /// Be aware setting this very low incurs additional overhead of evaluating the above more often. public virtual TimeSpan HeartbeatInterval => TimeSpan.FromSeconds(1); @@ -157,12 +157,12 @@ public static DefaultOptionsProvider GetProvider(EndPoint endpoint) public virtual bool HeartbeatConsistencyChecks => false; /// - /// Should exceptions include identifiable details? (key names, additional .Data annotations) + /// Whether exceptions include identifiable details (key names, additional .Data annotations). /// public virtual bool IncludeDetailInExceptions => true; /// - /// Should exceptions include performance counter details? + /// Whether exceptions include performance counter details. /// /// /// CPU usage, etc - note that this can be problematic on some platforms. @@ -223,6 +223,7 @@ public static DefaultOptionsProvider GetProvider(EndPoint endpoint) // We memoize this to reduce cost on re-access private string? defaultClientName; + /// /// The default client name for a connection, with the library version appended. /// @@ -253,7 +254,7 @@ protected virtual string GetDefaultClientName() => protected static string ComputerName => Environment.MachineName ?? Environment.GetEnvironmentVariable("ComputerName") ?? "Unknown"; /// - /// Whether to identify the client by library name/version when possible + /// Whether to identify the client by library name/version when possible. /// public virtual bool SetClientLibrary => true; @@ -293,7 +294,7 @@ protected virtual string GetDefaultClientName() => } catch (Exception) { - //silently ignores the exception + // Silently ignores the exception roleInstanceId = null; } return roleInstanceId; diff --git a/src/StackExchange.Redis/Configuration/LoggingTunnel.cs b/src/StackExchange.Redis/Configuration/LoggingTunnel.cs index a30dedf85..987d2075c 100644 --- a/src/StackExchange.Redis/Configuration/LoggingTunnel.cs +++ b/src/StackExchange.Redis/Configuration/LoggingTunnel.cs @@ -1,6 +1,4 @@ -using Pipelines.Sockets.Unofficial; -using Pipelines.Sockets.Unofficial.Arenas; -using System; +using System; using System.Buffers; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -12,12 +10,14 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Pipelines.Sockets.Unofficial; +using Pipelines.Sockets.Unofficial.Arenas; using static StackExchange.Redis.PhysicalConnection; namespace StackExchange.Redis.Configuration; /// -/// Captures redis traffic; intended for debug use +/// Captures redis traffic; intended for debug use. /// [Obsolete("This API is experimental, has security and performance implications, and may change without notice", false)] [SuppressMessage("ApiDesign", "RS0016:Add public types and members to the declared API", Justification = "Experimental API")] @@ -28,7 +28,7 @@ public abstract class LoggingTunnel : Tunnel private readonly Tunnel? _tail; /// - /// Replay the RESP messages for a pair of streams, invoking a callback per operation + /// Replay the RESP messages for a pair of streams, invoking a callback per operation. /// public static async Task ReplayAsync(Stream @out, Stream @in, Action pair) { @@ -51,7 +51,8 @@ public static async Task ReplayAsync(Stream @out, Stream @in, Action ReplayAsync(Stream @out, Stream @in, Action - /// Replay the RESP messages all the streams in a folder, invoking a callback per operation + /// Replay the RESP messages all the streams in a folder, invoking a callback per operation. /// /// The directory of captured files to replay. /// Operation to perform per replayed message pair. @@ -249,15 +249,14 @@ private static ContextualRedisResult ProcessBuffer(Arena arena, ref R static bool IsArrayOutOfBand(in RawResult result) { var items = result.GetItems(); - return (items.Length >= 3 && items[0].IsEqual(message) || items[0].IsEqual(smessage)) + return (items.Length >= 3 && (items[0].IsEqual(message) || items[0].IsEqual(smessage))) || (items.Length >= 4 && items[0].IsEqual(pmessage)); - } } private static readonly CommandBytes message = "message", pmessage = "pmessage", smessage = "smessage"; /// - /// Create a new instance of a + /// Create a new instance of a . /// protected LoggingTunnel(ConfigurationOptions? options = null, Tunnel? tail = null) { @@ -324,7 +323,7 @@ protected override Stream Log(Stream stream, EndPoint endpoint, ConnectionType c } /// - /// Perform logging on the provided stream + /// Perform logging on the provided stream. /// protected abstract Stream Log(Stream stream, EndPoint endpoint, ConnectionType connectionType); @@ -353,10 +352,12 @@ private async Task TlsHandshakeAsync(Stream stream, EndPoint endpoint) host = Format.ToStringHostOnly(endpoint); } - var ssl = new SslStream(stream, false, - _options.CertificateValidationCallback ?? PhysicalConnection.GetAmbientIssuerCertificateCallback(), - _options.CertificateSelectionCallback ?? PhysicalConnection.GetAmbientClientCertificateCallback(), - EncryptionPolicy.RequireEncryption); + var ssl = new SslStream( + innerStream: stream, + leaveInnerStreamOpen: false, + userCertificateValidationCallback: _options.CertificateValidationCallback ?? PhysicalConnection.GetAmbientIssuerCertificateCallback(), + userCertificateSelectionCallback: _options.CertificateSelectionCallback ?? PhysicalConnection.GetAmbientClientCertificateCallback(), + encryptionPolicy: EncryptionPolicy.RequireEncryption); #if NETCOREAPP3_1_OR_GREATER var configOptions = _options.SslClientAuthenticationOptions?.Invoke(host); @@ -375,7 +376,7 @@ private async Task TlsHandshakeAsync(Stream stream, EndPoint endpoint) } /// - /// Get a typical text representation of a redis command + /// Get a typical text representation of a redis command. /// public static string DefaultFormatCommand(RedisResult value) { @@ -402,7 +403,7 @@ public static string DefaultFormatCommand(RedisResult value) return sb.ToString(); } } - catch {} + catch { } return value.Type.ToString(); static bool IsSimple(RedisResult value) @@ -433,7 +434,7 @@ static bool IsSimple(RedisResult value) } /// - /// Get a typical text representation of a redis response + /// Get a typical text representation of a redis response. /// public static string DefaultFormatResponse(RedisResult value) { diff --git a/src/StackExchange.Redis/Configuration/Tunnel.cs b/src/StackExchange.Redis/Configuration/Tunnel.cs index 15c9abd15..beebff2dc 100644 --- a/src/StackExchange.Redis/Configuration/Tunnel.cs +++ b/src/StackExchange.Redis/Configuration/Tunnel.cs @@ -52,8 +52,7 @@ private sealed class HttpProxyTunnel : Tunnel const string Prefix = "CONNECT ", Suffix = " HTTP/1.1\r\n\r\n", ExpectedResponse1 = "HTTP/1.1 200 OK\r\n\r\n", ExpectedResponse2 = "HTTP/1.1 200 Connection established\r\n\r\n"; byte[] chunk = ArrayPool.Shared.Rent(Math.Max( encoding.GetByteCount(Prefix) + encoding.GetByteCount(ep) + encoding.GetByteCount(Suffix), - Math.Max(encoding.GetByteCount(ExpectedResponse1), encoding.GetByteCount(ExpectedResponse2)) - )); + Math.Max(encoding.GetByteCount(ExpectedResponse1), encoding.GetByteCount(ExpectedResponse2)))); var offset = 0; offset += encoding.GetBytes(Prefix, 0, Prefix.Length, chunk, offset); offset += encoding.GetBytes(ep, 0, ep.Length, chunk, offset); diff --git a/src/StackExchange.Redis/ConfigurationOptions.cs b/src/StackExchange.Redis/ConfigurationOptions.cs index 4f3ff1287..e972962b2 100644 --- a/src/StackExchange.Redis/ConfigurationOptions.cs +++ b/src/StackExchange.Redis/ConfigurationOptions.cs @@ -63,7 +63,7 @@ internal static Proxy ParseProxy(string key, string value) internal static SslProtocols ParseSslProtocols(string key, string? value) { - //Flags expect commas as separators, but we need to use '|' since commas are already used in the connection string to mean something else + // Flags expect commas as separators, but we need to use '|' since commas are already used in the connection string to mean something else value = value?.Replace("|", ","); if (!Enum.TryParse(value, true, out SslProtocols tmp)) throw new ArgumentOutOfRangeException(key, $"Keyword '{key}' requires an SslProtocol value (multiple values separated by '|'); the value '{value}' is not recognised."); @@ -182,14 +182,14 @@ public static string TryNormalize(string value) /// A LocalCertificateSelectionCallback delegate responsible for selecting the certificate used for authentication; note /// that this cannot be specified in the configuration-string. /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly", Justification = "Existing compatibility")] public event LocalCertificateSelectionCallback? CertificateSelection; /// /// A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party; note /// that this cannot be specified in the configuration-string. /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly", Justification = "Existing compatibility")] public event RemoteCertificateValidationCallback? CertificateValidation; /// @@ -238,7 +238,7 @@ public int AsyncTimeout } /// - /// Indicates whether the connection should be encrypted + /// Indicates whether the connection should be encrypted. /// [Obsolete("Please use .Ssl instead of .UseSsl, will be removed in 3.0."), Browsable(false), @@ -258,7 +258,6 @@ public bool SetClientLibrary set => setClientLibrary = value; } - /// /// Gets or sets the library name to use for CLIENT SETINFO lib-name calls to Redis during handshake. /// Defaults to "SE.Redis". @@ -477,9 +476,9 @@ public bool HeartbeatConsistencyChecks /// /// Controls how often the connection heartbeats. A heartbeat includes: - /// - Evaluating if any messages have timed out - /// - Evaluating connection status (checking for failures) - /// - Sending a server message to keep the connection alive if needed + /// - Evaluating if any messages have timed out. + /// - Evaluating connection status (checking for failures). + /// - Sending a server message to keep the connection alive if needed. /// /// /// This defaults to 1000 milliseconds and should not be changed for most use cases. @@ -506,7 +505,7 @@ public bool HighPrioritySocketThreads } /// - /// Should exceptions include identifiable details? (key names, additional .Data annotations) + /// Whether exceptions include identifiable details (key names, additional .Data annotations). /// public bool IncludeDetailInExceptions { @@ -515,7 +514,7 @@ public bool IncludeDetailInExceptions } /// - /// Should exceptions include performance counter details? + /// Whether exceptions include performance counter details. /// /// /// CPU usage, etc - note that this can be problematic on some platforms. @@ -528,7 +527,7 @@ public bool IncludePerformanceCountersInExceptions /// /// Specifies the time in seconds at which connections should be pinged to ensure validity. - /// -1 Defaults to 60 Seconds + /// -1 Defaults to 60 Seconds. /// public int KeepAlive { @@ -1107,7 +1106,7 @@ private ConfigurationOptions DoParse(string configuration, bool ignoreUnknown) public Tunnel? Tunnel { get; set; } /// - /// Specify the redis protocol type + /// Specify the redis protocol type. /// public RedisProtocol? Protocol { get; set; } @@ -1115,12 +1114,12 @@ internal bool TryResp3() { // note: deliberately leaving the IsAvailable duplicated to use short-circuit - //if (Protocol is null) - //{ - // // if not specified, lean on the server version and whether HELLO is available - // return new RedisFeatures(DefaultVersion).Resp3 && CommandMap.IsAvailable(RedisCommand.HELLO); - //} - //else + // if (Protocol is null) + // { + // // if not specified, lean on the server version and whether HELLO is available + // return new RedisFeatures(DefaultVersion).Resp3 && CommandMap.IsAvailable(RedisCommand.HELLO); + // } + // else // ^^^ left for context; originally our intention was to auto-enable RESP3 by default *if* the server version // is >= 6; however, it turns out (see extensive conversation here https://github.com/StackExchange/StackExchange.Redis/pull/2396) // that tangential undocumented API breaks were made at the same time; this means that even if we fix every diff --git a/src/StackExchange.Redis/ConnectionCounters.cs b/src/StackExchange.Redis/ConnectionCounters.cs index 5be2ae488..546e2eff5 100644 --- a/src/StackExchange.Redis/ConnectionCounters.cs +++ b/src/StackExchange.Redis/ConnectionCounters.cs @@ -71,7 +71,7 @@ internal ConnectionCounters(ConnectionType connectionType) /// /// The number of subscriptions (with and without patterns) currently held against this connection. /// - public long Subscriptions { get;internal set; } + public long Subscriptions { get; internal set; } /// /// Indicates the total number of outstanding items against this connection. diff --git a/src/StackExchange.Redis/ConnectionFailedEventArgs.cs b/src/StackExchange.Redis/ConnectionFailedEventArgs.cs index 01f9ff408..5d165add1 100644 --- a/src/StackExchange.Redis/ConnectionFailedEventArgs.cs +++ b/src/StackExchange.Redis/ConnectionFailedEventArgs.cs @@ -32,7 +32,7 @@ internal ConnectionFailedEventArgs(EventHandler? hand /// The exception that occurred. /// Connection physical name. public ConnectionFailedEventArgs(object sender, EndPoint endPoint, ConnectionType connectionType, ConnectionFailureType failureType, Exception exception, string physicalName) - : this (null, sender, endPoint, connectionType, failureType, exception, physicalName) + : this(null, sender, endPoint, connectionType, failureType, exception, physicalName) { } diff --git a/src/StackExchange.Redis/ConnectionMultiplexer.ExportConfiguration.cs b/src/StackExchange.Redis/ConnectionMultiplexer.ExportConfiguration.cs index 55c8deefb..c095ffd53 100644 --- a/src/StackExchange.Redis/ConnectionMultiplexer.ExportConfiguration.cs +++ b/src/StackExchange.Redis/ConnectionMultiplexer.ExportConfiguration.cs @@ -98,7 +98,7 @@ public void ExportConfiguration(Stream destination, ExportOptions options = Expo } } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification = "We're not double disposing.")] private static void Write(ZipArchive zip, string name, Task task, Action callback) { var entry = zip.CreateEntry(name, CompressionLevel.Optimal); diff --git a/src/StackExchange.Redis/ConnectionMultiplexer.FeatureFlags.cs b/src/StackExchange.Redis/ConnectionMultiplexer.FeatureFlags.cs index a6c2168f6..975da5de1 100644 --- a/src/StackExchange.Redis/ConnectionMultiplexer.FeatureFlags.cs +++ b/src/StackExchange.Redis/ConnectionMultiplexer.FeatureFlags.cs @@ -19,7 +19,8 @@ private static void SetAutodetectFeatureFlags() { bool value = false; try - { // attempt to detect a known problem scenario + { + // attempt to detect a known problem scenario value = SynchronizationContext.Current?.GetType()?.Name == "LegacyAspNetSynchronizationContext"; } diff --git a/src/StackExchange.Redis/ConnectionMultiplexer.Profiling.cs b/src/StackExchange.Redis/ConnectionMultiplexer.Profiling.cs index b6ecbdf3f..c60966234 100644 --- a/src/StackExchange.Redis/ConnectionMultiplexer.Profiling.cs +++ b/src/StackExchange.Redis/ConnectionMultiplexer.Profiling.cs @@ -10,7 +10,7 @@ public partial class ConnectionMultiplexer /// /// Register a callback to provide an on-demand ambient session provider based on the /// calling context; the implementing code is responsible for reliably resolving the same provider - /// based on ambient context, or returning null to not profile + /// based on ambient context, or returning null to not profile. /// /// The session provider to register. public void RegisterProfiler(Func profilingSessionProvider) => _profilingSessionProvider = profilingSessionProvider; diff --git a/src/StackExchange.Redis/ConnectionMultiplexer.Sentinel.cs b/src/StackExchange.Redis/ConnectionMultiplexer.Sentinel.cs index 238c32bda..7753954d0 100644 --- a/src/StackExchange.Redis/ConnectionMultiplexer.Sentinel.cs +++ b/src/StackExchange.Redis/ConnectionMultiplexer.Sentinel.cs @@ -1,12 +1,12 @@ -using Microsoft.Extensions.Logging; -using Pipelines.Sockets.Unofficial; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Pipelines.Sockets.Unofficial; namespace StackExchange.Redis; @@ -33,33 +33,36 @@ internal void InitializeSentinel(ILogger? log) if (sub.SubscribedEndpoint(RedisChannel.Literal("+switch-master")) == null) { - sub.Subscribe(RedisChannel.Literal("+switch-master"), (__, message) => - { - string[] messageParts = ((string)message!).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); - // We don't care about the result of this - we're just trying - _ = Format.TryParseEndPoint(string.Format("{0}:{1}", messageParts[1], messageParts[2]), out var switchBlame); - - lock (sentinelConnectionChildren) + sub.Subscribe( + RedisChannel.Literal("+switch-master"), + (__, message) => { - // Switch the primary if we have connections for that service - if (sentinelConnectionChildren.ContainsKey(messageParts[0])) - { - ConnectionMultiplexer child = sentinelConnectionChildren[messageParts[0]]; + string[] messageParts = ((string)message!).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + // We don't care about the result of this - we're just trying + _ = Format.TryParseEndPoint(string.Format("{0}:{1}", messageParts[1], messageParts[2]), out var switchBlame); - // Is the connection still valid? - if (child.IsDisposed) - { - child.ConnectionFailed -= OnManagedConnectionFailed; - child.ConnectionRestored -= OnManagedConnectionRestored; - sentinelConnectionChildren.Remove(messageParts[0]); - } - else + lock (sentinelConnectionChildren) + { + // Switch the primary if we have connections for that service + if (sentinelConnectionChildren.ContainsKey(messageParts[0])) { - SwitchPrimary(switchBlame, sentinelConnectionChildren[messageParts[0]]); + ConnectionMultiplexer child = sentinelConnectionChildren[messageParts[0]]; + + // Is the connection still valid? + if (child.IsDisposed) + { + child.ConnectionFailed -= OnManagedConnectionFailed; + child.ConnectionRestored -= OnManagedConnectionRestored; + sentinelConnectionChildren.Remove(messageParts[0]); + } + else + { + SwitchPrimary(switchBlame, sentinelConnectionChildren[messageParts[0]]); + } } } - } - }, CommandFlags.FireAndForget); + }, + CommandFlags.FireAndForget); } // If we lose connection to a sentinel server, @@ -71,11 +74,14 @@ internal void InitializeSentinel(ILogger? log) // Subscribe to new sentinels being added if (sub.SubscribedEndpoint(RedisChannel.Literal("+sentinel")) == null) { - sub.Subscribe(RedisChannel.Literal("+sentinel"), (_, message) => - { - string[] messageParts = ((string)message!).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); - UpdateSentinelAddressList(messageParts[0]); - }, CommandFlags.FireAndForget); + sub.Subscribe( + RedisChannel.Literal("+sentinel"), + (_, message) => + { + string[] messageParts = ((string)message!).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + UpdateSentinelAddressList(messageParts[0]); + }, + CommandFlags.FireAndForget); } } @@ -164,7 +170,8 @@ public ConnectionMultiplexer GetSentinelMasterConnection(ConfigurationOptions co { if (ServerSelectionStrategy.ServerType != ServerType.Sentinel) { - throw new RedisConnectionException(ConnectionFailureType.UnableToConnect, + throw new RedisConnectionException( + ConnectionFailureType.UnableToConnect, "Sentinel: The ConnectionMultiplexer is not a Sentinel connection. Detected as: " + ServerSelectionStrategy.ServerType); } @@ -198,7 +205,8 @@ public ConnectionMultiplexer GetSentinelMasterConnection(ConfigurationOptions co if (newPrimaryEndPoint is null) { - throw new RedisConnectionException(ConnectionFailureType.UnableToConnect, + throw new RedisConnectionException( + ConnectionFailureType.UnableToConnect, $"Sentinel: Failed connecting to configured primary for service: {config.ServiceName}"); } @@ -241,11 +249,13 @@ public ConnectionMultiplexer GetSentinelMasterConnection(ConfigurationOptions co } Thread.Sleep(100); - } while (sw.ElapsedMilliseconds < config.ConnectTimeout); + } + while (sw.ElapsedMilliseconds < config.ConnectTimeout); if (!success) { - throw new RedisConnectionException(ConnectionFailureType.UnableToConnect, + throw new RedisConnectionException( + ConnectionFailureType.UnableToConnect, $"Sentinel: Failed connecting to configured primary for service: {config.ServiceName}"); } @@ -323,29 +333,33 @@ internal void OnManagedConnectionFailed(object? sender, ConnectionFailedEventArg // or if we miss the published primary change. if (connection.sentinelPrimaryReconnectTimer == null) { - connection.sentinelPrimaryReconnectTimer = new Timer(_ => - { - try - { - // Attempt, but do not fail here - SwitchPrimary(e.EndPoint, connection); - } - catch (Exception) - { - } - finally + connection.sentinelPrimaryReconnectTimer = new Timer( + _ => { try { - connection.sentinelPrimaryReconnectTimer?.Change(TimeSpan.FromSeconds(1), Timeout.InfiniteTimeSpan); + // Attempt, but do not fail here + SwitchPrimary(e.EndPoint, connection); } - catch (ObjectDisposedException) + catch (Exception) { - // If we get here the managed connection was restored and the timer was - // disposed by another thread, so there's no need to run the timer again. } - } - }, null, TimeSpan.Zero, Timeout.InfiniteTimeSpan); + finally + { + try + { + connection.sentinelPrimaryReconnectTimer?.Change(TimeSpan.FromSeconds(1), Timeout.InfiniteTimeSpan); + } + catch (ObjectDisposedException) + { + // If we get here the managed connection was restored and the timer was + // disposed by another thread, so there's no need to run the timer again. + } + } + }, + null, + TimeSpan.Zero, + Timeout.InfiniteTimeSpan); } } @@ -389,8 +403,7 @@ internal void SwitchPrimary(EndPoint? switchBlame, ConnectionMultiplexer connect // Get new primary - try twice EndPoint newPrimaryEndPoint = GetConfiguredPrimaryForService(serviceName) ?? GetConfiguredPrimaryForService(serviceName) - ?? throw new RedisConnectionException(ConnectionFailureType.UnableToConnect, - $"Sentinel: Failed connecting to switch primary for service: {serviceName}"); + ?? throw new RedisConnectionException(ConnectionFailureType.UnableToConnect, $"Sentinel: Failed connecting to switch primary for service: {serviceName}"); connection.currentSentinelPrimaryEndPoint = newPrimaryEndPoint; @@ -411,8 +424,14 @@ internal void SwitchPrimary(EndPoint? switchBlame, ConnectionMultiplexer connect } Trace($"Switching primary to {newPrimaryEndPoint}"); // Trigger a reconfigure - connection.ReconfigureAsync(first: false, reconfigureAll: false, logger, switchBlame, - $"Primary switch {serviceName}", false, CommandFlags.PreferMaster).Wait(); + connection.ReconfigureAsync( + first: false, + reconfigureAll: false, + log: logger, + blame: switchBlame, + cause: $"Primary switch {serviceName}", + publishReconfigure: false, + publishReconfigureFlags: CommandFlags.PreferMaster).Wait(); UpdateSentinelAddressList(serviceName); } diff --git a/src/StackExchange.Redis/ConnectionMultiplexer.StormLog.cs b/src/StackExchange.Redis/ConnectionMultiplexer.StormLog.cs index a32687b5d..51c62d00e 100644 --- a/src/StackExchange.Redis/ConnectionMultiplexer.StormLog.cs +++ b/src/StackExchange.Redis/ConnectionMultiplexer.StormLog.cs @@ -6,6 +6,7 @@ public partial class ConnectionMultiplexer { internal int haveStormLog = 0; internal string? stormLogSnapshot; + /// /// Limit at which to start recording unusual busy patterns (only one log will be retained at a time). /// Set to a negative value to disable this feature. diff --git a/src/StackExchange.Redis/ConnectionMultiplexer.cs b/src/StackExchange.Redis/ConnectionMultiplexer.cs index 022ae8cd9..8a4b8733d 100644 --- a/src/StackExchange.Redis/ConnectionMultiplexer.cs +++ b/src/StackExchange.Redis/ConnectionMultiplexer.cs @@ -1,7 +1,4 @@ -using Microsoft.Extensions.Logging; -using Pipelines.Sockets.Unofficial; -using StackExchange.Redis.Profiling; -using System; +using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; @@ -14,6 +11,9 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Pipelines.Sockets.Unofficial; +using StackExchange.Redis.Profiling; namespace StackExchange.Redis { @@ -70,9 +70,7 @@ pulse is null internal static long LastGlobalHeartbeatSecondsAgo => unchecked(Environment.TickCount - Thread.VolatileRead(ref lastGlobalHeartbeatTicks)) / 1000; - /// - /// Should exceptions include identifiable details? (key names, additional .Data annotations) - /// + /// [Obsolete($"Please use {nameof(ConfigurationOptions)}.{nameof(ConfigurationOptions.IncludeDetailInExceptions)} instead - this will be removed in 3.0.")] [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public bool IncludeDetailInExceptions @@ -81,12 +79,7 @@ public bool IncludeDetailInExceptions set => RawConfig.IncludeDetailInExceptions = value; } - /// - /// Should exceptions include performance counter details? - /// - /// - /// CPU usage, etc - note that this can be problematic on some platforms. - /// + /// [Obsolete($"Please use {nameof(ConfigurationOptions)}.{nameof(ConfigurationOptions.IncludePerformanceCountersInExceptions)} instead - this will be removed in 3.0.")] [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public bool IncludePerformanceCountersInExceptions @@ -858,7 +851,7 @@ public bool Any(Func? predicate = null) public ServerSnapshotFiltered Where(CommandFlags flags) { var effectiveFlags = flags & (CommandFlags.DemandMaster | CommandFlags.DemandReplica); - return (effectiveFlags) switch + return effectiveFlags switch { CommandFlags.DemandMaster => Where(static s => !s.IsReplica), CommandFlags.DemandReplica => Where(static s => s.IsReplica), @@ -1021,7 +1014,6 @@ public void Dispose() // outstanding messages; if the consumer has dropped the multiplexer, then // there will be no new incoming messages, and after timeouts: everything // should drop. - public void Root(ConnectionMultiplexer multiplexer) { lock (StrongRefSyncLock) @@ -1074,7 +1066,8 @@ private void OnHeartbeat() } } if (isRooted && !hasPendingCallerFacingItems) - { // release the GC root on the heartbeat *if* the token still matches + { + // release the GC root on the heartbeat *if* the token still matches pulse?.UnRoot(token); } } @@ -1483,7 +1476,7 @@ internal async Task ReconfigureAsync(bool first, bool reconfigureAll, ILog Trace("Testing: " + Format.ToString(endpoints[i])); var server = GetServerEndPoint(endpoints[i]); - //server.ReportNextFailure(); + // server.ReportNextFailure(); servers[i] = server; // This awaits either the endpoint's initial connection, or a tracer if we're already connected @@ -1695,8 +1688,9 @@ internal async Task ReconfigureAsync(bool first, bool reconfigureAll, ILog ResetAllNonConnected(); log?.LogInformation($" Retrying - attempts left: {attemptsLeft}..."); } - //WTF("?: " + attempts); - } while (first && !healthy && attemptsLeft > 0); + // WTF("?: " + attempts); + } + while (first && !healthy && attemptsLeft > 0); if (first && RawConfig.AbortOnConnectFail && !healthy) { diff --git a/src/StackExchange.Redis/CursorEnumerable.cs b/src/StackExchange.Redis/CursorEnumerable.cs index efe2db61a..55d93d6a6 100644 --- a/src/StackExchange.Redis/CursorEnumerable.cs +++ b/src/StackExchange.Redis/CursorEnumerable.cs @@ -12,6 +12,7 @@ namespace StackExchange.Redis /// /// Provides the ability to iterate over a cursor-based sequence of redis data, synchronously or asynchronously. /// + /// The type of the data in the cursor. internal abstract class CursorEnumerable : IEnumerable, IScanningCursor, IAsyncEnumerable { private readonly RedisBase redis; @@ -91,7 +92,8 @@ internal Enumerator(CursorEnumerable parent, CancellationToken cancellationTo /// /// Gets the current value of the enumerator. /// - public T Current { + public T Current + { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { @@ -165,7 +167,7 @@ private void ProcessReply(in ScanResult result, bool isInitial) { _currentCursor = _nextCursor; _nextCursor = result.Cursor; - _pageOffset = isInitial ? parent.initialOffset - 1 : -1; + _pageOffset = isInitial ? parent.initialOffset - 1 : -1; Recycle(ref _pageOversized, ref _isPooled); // recycle any existing data _pageOversized = result.ValuesOversized ?? Array.Empty(); _isPooled = result.IsPooled; @@ -206,7 +208,7 @@ private protected TResult Wait(Task pending, Message message) /// public ValueTask MoveNextAsync() { - if(SimpleNext()) return new ValueTask(true); + if (SimpleNext()) return new ValueTask(true); return SlowNextAsync(); } @@ -274,7 +276,7 @@ private async ValueTask AwaitedNextAsync(bool isInitial) { scanResult = await pending.ForAwait(); } - catch(Exception ex) + catch (Exception ex) { TryAppendExceptionState(ex); throw; @@ -344,8 +346,8 @@ internal static CursorEnumerable From(RedisBase redis, ServerEndPoint? server private class SingleBlockEnumerable : CursorEnumerable { private readonly Task _pending; - public SingleBlockEnumerable(RedisBase redis, ServerEndPoint? server, - Task pending, int pageOffset) : base(redis, server, 0, int.MaxValue, 0, pageOffset, default) + public SingleBlockEnumerable(RedisBase redis, ServerEndPoint? server, Task pending, int pageOffset) + : base(redis, server, 0, int.MaxValue, 0, pageOffset, default) { _pending = pending; } diff --git a/src/StackExchange.Redis/EndPointCollection.cs b/src/StackExchange.Redis/EndPointCollection.cs index 44fd67e79..cf4c844c1 100644 --- a/src/StackExchange.Redis/EndPointCollection.cs +++ b/src/StackExchange.Redis/EndPointCollection.cs @@ -1,10 +1,10 @@ -using Microsoft.Extensions.Logging; -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Net; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; namespace StackExchange.Redis { @@ -23,13 +23,13 @@ private static class DefaultPorts /// /// Create a new . /// - public EndPointCollection() {} + public EndPointCollection() { } /// /// Create a new . /// /// The endpoints to add to the collection. - public EndPointCollection(IList endpoints) : base(endpoints) {} + public EndPointCollection(IList endpoints) : base(endpoints) { } /// /// Format an . @@ -165,7 +165,7 @@ internal void SetDefaultPorts(ServerType? serverType, bool ssl = false) IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - /// + /// public new IEnumerator GetEnumerator() { // this does *not* need to handle all threading scenarios; but we do diff --git a/src/StackExchange.Redis/EndPointEventArgs.cs b/src/StackExchange.Redis/EndPointEventArgs.cs index 5f8cc6b18..bef0db9b6 100644 --- a/src/StackExchange.Redis/EndPointEventArgs.cs +++ b/src/StackExchange.Redis/EndPointEventArgs.cs @@ -11,6 +11,7 @@ public class EndPointEventArgs : EventArgs, ICompletable { private readonly EventHandler? handler; private readonly object sender; + internal EndPointEventArgs(EventHandler? handler, object sender, EndPoint endpoint) { this.handler = handler; @@ -24,7 +25,7 @@ internal EndPointEventArgs(EventHandler? handler, object send /// The source of the event. /// Redis endpoint. public EndPointEventArgs(object sender, EndPoint endpoint) - : this (null, sender, endpoint) + : this(null, sender, endpoint) { } diff --git a/src/StackExchange.Redis/Enums/Aggregate.cs b/src/StackExchange.Redis/Enums/Aggregate.cs index 0c4d890fa..41e1d435d 100644 --- a/src/StackExchange.Redis/Enums/Aggregate.cs +++ b/src/StackExchange.Redis/Enums/Aggregate.cs @@ -9,13 +9,15 @@ public enum Aggregate /// The values of the combined elements are added. /// Sum, + /// /// The least value of the combined elements is used. /// Min, + /// /// The greatest value of the combined elements is used. /// - Max + Max, } } diff --git a/src/StackExchange.Redis/Enums/Bitwise.cs b/src/StackExchange.Redis/Enums/Bitwise.cs index ada2e99c5..b38423eac 100644 --- a/src/StackExchange.Redis/Enums/Bitwise.cs +++ b/src/StackExchange.Redis/Enums/Bitwise.cs @@ -9,14 +9,17 @@ public enum Bitwise /// And /// And, + /// /// Or /// Or, + /// /// Xor /// Xor, + /// /// Not /// diff --git a/src/StackExchange.Redis/Enums/ClientFlags.cs b/src/StackExchange.Redis/Enums/ClientFlags.cs index 50d32261b..eb687bba6 100644 --- a/src/StackExchange.Redis/Enums/ClientFlags.cs +++ b/src/StackExchange.Redis/Enums/ClientFlags.cs @@ -85,74 +85,91 @@ public enum ClientFlags : long /// No specific flag set. /// None = 0, + /// /// The client is a replica in MONITOR mode. /// [Obsolete("Starting with Redis version 5, Redis has moved to 'replica' terminology. Please use " + nameof(ReplicaMonitor) + " instead, this will be removed in 3.0.")] [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] SlaveMonitor = 1, + /// /// The client is a replica in MONITOR mode. /// ReplicaMonitor = 1, // as an implementation detail, note that enum.ToString on [Flags] prefers *later* options when naming Flags + /// /// The client is a normal replica server. /// [Obsolete("Starting with Redis version 5, Redis has moved to 'replica' terminology. Please use " + nameof(Replica) + " instead, this will be removed in 3.0.")] [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] Slave = 2, + /// /// The client is a normal replica server. /// Replica = 2, // as an implementation detail, note that enum.ToString on [Flags] prefers *later* options when naming Flags + /// /// The client is a primary. /// Master = 4, + /// /// The client is in a MULTI/EXEC context. /// Transaction = 8, + /// /// The client is waiting in a blocking operation. /// Blocked = 16, + /// /// A watched keys has been modified - EXEC will fail. /// TransactionDoomed = 32, + /// /// Connection to be closed after writing entire reply. /// Closing = 64, + /// /// The client is unblocked. /// Unblocked = 128, + /// /// Connection to be closed ASAP. /// CloseASAP = 256, + /// /// The client is a Pub/Sub subscriber. /// PubSubSubscriber = 512, + /// /// The client is in readonly mode against a cluster node. /// ReadOnlyCluster = 1024, + /// /// The client is connected via a Unix domain socket. /// UnixDomainSocket = 2048, + /// /// The client enabled keys tracking in order to perform client side caching. /// KeysTracking = 4096, + /// /// The client tracking target client is invalid. /// TrackingTargetInvalid = 8192, + /// /// The client enabled broadcast tracking mode. /// diff --git a/src/StackExchange.Redis/Enums/ClientType.cs b/src/StackExchange.Redis/Enums/ClientType.cs index 498c7dd70..c2b003d9a 100644 --- a/src/StackExchange.Redis/Enums/ClientType.cs +++ b/src/StackExchange.Redis/Enums/ClientType.cs @@ -4,27 +4,30 @@ namespace StackExchange.Redis { /// - /// The class of the connection + /// The class of the connection. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1069:Enums values should not be duplicated", Justification = "Compatibility")] public enum ClientType { /// - /// Regular connections, including MONITOR connections + /// Regular connections, including MONITOR connections. /// Normal = 0, + /// - /// Replication connections + /// Replication connections. /// Replica = 1, // as an implementation detail, note that enum.ToString without [Flags] prefers *earlier* values + /// - /// Replication connections + /// Replication connections. /// [Obsolete("Starting with Redis version 5, Redis has moved to 'replica' terminology. Please use " + nameof(Replica) + " instead, this will be removed in 3.0.")] [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] Slave = 1, + /// - /// Subscription connections + /// Subscription connections. /// PubSub = 2, } diff --git a/src/StackExchange.Redis/Enums/CommandFlags.cs b/src/StackExchange.Redis/Enums/CommandFlags.cs index 95e815a3a..bafaee70f 100644 --- a/src/StackExchange.Redis/Enums/CommandFlags.cs +++ b/src/StackExchange.Redis/Enums/CommandFlags.cs @@ -4,7 +4,7 @@ namespace StackExchange.Redis { /// - /// Behaviour markers associated with a given command + /// Behaviour markers associated with a given command. /// [Flags] [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1069:Enums values should not be duplicated", Justification = "Compatibility")] @@ -16,11 +16,12 @@ public enum CommandFlags None = 0, /// - /// From 2.0, this flag is not used + /// From 2.0, this flag is not used. /// [Obsolete("From 2.0, this flag is not used, this will be removed in 3.0.", false)] [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] HighPriority = 1, + /// /// The caller is not interested in the result; the caller will immediately receive a default-value /// of the expected return type (this value is not indicative of anything at the server). @@ -69,7 +70,7 @@ public enum CommandFlags // 32: used for "asking" flag; never user-specified, so not visible on the public API /// - /// Indicates that this operation should not be forwarded to other servers as a result of an ASK or MOVED response + /// Indicates that this operation should not be forwarded to other servers as a result of an ASK or MOVED response. /// NoRedirect = 64, @@ -78,7 +79,7 @@ public enum CommandFlags // 256: used for "script unavailable"; never user-specified, so not visible on the public API /// - /// Indicates that script-related operations should use EVAL, not SCRIPT LOAD + EVALSHA + /// Indicates that script-related operations should use EVAL, not SCRIPT LOAD + EVALSHA. /// NoScriptCache = 512, diff --git a/src/StackExchange.Redis/Enums/CommandStatus.cs b/src/StackExchange.Redis/Enums/CommandStatus.cs index 472c96dfc..c4de5753d 100644 --- a/src/StackExchange.Redis/Enums/CommandStatus.cs +++ b/src/StackExchange.Redis/Enums/CommandStatus.cs @@ -9,14 +9,17 @@ public enum CommandStatus /// Command status unknown. /// Unknown, + /// /// ConnectionMultiplexer has not yet started writing this command to Redis. /// WaitingToBeSent, + /// /// Command has been sent to Redis. /// Sent, + /// /// Command is in the backlog, waiting to be processed and written to Redis. /// diff --git a/src/StackExchange.Redis/Enums/ConnectionFailureType.cs b/src/StackExchange.Redis/Enums/ConnectionFailureType.cs index d9407b69e..55eeacef6 100644 --- a/src/StackExchange.Redis/Enums/ConnectionFailureType.cs +++ b/src/StackExchange.Redis/Enums/ConnectionFailureType.cs @@ -9,44 +9,54 @@ public enum ConnectionFailureType /// This event is not a failure. /// None, + /// /// No viable connections were available for this operation. /// UnableToResolvePhysicalConnection, + /// /// The socket for this connection failed. /// SocketFailure, + /// /// Either SSL Stream or Redis authentication failed. /// AuthenticationFailure, + /// /// An unexpected response was received from the server. /// ProtocolFailure, + /// /// An unknown internal error occurred. /// InternalFailure, + /// /// The socket was closed. /// SocketClosed, + /// /// The socket was closed. /// ConnectionDisposed, + /// /// The database is loading and is not available for use. /// Loading, + /// /// It has not been possible to create an initial connection to the redis server(s). /// UnableToConnect, + /// - /// High-integrity mode was enabled, and a failure was detected + /// High-integrity mode was enabled, and a failure was detected. /// ResponseIntegrityFailure, } diff --git a/src/StackExchange.Redis/Enums/ConnectionType.cs b/src/StackExchange.Redis/Enums/ConnectionType.cs index ead82f222..8db655c08 100644 --- a/src/StackExchange.Redis/Enums/ConnectionType.cs +++ b/src/StackExchange.Redis/Enums/ConnectionType.cs @@ -9,13 +9,15 @@ public enum ConnectionType /// Not connection-type related. /// None = 0, + /// /// An interactive connection handles request/response commands for accessing data on demand. /// Interactive, + /// /// A subscriber connection receives unsolicited messages from the server as pub/sub events occur. /// - Subscription + Subscription, } } diff --git a/src/StackExchange.Redis/Enums/Exclude.cs b/src/StackExchange.Redis/Enums/Exclude.cs index 4da2e9ef4..912a2af95 100644 --- a/src/StackExchange.Redis/Enums/Exclude.cs +++ b/src/StackExchange.Redis/Enums/Exclude.cs @@ -13,17 +13,20 @@ public enum Exclude /// Both start and stop are inclusive. /// None = 0, + /// /// Start is exclusive, stop is inclusive. /// Start = 1, + /// /// Start is inclusive, stop is exclusive. /// Stop = 2, + /// /// Both start and stop are exclusive. /// - Both = Start | Stop + Both = Start | Stop, } } diff --git a/src/StackExchange.Redis/Enums/ExpireWhen.cs b/src/StackExchange.Redis/Enums/ExpireWhen.cs index 0ed3782bc..2637e7625 100644 --- a/src/StackExchange.Redis/Enums/ExpireWhen.cs +++ b/src/StackExchange.Redis/Enums/ExpireWhen.cs @@ -11,20 +11,24 @@ public enum ExpireWhen /// Set expiry whether or not there is an existing expiry. /// Always, + /// /// Set expiry only when the new expiry is greater than current one. /// GreaterThanCurrentExpiry, + /// /// Set expiry only when the key has an existing expiry. /// HasExpiry, + /// /// Set expiry only when the key has no expiry. /// HasNoExpiry, + /// - /// Set expiry only when the new expiry is less than current one + /// Set expiry only when the new expiry is less than current one. /// LessThanCurrentExpiry, } @@ -37,6 +41,6 @@ internal static class ExpiryOptionExtensions ExpireWhen.HasExpiry => RedisLiterals.XX, ExpireWhen.GreaterThanCurrentExpiry => RedisLiterals.GT, ExpireWhen.LessThanCurrentExpiry => RedisLiterals.LT, - _ => throw new ArgumentOutOfRangeException(nameof(op)) + _ => throw new ArgumentOutOfRangeException(nameof(op)), }; } diff --git a/src/StackExchange.Redis/Enums/ExportOptions.cs b/src/StackExchange.Redis/Enums/ExportOptions.cs index fd29dd388..594651955 100644 --- a/src/StackExchange.Redis/Enums/ExportOptions.cs +++ b/src/StackExchange.Redis/Enums/ExportOptions.cs @@ -12,25 +12,30 @@ public enum ExportOptions /// No options. /// None = 0, + /// /// The output of INFO. /// Info = 1, + /// /// The output of CONFIG GET *. /// Config = 2, + /// /// The output of CLIENT LIST. /// Client = 4, + /// /// The output of CLUSTER NODES. /// Cluster = 8, + /// /// Everything available. /// - All = -1 + All = -1, } } diff --git a/src/StackExchange.Redis/Enums/GeoUnit.cs b/src/StackExchange.Redis/Enums/GeoUnit.cs index 3f5104742..99ab0a143 100644 --- a/src/StackExchange.Redis/Enums/GeoUnit.cs +++ b/src/StackExchange.Redis/Enums/GeoUnit.cs @@ -8,19 +8,22 @@ namespace StackExchange.Redis public enum GeoUnit { /// - /// Meters + /// Meters. /// Meters, + /// - /// Kilometers + /// Kilometers. /// Kilometers, + /// - /// Miles + /// Miles. /// Miles, + /// - /// Feet + /// Feet. /// Feet, } @@ -33,7 +36,7 @@ internal static class GeoUnitExtensions GeoUnit.Kilometers => RedisLiterals.km, GeoUnit.Meters => RedisLiterals.m, GeoUnit.Miles => RedisLiterals.mi, - _ => throw new ArgumentOutOfRangeException(nameof(unit)) + _ => throw new ArgumentOutOfRangeException(nameof(unit)), }; } } diff --git a/src/StackExchange.Redis/Enums/ListSide.cs b/src/StackExchange.Redis/Enums/ListSide.cs index dfb74383d..8d326a8af 100644 --- a/src/StackExchange.Redis/Enums/ListSide.cs +++ b/src/StackExchange.Redis/Enums/ListSide.cs @@ -11,6 +11,7 @@ public enum ListSide /// The head of the list. /// Left, + /// /// The tail of the list. /// @@ -23,7 +24,7 @@ internal static class ListSideExtensions { ListSide.Left => RedisLiterals.LEFT, ListSide.Right => RedisLiterals.RIGHT, - _ => throw new ArgumentOutOfRangeException(nameof(side)) + _ => throw new ArgumentOutOfRangeException(nameof(side)), }; } } diff --git a/src/StackExchange.Redis/Enums/MigrateOptions.cs b/src/StackExchange.Redis/Enums/MigrateOptions.cs index 561b5494d..fbfdaa731 100644 --- a/src/StackExchange.Redis/Enums/MigrateOptions.cs +++ b/src/StackExchange.Redis/Enums/MigrateOptions.cs @@ -12,10 +12,12 @@ public enum MigrateOptions /// No options specified. /// None = 0, + /// /// Do not remove the key from the local instance. /// Copy = 1, + /// /// Replace existing key on the remote instance. /// diff --git a/src/StackExchange.Redis/Enums/Order.cs b/src/StackExchange.Redis/Enums/Order.cs index be3dd0a8b..99d989006 100644 --- a/src/StackExchange.Redis/Enums/Order.cs +++ b/src/StackExchange.Redis/Enums/Order.cs @@ -11,6 +11,7 @@ public enum Order /// Ordered from low values to high values. /// Ascending, + /// /// Ordered from high values to low values. /// @@ -23,7 +24,7 @@ internal static class OrderExtensions { Order.Ascending => RedisLiterals.ASC, Order.Descending => RedisLiterals.DESC, - _ => throw new ArgumentOutOfRangeException(nameof(order)) + _ => throw new ArgumentOutOfRangeException(nameof(order)), }; } } diff --git a/src/StackExchange.Redis/Enums/Proxy.cs b/src/StackExchange.Redis/Enums/Proxy.cs index f529ac123..9dc1d3770 100644 --- a/src/StackExchange.Redis/Enums/Proxy.cs +++ b/src/StackExchange.Redis/Enums/Proxy.cs @@ -9,10 +9,12 @@ public enum Proxy /// Direct communication to the redis server(s). /// None, + /// /// Communication via twemproxy. /// Twemproxy, + /// /// Communication via envoyproxy. /// @@ -28,7 +30,7 @@ internal static class ProxyExtensions { Proxy.Twemproxy => false, Proxy.Envoyproxy => false, - _ => true + _ => true, }; /// @@ -38,7 +40,7 @@ internal static class ProxyExtensions { Proxy.Twemproxy => false, Proxy.Envoyproxy => false, - _ => true + _ => true, }; /// @@ -48,7 +50,7 @@ internal static class ProxyExtensions { Proxy.Twemproxy => false, Proxy.Envoyproxy => false, - _ => true + _ => true, }; } } diff --git a/src/StackExchange.Redis/Enums/RedisType.cs b/src/StackExchange.Redis/Enums/RedisType.cs index b061dc906..f1da87505 100644 --- a/src/StackExchange.Redis/Enums/RedisType.cs +++ b/src/StackExchange.Redis/Enums/RedisType.cs @@ -10,6 +10,7 @@ public enum RedisType /// The specified key does not exist. /// None, + /// /// Strings are the most basic kind of Redis value. Redis Strings are binary safe, this means that /// a Redis string can contain any kind of data, for instance a JPEG image or a serialized Ruby object. @@ -17,6 +18,7 @@ public enum RedisType /// /// String, + /// /// Redis Lists are simply lists of strings, sorted by insertion order. /// It is possible to add elements to a Redis List pushing new elements on the head (on the left) or @@ -24,6 +26,7 @@ public enum RedisType /// /// List, + /// /// Redis Sets are an unordered collection of Strings. It is possible to add, remove, and test for /// existence of members in O(1) (constant time regardless of the number of elements contained inside the Set). @@ -33,6 +36,7 @@ public enum RedisType /// /// Set, + /// /// Redis Sorted Sets are, similarly to Redis Sets, non repeating collections of Strings. /// The difference is that every member of a Sorted Set is associated with score, that is used @@ -41,12 +45,14 @@ public enum RedisType /// /// SortedSet, + /// /// Redis Hashes are maps between string fields and string values, so they are the perfect data type /// to represent objects (e.g. A User with a number of fields like name, surname, age, and so forth). /// /// Hash, + /// /// A Redis Stream is a data structure which models the behavior of an append only log but it has more /// advanced features for manipulating the data contained within the stream. Each entry in a @@ -54,6 +60,7 @@ public enum RedisType /// /// Stream, + /// /// The data-type was not recognised by the client library. /// diff --git a/src/StackExchange.Redis/Enums/ReplicationChangeOptions.cs b/src/StackExchange.Redis/Enums/ReplicationChangeOptions.cs index 12f84ffba..897ebbb6c 100644 --- a/src/StackExchange.Redis/Enums/ReplicationChangeOptions.cs +++ b/src/StackExchange.Redis/Enums/ReplicationChangeOptions.cs @@ -14,24 +14,29 @@ public enum ReplicationChangeOptions /// No additional operations. /// None = 0, + /// /// Set the tie-breaker key on all available primaries, to specify this server. /// SetTiebreaker = 1, + /// /// Broadcast to the pub-sub channel to listening clients to reconfigure themselves. /// Broadcast = 2, + /// /// Issue a REPLICAOF to all other known nodes, making this primary of all. /// [Obsolete("Starting with Redis version 5, Redis has moved to 'replica' terminology. Please use " + nameof(ReplicateToOtherEndpoints) + " instead, this will be removed in 3.0.")] [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] EnslaveSubordinates = 4, + /// /// Issue a REPLICAOF to all other known nodes, making this primary of all. /// ReplicateToOtherEndpoints = 4, // note ToString prefers *later* options + /// /// All additional operations. /// diff --git a/src/StackExchange.Redis/Enums/ResultType.cs b/src/StackExchange.Redis/Enums/ResultType.cs index ca09f64b0..63e267a91 100644 --- a/src/StackExchange.Redis/Enums/ResultType.cs +++ b/src/StackExchange.Redis/Enums/ResultType.cs @@ -19,14 +19,17 @@ public enum ResultType : byte /// Basic strings typically represent status results such as "OK". /// SimpleString = 1, + /// /// Error strings represent invalid operation results from the server. /// Error = 2, + /// /// Integers are returned for count operations and some integer-based increment operations. /// Integer = 3, + /// /// Bulk strings represent typical user content values. /// @@ -65,7 +68,7 @@ public enum ResultType : byte Double = (1 << 3) | SimpleString, /// - /// A large number non representable by the type + /// A large number non representable by the type. /// BigInteger = (2 << 3) | SimpleString, diff --git a/src/StackExchange.Redis/Enums/RetransmissionReasonType.cs b/src/StackExchange.Redis/Enums/RetransmissionReasonType.cs index 18529b029..6bd9d43e6 100644 --- a/src/StackExchange.Redis/Enums/RetransmissionReasonType.cs +++ b/src/StackExchange.Redis/Enums/RetransmissionReasonType.cs @@ -16,10 +16,12 @@ public enum RetransmissionReasonType /// No stated reason. /// None = 0, + /// /// Issued to investigate which node owns a key. /// Ask, + /// /// A node has indicated that it does *not* own the given key. /// diff --git a/src/StackExchange.Redis/Enums/SaveType.cs b/src/StackExchange.Redis/Enums/SaveType.cs index 740e262a9..5296d110e 100644 --- a/src/StackExchange.Redis/Enums/SaveType.cs +++ b/src/StackExchange.Redis/Enums/SaveType.cs @@ -13,6 +13,7 @@ public enum SaveType /// /// BackgroundRewriteAppendOnlyFile, + /// /// Save the DB in background. The OK code is immediately returned. /// Redis forks, the parent continues to serve the clients, the child saves the DB on disk then exits. @@ -20,6 +21,7 @@ public enum SaveType /// /// BackgroundSave, + /// /// Save the DB in foreground. /// This is almost never a good thing to do, and could cause significant blocking. diff --git a/src/StackExchange.Redis/Enums/ServerType.cs b/src/StackExchange.Redis/Enums/ServerType.cs index 19c6a3f19..ef49a8449 100644 --- a/src/StackExchange.Redis/Enums/ServerType.cs +++ b/src/StackExchange.Redis/Enums/ServerType.cs @@ -9,18 +9,22 @@ public enum ServerType /// Classic redis-server server. /// Standalone, + /// /// Monitoring/configuration redis-sentinel server. /// Sentinel, + /// /// Distributed redis-cluster server. /// Cluster, + /// /// Distributed redis installation via twemproxy. /// Twemproxy, + /// /// Redis cluster via envoyproxy. /// @@ -35,7 +39,7 @@ internal static class ServerTypeExtensions internal static bool HasSinglePrimary(this ServerType type) => type switch { ServerType.Envoyproxy => false, - _ => true + _ => true, }; /// @@ -45,7 +49,7 @@ internal static class ServerTypeExtensions { ServerType.Twemproxy => false, ServerType.Envoyproxy => false, - _ => true + _ => true, }; } } diff --git a/src/StackExchange.Redis/Enums/SetOperation.cs b/src/StackExchange.Redis/Enums/SetOperation.cs index 7e649847f..a529d348e 100644 --- a/src/StackExchange.Redis/Enums/SetOperation.cs +++ b/src/StackExchange.Redis/Enums/SetOperation.cs @@ -11,10 +11,12 @@ public enum SetOperation /// Returns the members of the set resulting from the union of all the given sets. /// Union, + /// /// Returns the members of the set resulting from the intersection of all the given sets. /// Intersect, + /// /// Returns the members of the set resulting from the difference between the first set and all the successive sets. /// @@ -25,12 +27,12 @@ internal static class SetOperationExtensions { internal static RedisCommand ToCommand(this SetOperation operation, bool store) => operation switch { - SetOperation.Intersect when store => RedisCommand.ZINTERSTORE, - SetOperation.Intersect => RedisCommand.ZINTER, - SetOperation.Union when store => RedisCommand.ZUNIONSTORE, - SetOperation.Union => RedisCommand.ZUNION, + SetOperation.Intersect when store => RedisCommand.ZINTERSTORE, + SetOperation.Intersect => RedisCommand.ZINTER, + SetOperation.Union when store => RedisCommand.ZUNIONSTORE, + SetOperation.Union => RedisCommand.ZUNION, SetOperation.Difference when store => RedisCommand.ZDIFFSTORE, - SetOperation.Difference => RedisCommand.ZDIFF, + SetOperation.Difference => RedisCommand.ZDIFF, _ => throw new ArgumentOutOfRangeException(nameof(operation)), }; } diff --git a/src/StackExchange.Redis/Enums/ShutdownMode.cs b/src/StackExchange.Redis/Enums/ShutdownMode.cs index dfd46b70f..a8b701ea8 100644 --- a/src/StackExchange.Redis/Enums/ShutdownMode.cs +++ b/src/StackExchange.Redis/Enums/ShutdownMode.cs @@ -9,10 +9,12 @@ public enum ShutdownMode /// The data is persisted if save points are configured. /// Default, + /// /// The data is NOT persisted even if save points are configured. /// Never, + /// /// The data is persisted even if save points are NOT configured. /// diff --git a/src/StackExchange.Redis/Enums/SimulatedFailureType.cs b/src/StackExchange.Redis/Enums/SimulatedFailureType.cs index 80fca095c..7f2968eca 100644 --- a/src/StackExchange.Redis/Enums/SimulatedFailureType.cs +++ b/src/StackExchange.Redis/Enums/SimulatedFailureType.cs @@ -5,10 +5,10 @@ namespace StackExchange.Redis [Flags] internal enum SimulatedFailureType { - None = 0, - InteractiveInbound = 1 << 0, - InteractiveOutbound = 1 << 1, - SubscriptionInbound = 1 << 2, + None = 0, + InteractiveInbound = 1 << 0, + InteractiveOutbound = 1 << 1, + SubscriptionInbound = 1 << 2, SubscriptionOutbound = 1 << 3, AllInbound = InteractiveInbound | SubscriptionInbound, diff --git a/src/StackExchange.Redis/Enums/SortType.cs b/src/StackExchange.Redis/Enums/SortType.cs index 9fc3a20ae..48a3596b6 100644 --- a/src/StackExchange.Redis/Enums/SortType.cs +++ b/src/StackExchange.Redis/Enums/SortType.cs @@ -9,6 +9,7 @@ public enum SortType /// Elements are interpreted as a double-precision floating point number and sorted numerically. /// Numeric, + /// /// Elements are sorted using their alphabetic form /// (Redis is UTF-8 aware as long as the !LC_COLLATE environment variable is set at the server). diff --git a/src/StackExchange.Redis/Enums/SortedSetOrder.cs b/src/StackExchange.Redis/Enums/SortedSetOrder.cs index 6c205bae0..474cd3612 100644 --- a/src/StackExchange.Redis/Enums/SortedSetOrder.cs +++ b/src/StackExchange.Redis/Enums/SortedSetOrder.cs @@ -16,7 +16,7 @@ public enum SortedSetOrder ByScore, /// - /// Bases ordering off of lexicographical order, this is only appropriate in an instance where all the members of your sorted set are given the same score + /// Bases ordering off of lexicographical order, this is only appropriate in an instance where all the members of your sorted set are given the same score. /// ByLex, } @@ -27,6 +27,6 @@ internal static class SortedSetOrderByExtensions { SortedSetOrder.ByLex => RedisLiterals.BYLEX, SortedSetOrder.ByScore => RedisLiterals.BYSCORE, - _ => RedisValue.Null + _ => RedisValue.Null, }; } diff --git a/src/StackExchange.Redis/Enums/SortedSetWhen.cs b/src/StackExchange.Redis/Enums/SortedSetWhen.cs index a394482b6..517aaeaa5 100644 --- a/src/StackExchange.Redis/Enums/SortedSetWhen.cs +++ b/src/StackExchange.Redis/Enums/SortedSetWhen.cs @@ -12,18 +12,22 @@ public enum SortedSetWhen /// The operation won't be prevented. /// Always = 0, + /// /// The operation should only occur when there is an existing value. /// Exists = 1 << 0, + /// /// The operation should only occur when the new score is greater than the current score. /// GreaterThan = 1 << 1, + /// /// The operation should only occur when the new score is less than the current score. /// LessThan = 1 << 2, + /// /// The operation should only occur when there is not an existing value. /// @@ -35,18 +39,18 @@ internal static class SortedSetWhenExtensions internal static uint CountBits(this SortedSetWhen when) { uint v = (uint)when; - v -= ((v >> 1) & 0x55555555); // reuse input as temporary + v -= (v >> 1) & 0x55555555; // reuse input as temporary v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp uint c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count return c; } - internal static SortedSetWhen Parse(When when)=> when switch + internal static SortedSetWhen Parse(When when) => when switch { When.Always => SortedSetWhen.Always, When.Exists => SortedSetWhen.Exists, When.NotExists => SortedSetWhen.NotExists, - _ => throw new ArgumentOutOfRangeException(nameof(when)) + _ => throw new ArgumentOutOfRangeException(nameof(when)), }; } } diff --git a/src/StackExchange.Redis/Enums/StringIndexType.cs b/src/StackExchange.Redis/Enums/StringIndexType.cs index deb180404..fcb41e391 100644 --- a/src/StackExchange.Redis/Enums/StringIndexType.cs +++ b/src/StackExchange.Redis/Enums/StringIndexType.cs @@ -11,6 +11,7 @@ public enum StringIndexType /// Indicates the index is the number of bytes into a string. /// Byte, + /// /// Indicates the index is the number of bits into a string. /// @@ -23,6 +24,6 @@ internal static class StringIndexTypeExtensions { StringIndexType.Bit => RedisLiterals.BIT, StringIndexType.Byte => RedisLiterals.BYTE, - _ => throw new ArgumentOutOfRangeException(nameof(indexType)) + _ => throw new ArgumentOutOfRangeException(nameof(indexType)), }; } diff --git a/src/StackExchange.Redis/Enums/When.cs b/src/StackExchange.Redis/Enums/When.cs index d0bc5d303..412e4064a 100644 --- a/src/StackExchange.Redis/Enums/When.cs +++ b/src/StackExchange.Redis/Enums/When.cs @@ -9,10 +9,12 @@ public enum When /// The operation should occur whether or not there is an existing value. /// Always, + /// /// The operation should only occur when there is an existing value. /// Exists, + /// /// The operation should only occur when there is not an existing value. /// diff --git a/src/StackExchange.Redis/ExceptionFactory.cs b/src/StackExchange.Redis/ExceptionFactory.cs index fd1953de6..24e519b54 100644 --- a/src/StackExchange.Redis/ExceptionFactory.cs +++ b/src/StackExchange.Redis/ExceptionFactory.cs @@ -102,8 +102,8 @@ internal static Exception NoConnectionAvailable( if (server != null) { - //if we already have the serverEndpoint for connection failure use that - //otherwise it would output state of all the endpoints + // If we already have the serverEndpoint for connection failure use that, + // otherwise it would output state of all the endpoints. serverSnapshot = new ServerEndPoint[] { server }; } @@ -283,11 +283,11 @@ internal static Exception Timeout(ConnectionMultiplexer multiplexer, string? bas Exception ex = logConnectionException && lastConnectionException is not null ? new RedisConnectionException(lastConnectionException.FailureType, sb.ToString(), lastConnectionException, message?.Status ?? CommandStatus.Unknown) { - HelpLink = TimeoutHelpLink + HelpLink = TimeoutHelpLink, } : new RedisTimeoutException(sb.ToString(), message?.Status ?? CommandStatus.Unknown) { - HelpLink = TimeoutHelpLink + HelpLink = TimeoutHelpLink, }; CopyDataToException(data, ex); @@ -312,8 +312,7 @@ private static void AddCommonDetail( StringBuilder sb, Message? message, ConnectionMultiplexer multiplexer, - ServerEndPoint? server - ) + ServerEndPoint? server) { if (message != null) { @@ -325,7 +324,7 @@ private static void AddCommonDetail( // Add server data, if we have it if (server != null && message != null) { - var bs = server.GetBridgeStatus(message.IsForSubscriptionBridge ? ConnectionType.Subscription: ConnectionType.Interactive); + var bs = server.GetBridgeStatus(message.IsForSubscriptionBridge ? ConnectionType.Subscription : ConnectionType.Interactive); switch (bs.Connection.ReadStatus) { diff --git a/src/StackExchange.Redis/Exceptions.cs b/src/StackExchange.Redis/Exceptions.cs index 17abcc21c..9315eb806 100644 --- a/src/StackExchange.Redis/Exceptions.cs +++ b/src/StackExchange.Redis/Exceptions.cs @@ -50,6 +50,7 @@ private RedisTimeoutException(SerializationInfo info, StreamingContext ctx) : ba { Commandstatus = info.GetValue("commandStatus", typeof(CommandStatus)) as CommandStatus? ?? CommandStatus.Unknown; } + /// /// Serialization implementation; not intended for general usage. /// @@ -73,7 +74,7 @@ public sealed partial class RedisConnectionException : RedisException /// /// The type of connection failure. /// The message for the exception. - public RedisConnectionException(ConnectionFailureType failureType, string message) : this(failureType, message, null, CommandStatus.Unknown) {} + public RedisConnectionException(ConnectionFailureType failureType, string message) : this(failureType, message, null, CommandStatus.Unknown) { } /// /// Creates a new . @@ -81,7 +82,7 @@ public RedisConnectionException(ConnectionFailureType failureType, string messag /// The type of connection failure. /// The message for the exception. /// The inner exception. - public RedisConnectionException(ConnectionFailureType failureType, string message, Exception? innerException) : this(failureType, message, innerException, CommandStatus.Unknown) {} + public RedisConnectionException(ConnectionFailureType failureType, string message, Exception? innerException) : this(failureType, message, innerException, CommandStatus.Unknown) { } /// /// Creates a new . @@ -111,6 +112,7 @@ private RedisConnectionException(SerializationInfo info, StreamingContext ctx) : FailureType = (ConnectionFailureType)info.GetInt32("failureType"); CommandStatus = info.GetValue("commandStatus", typeof(CommandStatus)) as CommandStatus? ?? CommandStatus.Unknown; } + /// /// Serialization implementation; not intended for general usage. /// diff --git a/src/StackExchange.Redis/ExponentialRetry.cs b/src/StackExchange.Redis/ExponentialRetry.cs index 4cf965abc..f28708679 100644 --- a/src/StackExchange.Redis/ExponentialRetry.cs +++ b/src/StackExchange.Redis/ExponentialRetry.cs @@ -15,14 +15,14 @@ public class ExponentialRetry : IReconnectRetryPolicy /// /// Initializes a new instance using the specified back off interval with default maxDeltaBackOffMilliseconds of 10 seconds. /// - /// time in milliseconds for the back-off interval between retries + /// Time in milliseconds for the back-off interval between retries. public ExponentialRetry(int deltaBackOffMilliseconds) : this(deltaBackOffMilliseconds, Math.Max(deltaBackOffMilliseconds, (int)TimeSpan.FromSeconds(10).TotalMilliseconds)) { } /// /// Initializes a new instance using the specified back off interval. /// - /// time in milliseconds for the back-off interval between retries. - /// time in milliseconds for the maximum value that the back-off interval can exponentially grow up to. + /// Time in milliseconds for the back-off interval between retries. + /// Time in milliseconds for the maximum value that the back-off interval can exponentially grow up to. public ExponentialRetry(int deltaBackOffMilliseconds, int maxDeltaBackOffMilliseconds) { if (deltaBackOffMilliseconds < 0) @@ -54,16 +54,16 @@ public bool ShouldRetry(long currentRetryCount, int timeElapsedMillisecondsSince r ??= new Random(); random = r.Next((int)deltaBackOffMilliseconds, exponential); return timeElapsedMillisecondsSinceLastRetry >= random; - //exponential backoff with deltaBackOff of 5000ms - //deltabackoff exponential - //5000 5500 - //5000 6050 - //5000 6655 - //5000 8053 - //5000 10718 - //5000 17261 - //5000 37001 - //5000 127738 + // exponential backoff with deltaBackOff of 5000ms + // deltabackoff exponential + // 5000 5500 + // 5000 6050 + // 5000 6655 + // 5000 8053 + // 5000 10718 + // 5000 17261 + // 5000 37001 + // 5000 127738 } } } diff --git a/src/StackExchange.Redis/ExtensionMethods.cs b/src/StackExchange.Redis/ExtensionMethods.cs index 89b9a0e21..87904aa9c 100644 --- a/src/StackExchange.Redis/ExtensionMethods.cs +++ b/src/StackExchange.Redis/ExtensionMethods.cs @@ -21,7 +21,7 @@ public static class ExtensionMethods /// /// The entry to convert to a dictionary. [return: NotNullIfNotNull("hash")] - public static Dictionary? ToStringDictionary(this HashEntry[]? hash) + public static Dictionary? ToStringDictionary(this HashEntry[]? hash) { if (hash is null) { @@ -29,7 +29,7 @@ public static class ExtensionMethods } var result = new Dictionary(hash.Length, StringComparer.Ordinal); - for(int i = 0; i < hash.Length; i++) + for (int i = 0; i < hash.Length; i++) { result.Add(hash[i].name!, hash[i].value!); } @@ -192,7 +192,7 @@ internal static void AuthenticateAsClient(this SslStream ssl, string host, SslPr { if (!allowedProtocols.HasValue) { - //Default to the sslProtocols defined by the .NET Framework + // Default to the sslProtocols defined by the .NET Framework AuthenticateAsClientUsingDefaultProtocols(ssl, host); return; } @@ -278,9 +278,8 @@ private static void AuthenticateAsClientUsingDefaultProtocols(SslStream ssl, str private sealed class LeaseMemoryStream : MemoryStream { private readonly IDisposable _parent; - public LeaseMemoryStream(ArraySegment segment, IDisposable parent) - : base(segment.Array!, segment.Offset, segment.Count, false, true) - => _parent = parent; + + public LeaseMemoryStream(ArraySegment segment, IDisposable parent) : base(segment.Array!, segment.Offset, segment.Count, false, true) => _parent = parent; protected override void Dispose(bool disposing) { @@ -302,7 +301,6 @@ protected override void Dispose(bool disposing) // assembly-binding-redirect entries to fix this up, so; it would present an unreasonable support burden // otherwise. And yes, I've tried explicitly referencing System.Numerics.Vectors in the manifest to // force it... nothing. Nada. - #if VECTOR_SAFE [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int VectorSafeIndexOf(this ReadOnlySpan span, byte value) @@ -325,12 +323,13 @@ internal static int VectorSafeIndexOf(this ReadOnlySpan span, byte value) } return -1; } + internal static int VectorSafeIndexOfCRLF(this ReadOnlySpan span) { // yes, this has zero optimization; I'm OK with this as the fallback strategy for (int i = 1; i < span.Length; i++) { - if (span[i] == '\n' && span[i-1] == '\r') return i - 1; + if (span[i] == '\n' && span[i - 1] == '\r') return i - 1; } return -1; } diff --git a/src/StackExchange.Redis/Format.cs b/src/StackExchange.Redis/Format.cs index 73c29a82e..6836a70da 100644 --- a/src/StackExchange.Redis/Format.cs +++ b/src/StackExchange.Redis/Format.cs @@ -1,10 +1,10 @@ using System; using System.Buffers; using System.Buffers.Text; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Net; using System.Text; -using System.Diagnostics.CodeAnalysis; #if UNIX_SOCKET using System.Net.Sockets; @@ -86,7 +86,7 @@ internal static string ToString(double value) float f => ToString(f), double d => ToString(d), EndPoint e => ToString(e), - _ => Convert.ToString(value, CultureInfo.InvariantCulture) + _ => Convert.ToString(value, CultureInfo.InvariantCulture), }; internal static string ToString(EndPoint? endpoint) @@ -113,7 +113,7 @@ internal static string ToStringHostOnly(EndPoint endpoint) => { DnsEndPoint dns => dns.Host, IPEndPoint ip => ip.Address.ToString(), - _ => "" + _ => "", }; internal static bool TryGetHostPort(EndPoint? endpoint, [NotNullWhen(true)] out string? host, [NotNullWhen(true)] out int? port) @@ -258,7 +258,7 @@ private static bool CaseInsensitiveASCIIEqual(string xLowerCase, ReadOnlySpan /// /// Adapted from IPEndPointParser in Microsoft.AspNetCore - /// Link: + /// Link: . /// /// /// Copyright (c) .NET Foundation. All rights reserved. @@ -276,7 +276,7 @@ internal static bool TryParseEndPoint(string? addressWithPort, [NotNullWhen(true return false; } - if (addressWithPort[0]=='!') + if (addressWithPort[0] == '!') { if (addressWithPort.Length == 1) { diff --git a/src/StackExchange.Redis/GlobalSuppressions.cs b/src/StackExchange.Redis/GlobalSuppressions.cs index 3882f4776..84d04d110 100644 --- a/src/StackExchange.Redis/GlobalSuppressions.cs +++ b/src/StackExchange.Redis/GlobalSuppressions.cs @@ -5,17 +5,17 @@ using System.Diagnostics.CodeAnalysis; -[assembly: SuppressMessage("Style", "IDE0066:Convert switch statement to expression", Justification = "", Scope = "member", Target = "~P:StackExchange.Redis.Message.IsAdmin")] -[assembly: SuppressMessage("Style", "IDE0066:Convert switch statement to expression", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.ServerEndPoint.GetBridge(StackExchange.Redis.RedisCommand,System.Boolean)~StackExchange.Redis.PhysicalBridge")] -[assembly: SuppressMessage("Style", "IDE0066:Convert switch statement to expression", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.RedisValue.op_Equality(StackExchange.Redis.RedisValue,StackExchange.Redis.RedisValue)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0075:Simplify conditional expression", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.RedisSubscriber.Unsubscribe(StackExchange.Redis.RedisChannel@,System.Action{StackExchange.Redis.RedisChannel,StackExchange.Redis.RedisValue},StackExchange.Redis.ChannelMessageQueue,StackExchange.Redis.CommandFlags)~System.Boolean")] -[assembly: SuppressMessage("Roslynator", "RCS1104:Simplify conditional expression.", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.RedisSubscriber.Unsubscribe(StackExchange.Redis.RedisChannel@,System.Action{StackExchange.Redis.RedisChannel,StackExchange.Redis.RedisValue},StackExchange.Redis.ChannelMessageQueue,StackExchange.Redis.CommandFlags)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0066:Convert switch statement to expression", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.Message.IsPrimaryOnly(StackExchange.Redis.RedisCommand)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0066:Convert switch statement to expression", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.Message.RequiresDatabase(StackExchange.Redis.RedisCommand)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0180:Use tuple to swap values", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.RedisDatabase.ReverseLimits(StackExchange.Redis.Order,StackExchange.Redis.Exclude@,StackExchange.Redis.RedisValue@,StackExchange.Redis.RedisValue@)")] -[assembly: SuppressMessage("Style", "IDE0180:Use tuple to swap values", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.RedisDatabase.GetSortedSetRangeByScoreMessage(StackExchange.Redis.RedisKey,System.Double,System.Double,StackExchange.Redis.Exclude,StackExchange.Redis.Order,System.Int64,System.Int64,StackExchange.Redis.CommandFlags,System.Boolean)~StackExchange.Redis.Message")] -[assembly: SuppressMessage("Reliability", "CA2012:Use ValueTasks correctly", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.PhysicalConnection.FlushSync(System.Boolean,System.Int32)~StackExchange.Redis.WriteResult")] -[assembly: SuppressMessage("Usage", "CA2219:Do not raise exceptions in finally clauses", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.PhysicalBridge.ProcessBacklogAsync~System.Threading.Tasks.Task")] -[assembly: SuppressMessage("Usage", "CA2249:Consider using 'string.Contains' instead of 'string.IndexOf'", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.ClientInfo.AddFlag(StackExchange.Redis.ClientFlags@,System.String,StackExchange.Redis.ClientFlags,System.Char)")] -[assembly: SuppressMessage("Style", "IDE0070:Use 'System.HashCode'", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.CommandBytes.GetHashCode~System.Int32")] -[assembly: SuppressMessage("Roslynator", "RCS1085:Use auto-implemented property.", Justification = "", Scope = "member", Target = "~P:StackExchange.Redis.RedisValue.OverlappedValueInt64")] +[assembly: SuppressMessage("Style", "IDE0066:Convert switch statement to expression", Justification = "Pending", Scope = "member", Target = "~P:StackExchange.Redis.Message.IsAdmin")] +[assembly: SuppressMessage("Style", "IDE0066:Convert switch statement to expression", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.ServerEndPoint.GetBridge(StackExchange.Redis.RedisCommand,System.Boolean)~StackExchange.Redis.PhysicalBridge")] +[assembly: SuppressMessage("Style", "IDE0066:Convert switch statement to expression", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.RedisValue.op_Equality(StackExchange.Redis.RedisValue,StackExchange.Redis.RedisValue)~System.Boolean")] +[assembly: SuppressMessage("Style", "IDE0075:Simplify conditional expression", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.RedisSubscriber.Unsubscribe(StackExchange.Redis.RedisChannel@,System.Action{StackExchange.Redis.RedisChannel,StackExchange.Redis.RedisValue},StackExchange.Redis.ChannelMessageQueue,StackExchange.Redis.CommandFlags)~System.Boolean")] +[assembly: SuppressMessage("Roslynator", "RCS1104:Simplify conditional expression.", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.RedisSubscriber.Unsubscribe(StackExchange.Redis.RedisChannel@,System.Action{StackExchange.Redis.RedisChannel,StackExchange.Redis.RedisValue},StackExchange.Redis.ChannelMessageQueue,StackExchange.Redis.CommandFlags)~System.Boolean")] +[assembly: SuppressMessage("Style", "IDE0066:Convert switch statement to expression", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.Message.IsPrimaryOnly(StackExchange.Redis.RedisCommand)~System.Boolean")] +[assembly: SuppressMessage("Style", "IDE0066:Convert switch statement to expression", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.Message.RequiresDatabase(StackExchange.Redis.RedisCommand)~System.Boolean")] +[assembly: SuppressMessage("Style", "IDE0180:Use tuple to swap values", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.RedisDatabase.ReverseLimits(StackExchange.Redis.Order,StackExchange.Redis.Exclude@,StackExchange.Redis.RedisValue@,StackExchange.Redis.RedisValue@)")] +[assembly: SuppressMessage("Style", "IDE0180:Use tuple to swap values", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.RedisDatabase.GetSortedSetRangeByScoreMessage(StackExchange.Redis.RedisKey,System.Double,System.Double,StackExchange.Redis.Exclude,StackExchange.Redis.Order,System.Int64,System.Int64,StackExchange.Redis.CommandFlags,System.Boolean)~StackExchange.Redis.Message")] +[assembly: SuppressMessage("Reliability", "CA2012:Use ValueTasks correctly", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.PhysicalConnection.FlushSync(System.Boolean,System.Int32)~StackExchange.Redis.WriteResult")] +[assembly: SuppressMessage("Usage", "CA2219:Do not raise exceptions in finally clauses", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.PhysicalBridge.ProcessBacklogAsync~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Usage", "CA2249:Consider using 'string.Contains' instead of 'string.IndexOf'", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.ClientInfo.AddFlag(StackExchange.Redis.ClientFlags@,System.String,StackExchange.Redis.ClientFlags,System.Char)")] +[assembly: SuppressMessage("Style", "IDE0070:Use 'System.HashCode'", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.CommandBytes.GetHashCode~System.Int32")] +[assembly: SuppressMessage("Roslynator", "RCS1085:Use auto-implemented property.", Justification = "Pending", Scope = "member", Target = "~P:StackExchange.Redis.RedisValue.OverlappedValueInt64")] diff --git a/src/StackExchange.Redis/HashSlotMovedEventArgs.cs b/src/StackExchange.Redis/HashSlotMovedEventArgs.cs index d92c2af8c..876088e5c 100644 --- a/src/StackExchange.Redis/HashSlotMovedEventArgs.cs +++ b/src/StackExchange.Redis/HashSlotMovedEventArgs.cs @@ -27,8 +27,7 @@ public class HashSlotMovedEventArgs : EventArgs, ICompletable /// public EndPoint NewEndPoint { get; } - internal HashSlotMovedEventArgs(EventHandler? handler, object sender, - int hashSlot, EndPoint? old, EndPoint @new) + internal HashSlotMovedEventArgs(EventHandler? handler, object sender, int hashSlot, EndPoint? old, EndPoint @new) { this.handler = handler; this.sender = sender; @@ -45,7 +44,7 @@ internal HashSlotMovedEventArgs(EventHandler? handler, o /// Old endpoint. /// New endpoint. public HashSlotMovedEventArgs(object sender, int hashSlot, EndPoint old, EndPoint @new) - : this (null, sender, hashSlot, old, @new) + : this(null, sender, hashSlot, old, @new) { } diff --git a/src/StackExchange.Redis/Interfaces/IConnectionMultiplexer.cs b/src/StackExchange.Redis/Interfaces/IConnectionMultiplexer.cs index 25d2f7099..b4bdb0950 100644 --- a/src/StackExchange.Redis/Interfaces/IConnectionMultiplexer.cs +++ b/src/StackExchange.Redis/Interfaces/IConnectionMultiplexer.cs @@ -1,11 +1,11 @@ -using StackExchange.Redis.Maintenance; -using StackExchange.Redis.Profiling; -using System; +using System; using System.Collections.Concurrent; using System.ComponentModel; using System.IO; using System.Net; using System.Threading.Tasks; +using StackExchange.Redis.Maintenance; +using StackExchange.Redis.Profiling; using static StackExchange.Redis.ConnectionMultiplexer; namespace StackExchange.Redis diff --git a/src/StackExchange.Redis/Interfaces/IDatabase.cs b/src/StackExchange.Redis/Interfaces/IDatabase.cs index 7cf2248fd..6178051d0 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabase.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabase.cs @@ -6,12 +6,12 @@ namespace StackExchange.Redis { /// - /// Describes functionality that is common to both standalone redis servers and redis clusters + /// Describes functionality that is common to both standalone redis servers and redis clusters. /// public interface IDatabase : IRedis, IDatabaseAsync { /// - /// The numeric identifier of this database + /// The numeric identifier of this database. /// int Database { get; } @@ -492,8 +492,9 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// if field is a new field in the hash and value was set, if field already exists in the hash and the value was updated. /// + /// See /// , - /// + /// . /// bool HashSet(RedisKey key, RedisValue hashField, RedisValue value, When when = When.Always, CommandFlags flags = CommandFlags.None); @@ -501,7 +502,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// Returns the string length of the value associated with field in the hash stored at key. /// /// The key of the hash. - /// The field containing the string + /// The field containing the string. /// The flags to use for this operation. /// The length of the string at field, or 0 when key does not exist. /// @@ -559,7 +560,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// /// The key of the merged hyperloglog. /// The key of the first hyperloglog to merge. - /// The key of the first hyperloglog to merge. + /// The key of the second hyperloglog to merge. /// The flags to use for this operation. /// void HyperLogLogMerge(RedisKey destination, RedisKey first, RedisKey second, CommandFlags flags = CommandFlags.None); @@ -601,8 +602,9 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// if the key was removed. /// + /// See /// , - /// + /// . /// bool KeyDelete(RedisKey key, CommandFlags flags = CommandFlags.None); @@ -614,8 +616,9 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// The number of keys that were removed. /// + /// See /// , - /// + /// . /// long KeyDelete(RedisKey[] keys, CommandFlags flags = CommandFlags.None); @@ -677,9 +680,10 @@ public interface IDatabase : IRedis, IDatabaseAsync /// See the page on key expiry for more information. /// /// + /// See /// , /// , - /// + /// . /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] @@ -696,8 +700,9 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// if the timeout was set. if key does not exist or the timeout could not be set. /// + /// See /// , - /// + /// . /// bool KeyExpire(RedisKey key, TimeSpan? expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); @@ -722,9 +727,10 @@ public interface IDatabase : IRedis, IDatabaseAsync /// See the page on key expiry for more information. /// /// + /// See /// , /// , - /// + /// . /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] @@ -741,8 +747,9 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// if the timeout was set. if key does not exist or the timeout could not be set. /// + /// See /// , - /// + /// . /// bool KeyExpire(RedisKey key, DateTime? expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); @@ -753,8 +760,9 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// The time at which the given key will expire, or if the key does not exist or has no associated expiration time. /// + /// See /// , - /// + /// . /// DateTime? KeyExpireTime(RedisKey key, CommandFlags flags = CommandFlags.None); @@ -826,8 +834,9 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// if the key was renamed, otherwise. /// + /// See /// , - /// + /// . /// bool KeyRename(RedisKey key, RedisKey newKey, When when = When.Always, CommandFlags flags = CommandFlags.None); @@ -931,7 +940,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// If the list contains less than count elements, removes and returns the number of elements in the list. /// /// The key of the list. - /// The number of elements to remove + /// The number of elements to remove. /// The flags to use for this operation. /// Array of values that were popped, or if the key doesn't exist. /// @@ -985,8 +994,9 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// The length of the list after the push operations. /// + /// See /// , - /// + /// . /// long ListLeftPush(RedisKey key, RedisValue value, When when = When.Always, CommandFlags flags = CommandFlags.None); @@ -1000,8 +1010,9 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// The length of the list after the push operations. /// + /// See /// , - /// + /// . /// long ListLeftPush(RedisKey key, RedisValue[] values, When when = When.Always, CommandFlags flags = CommandFlags.None); @@ -1085,7 +1096,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// If the list contains less than count elements, removes and returns the number of elements in the list. /// /// The key of the list. - /// The number of elements to pop + /// The number of elements to pop. /// The flags to use for this operation. /// Array of values that were popped, or if the key doesn't exist. /// @@ -1122,8 +1133,9 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// The length of the list after the push operation. /// + /// See /// , - /// + /// . /// long ListRightPush(RedisKey key, RedisValue value, When when = When.Always, CommandFlags flags = CommandFlags.None); @@ -1137,8 +1149,9 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// The length of the list after the push operation. /// + /// See /// , - /// + /// . /// long ListRightPush(RedisKey key, RedisValue[] values, When when = When.Always, CommandFlags flags = CommandFlags.None); @@ -1260,8 +1273,9 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// A dynamic representation of the script's result. /// + /// See /// , - /// + /// . /// RedisResult ScriptEvaluate(string script, RedisKey[]? keys = null, RedisValue[]? values = null, CommandFlags flags = CommandFlags.None); @@ -1312,8 +1326,9 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// A dynamic representation of the script's result. /// + /// See /// , - /// + /// . /// RedisResult ScriptEvaluateReadOnly(string script, RedisKey[]? keys = null, RedisValue[]? values = null, CommandFlags flags = CommandFlags.None); @@ -1361,9 +1376,10 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// List with members of the resulting set. /// + /// See /// , /// , - /// + /// . /// RedisValue[] SetCombine(SetOperation operation, RedisKey first, RedisKey second, CommandFlags flags = CommandFlags.None); @@ -1375,9 +1391,10 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// List with members of the resulting set. /// + /// See /// , /// , - /// + /// . /// RedisValue[] SetCombine(SetOperation operation, RedisKey[] keys, CommandFlags flags = CommandFlags.None); @@ -1392,9 +1409,10 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// The number of elements in the resulting set. /// + /// See /// , /// , - /// + /// . /// long SetCombineAndStore(SetOperation operation, RedisKey destination, RedisKey first, RedisKey second, CommandFlags flags = CommandFlags.None); @@ -1408,9 +1426,10 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// The number of elements in the resulting set. /// + /// See /// , /// , - /// + /// . /// long SetCombineAndStore(SetOperation operation, RedisKey destination, RedisKey[] keys, CommandFlags flags = CommandFlags.None); @@ -1565,7 +1584,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// /// The SSCAN command is used to incrementally iterate over set. - /// Note: to resume an iteration via cursor, cast the original enumerable or enumerator to . + /// Note: to resume an iteration via cursor, cast the original enumerable or enumerator to . /// /// The key of the set. /// The pattern to match. @@ -1596,8 +1615,9 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// The sorted elements, or the external values if get is specified. /// + /// See /// , - /// + /// . /// RedisValue[] Sort(RedisKey key, long skip = 0, long take = -1, Order order = Order.Ascending, SortType sortType = SortType.Numeric, RedisValue by = default, RedisValue[]? get = null, CommandFlags flags = CommandFlags.None); @@ -1628,7 +1648,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - bool SortedSetAdd(RedisKey key, RedisValue member, double score, When when, CommandFlags flags= CommandFlags.None); + bool SortedSetAdd(RedisKey key, RedisValue member, double score, When when, CommandFlags flags = CommandFlags.None); /// /// Adds the specified member with the specified score to the sorted set stored at key. @@ -1675,9 +1695,10 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// The resulting sorted set. /// + /// See /// , /// , - /// + /// . /// RedisValue[] SortedSetCombine(SetOperation operation, RedisKey[] keys, double[]? weights = null, Aggregate aggregate = Aggregate.Sum, CommandFlags flags = CommandFlags.None); @@ -1693,9 +1714,10 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// The resulting sorted set with scores. /// + /// See /// , /// , - /// + /// . /// SortedSetEntry[] SortedSetCombineWithScores(SetOperation operation, RedisKey[] keys, double[]? weights = null, Aggregate aggregate = Aggregate.Sum, CommandFlags flags = CommandFlags.None); @@ -1712,9 +1734,10 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// The number of elements in the resulting sorted set at destination. /// + /// See /// , /// , - /// + /// . /// long SortedSetCombineAndStore(SetOperation operation, RedisKey destination, RedisKey first, RedisKey second, Aggregate aggregate = Aggregate.Sum, CommandFlags flags = CommandFlags.None); @@ -1731,9 +1754,10 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// The number of elements in the resulting sorted set at destination. /// + /// See /// , /// , - /// + /// . /// long SortedSetCombineAndStore(SetOperation operation, RedisKey destination, RedisKey[] keys, double[]? weights = null, Aggregate aggregate = Aggregate.Sum, CommandFlags flags = CommandFlags.None); @@ -1856,8 +1880,9 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The flags to use for this operation. /// List of elements in the specified range. /// + /// See /// , - /// + /// . /// RedisValue[] SortedSetRangeByRank(RedisKey key, long start = 0, long stop = -1, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None); @@ -1907,8 +1932,9 @@ long SortedSetRangeAndStore( /// The flags to use for this operation. /// List of elements in the specified range. /// + /// See /// , - /// + /// . /// SortedSetEntry[] SortedSetRangeByRankWithScores(RedisKey key, long start = 0, long stop = -1, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None); @@ -1929,10 +1955,12 @@ long SortedSetRangeAndStore( /// The flags to use for this operation. /// List of elements in the specified score range. /// + /// See /// , - /// + /// . /// - RedisValue[] SortedSetRangeByScore(RedisKey key, + RedisValue[] SortedSetRangeByScore( + RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity, Exclude exclude = Exclude.None, @@ -1958,10 +1986,12 @@ RedisValue[] SortedSetRangeByScore(RedisKey key, /// The flags to use for this operation. /// List of elements in the specified score range. /// + /// See /// , - /// + /// . /// - SortedSetEntry[] SortedSetRangeByScoreWithScores(RedisKey key, + SortedSetEntry[] SortedSetRangeByScoreWithScores( + RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity, Exclude exclude = Exclude.None, @@ -1983,7 +2013,8 @@ SortedSetEntry[] SortedSetRangeByScoreWithScores(RedisKey key, /// The flags to use for this operation. /// List of elements in the specified score range. /// - RedisValue[] SortedSetRangeByValue(RedisKey key, + RedisValue[] SortedSetRangeByValue( + RedisKey key, RedisValue min, RedisValue max, Exclude exclude, @@ -1999,16 +2030,18 @@ RedisValue[] SortedSetRangeByValue(RedisKey key, /// The min value to filter by. /// The max value to filter by. /// Which of and to exclude (defaults to both inclusive). - /// Whether to order the data ascending or descending + /// Whether to order the data ascending or descending. /// How many items to skip. /// How many items to take. /// The flags to use for this operation. /// List of elements in the specified score range. /// + /// See /// , - /// + /// . /// - RedisValue[] SortedSetRangeByValue(RedisKey key, + RedisValue[] SortedSetRangeByValue( + RedisKey key, RedisValue min = default, RedisValue max = default, Exclude exclude = Exclude.None, @@ -2027,8 +2060,9 @@ RedisValue[] SortedSetRangeByValue(RedisKey key, /// The flags to use for this operation. /// If member exists in the sorted set, the rank of member. If member does not exist in the sorted set or key does not exist, . /// + /// See /// , - /// + /// . /// long? SortedSetRank(RedisKey key, RedisValue member, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None); @@ -2104,7 +2138,7 @@ RedisValue[] SortedSetRangeByValue(RedisKey key, /// /// The ZSCAN command is used to incrementally iterate over a sorted set - /// Note: to resume an iteration via cursor, cast the original enumerable or enumerator to IScanningCursor. + /// Note: to resume an iteration via cursor, cast the original enumerable or enumerator to IScanningCursor. /// /// The key of the sorted set. /// The pattern to match. @@ -2114,7 +2148,8 @@ RedisValue[] SortedSetRangeByValue(RedisKey key, /// The flags to use for this operation. /// Yields all matching elements of the sorted set. /// - IEnumerable SortedSetScan(RedisKey key, + IEnumerable SortedSetScan( + RedisKey key, RedisValue pattern = default, int pageSize = RedisBase.CursorUtils.DefaultLibraryPageSize, long cursor = RedisBase.CursorUtils.Origin, @@ -2154,8 +2189,9 @@ IEnumerable SortedSetScan(RedisKey key, /// The flags to use for this operation. /// The removed element, or when key does not exist. /// + /// See /// , - /// + /// . /// SortedSetEntry? SortedSetPop(RedisKey key, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None); @@ -2168,8 +2204,9 @@ IEnumerable SortedSetScan(RedisKey key, /// The flags to use for this operation. /// An array of elements, or an empty array when key does not exist. /// + /// See /// , - /// + /// . /// SortedSetEntry[] SortedSetPop(RedisKey key, long count, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None); @@ -2428,7 +2465,7 @@ IEnumerable SortedSetScan(RedisKey key, /// A pending message is a message read using StreamReadGroup (XREADGROUP) but not yet acknowledged. /// /// The key of the stream. - /// The name of the consumer group + /// The name of the consumer group. /// The flags to use for this operation. /// /// An instance of . @@ -2527,7 +2564,7 @@ IEnumerable SortedSetScan(RedisKey key, /// /// Array of streams and the positions from which to begin reading for each stream. /// The name of the consumer group. - /// + /// The name of the consumer. /// The maximum number of messages to return from each stream. /// The flags to use for this operation. /// A value of for each stream. @@ -2543,7 +2580,7 @@ IEnumerable SortedSetScan(RedisKey key, /// /// Array of streams and the positions from which to begin reading for each stream. /// The name of the consumer group. - /// + /// The name of the consumer. /// The maximum number of messages to return from each stream. /// When true, the message will not be added to the pending message list. /// The flags to use for this operation. @@ -2657,8 +2694,9 @@ IEnumerable SortedSetScan(RedisKey key, /// The flags to use for this operation. /// The value of key after the decrement. /// + /// See /// , - /// + /// . /// long StringDecrement(RedisKey key, long value = 1, CommandFlags flags = CommandFlags.None); @@ -2793,8 +2831,9 @@ IEnumerable SortedSetScan(RedisKey key, /// The flags to use for this operation. /// The value of key after the increment. /// + /// See /// , - /// + /// . /// long StringIncrement(RedisKey key, long value = 1, CommandFlags flags = CommandFlags.None); @@ -2889,8 +2928,9 @@ IEnumerable SortedSetScan(RedisKey key, /// The flags to use for this operation. /// if the keys were set, otherwise. /// + /// See /// , - /// + /// . /// bool StringSet(KeyValuePair[] values, When when = When.Always, CommandFlags flags = CommandFlags.None); diff --git a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs index a19525925..103b7151b 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs @@ -18,1834 +18,452 @@ public interface IDatabaseAsync : IRedisAsync /// The flags to use for this operation. bool IsConnected(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Atomically transfer a key from a source Redis instance to a destination Redis instance. - /// On success the key is deleted from the original instance by default, and is guaranteed to exist in the target instance. - /// - /// The key to migrate. - /// The server to migrate the key to. - /// The database to migrate the key to. - /// The timeout to use for the transfer. - /// The options to use for this migration. - /// The flags to use for this operation. - /// + /// Task KeyMigrateAsync(RedisKey key, EndPoint toServer, int toDatabase = 0, int timeoutMilliseconds = 0, MigrateOptions migrateOptions = MigrateOptions.None, CommandFlags flags = CommandFlags.None); - /// - /// Returns the raw DEBUG OBJECT output for a key. - /// This command is not fully documented and should be avoided unless you have good reason, and then avoided anyway. - /// - /// The key to debug. - /// The flags to use for this migration. - /// The raw output from DEBUG OBJECT. - /// + /// " Task DebugObjectAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Add the specified member to the set stored at key. - /// Specified members that are already a member of this set are ignored. - /// If key does not exist, a new set is created before adding the specified members. - /// - /// The key of the set. - /// The longitude of geo entry. - /// The latitude of the geo entry. - /// The value to set at this entry. - /// The flags to use for this operation. - /// if the specified member was not already present in the set, else . - /// + /// Task GeoAddAsync(RedisKey key, double longitude, double latitude, RedisValue member, CommandFlags flags = CommandFlags.None); - /// - /// Add the specified member to the set stored at key. - /// Specified members that are already a member of this set are ignored. - /// If key does not exist, a new set is created before adding the specified members. - /// - /// The key of the set. - /// The geo value to store. - /// The flags to use for this operation. - /// if the specified member was not already present in the set, else . - /// + /// Task GeoAddAsync(RedisKey key, GeoEntry value, CommandFlags flags = CommandFlags.None); - /// - /// Add the specified members to the set stored at key. - /// Specified members that are already a member of this set are ignored. - /// If key does not exist, a new set is created before adding the specified members. - /// - /// The key of the set. - /// The geo values add to the set. - /// The flags to use for this operation. - /// The number of elements that were added to the set, not including all the elements already present into the set. - /// + /// Task GeoAddAsync(RedisKey key, GeoEntry[] values, CommandFlags flags = CommandFlags.None); - /// - /// Removes the specified member from the geo sorted set stored at key. - /// Non existing members are ignored. - /// - /// The key of the set. - /// The geo value to remove. - /// The flags to use for this operation. - /// if the member existed in the sorted set and was removed, else . - /// + /// Task GeoRemoveAsync(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None); - /// - /// Return the distance between two members in the geospatial index represented by the sorted set. - /// - /// The key of the set. - /// The first member to check. - /// The second member to check. - /// The unit of distance to return (defaults to meters). - /// The flags to use for this operation. - /// The command returns the distance as a double (represented as a string) in the specified unit, or if one or both the elements are missing. - /// + /// Task GeoDistanceAsync(RedisKey key, RedisValue member1, RedisValue member2, GeoUnit unit = GeoUnit.Meters, CommandFlags flags = CommandFlags.None); - /// - /// Return valid Geohash strings representing the position of one or more elements in a sorted set value representing a geospatial index (where elements were added using GEOADD). - /// - /// The key of the set. - /// The members to get. - /// The flags to use for this operation. - /// The command returns an array where each element is the Geohash corresponding to each member name passed as argument to the command. - /// + /// Task GeoHashAsync(RedisKey key, RedisValue[] members, CommandFlags flags = CommandFlags.None); - /// - /// Return valid Geohash strings representing the position of one or more elements in a sorted set value representing a geospatial index (where elements were added using GEOADD). - /// - /// The key of the set. - /// The member to get. - /// The flags to use for this operation. - /// The command returns an array where each element is the Geohash corresponding to each member name passed as argument to the command. - /// + /// Task GeoHashAsync(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None); - /// - /// Return the positions (longitude,latitude) of all the specified members of the geospatial index represented by the sorted set at key. - /// - /// The key of the set. - /// The members to get. - /// The flags to use for this operation. - /// - /// The command returns an array where each element is a two elements array representing longitude and latitude (x,y) of each member name passed as argument to the command. - /// Non existing elements are reported as NULL elements of the array. - /// - /// + /// Task GeoPositionAsync(RedisKey key, RedisValue[] members, CommandFlags flags = CommandFlags.None); - /// - /// Return the positions (longitude,latitude) of all the specified members of the geospatial index represented by the sorted set at key. - /// - /// The key of the set. - /// The member to get. - /// The flags to use for this operation. - /// - /// The command returns an array where each element is a two elements array representing longitude and latitude (x,y) of each member name passed as argument to the command. - /// Non existing elements are reported as NULL elements of the array. - /// - /// + /// Task GeoPositionAsync(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None); - /// - /// Return the members of a sorted set populated with geospatial information using GEOADD, which are - /// within the borders of the area specified with the center location and the maximum distance from the center (the radius). - /// - /// The key of the set. - /// The member to get a radius of results from. - /// The radius to check. - /// The unit of (defaults to meters). - /// The count of results to get, -1 for unlimited. - /// The order of the results. - /// The search options to use. - /// The flags to use for this operation. - /// The results found within the radius, if any. - /// + /// Task GeoRadiusAsync(RedisKey key, RedisValue member, double radius, GeoUnit unit = GeoUnit.Meters, int count = -1, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None); - /// - /// Return the members of a sorted set populated with geospatial information using GEOADD, which are - /// within the borders of the area specified with the center location and the maximum distance from the center (the radius). - /// - /// The key of the set. - /// The longitude of the point to get a radius of results from. - /// The latitude of the point to get a radius of results from. - /// The radius to check. - /// The unit of (defaults to meters). - /// The count of results to get, -1 for unlimited. - /// The order of the results. - /// The search options to use. - /// The flags to use for this operation. - /// The results found within the radius, if any. - /// + /// Task GeoRadiusAsync(RedisKey key, double longitude, double latitude, double radius, GeoUnit unit = GeoUnit.Meters, int count = -1, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None); - /// - /// Return the members of the geo-encoded sorted set stored at bounded by the provided - /// , centered at the provided set . - /// - /// The key of the set. - /// The set member to use as the center of the shape. - /// The shape to use to bound the geo search. - /// The maximum number of results to pull back. - /// Whether or not to terminate the search after finding results. Must be true of count is -1. - /// The order to sort by (defaults to unordered). - /// The search options to use. - /// The flags for this operation. - /// The results found within the shape, if any. - /// + /// Task GeoSearchAsync(RedisKey key, RedisValue member, GeoSearchShape shape, int count = -1, bool demandClosest = true, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None); - /// - /// Return the members of the geo-encoded sorted set stored at bounded by the provided - /// , centered at the point provided by the and . - /// - /// The key of the set. - /// The longitude of the center point. - /// The latitude of the center point. - /// The shape to use to bound the geo search. - /// The maximum number of results to pull back. - /// Whether or not to terminate the search after finding results. Must be true of count is -1. - /// The order to sort by (defaults to unordered). - /// The search options to use. - /// The flags for this operation. - /// The results found within the shape, if any. - /// + /// Task GeoSearchAsync(RedisKey key, double longitude, double latitude, GeoSearchShape shape, int count = -1, bool demandClosest = true, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None); - /// - /// Stores the members of the geo-encoded sorted set stored at bounded by the provided - /// , centered at the provided set . - /// - /// The key of the set. - /// The key to store the result at. - /// The set member to use as the center of the shape. - /// The shape to use to bound the geo search. - /// The maximum number of results to pull back. - /// Whether or not to terminate the search after finding results. Must be true of count is -1. - /// The order to sort by (defaults to unordered). - /// If set to true, the resulting set will be a regular sorted-set containing only distances, rather than a geo-encoded sorted-set. - /// The flags for this operation. - /// The size of the set stored at . - /// + /// Task GeoSearchAndStoreAsync(RedisKey sourceKey, RedisKey destinationKey, RedisValue member, GeoSearchShape shape, int count = -1, bool demandClosest = true, Order? order = null, bool storeDistances = false, CommandFlags flags = CommandFlags.None); - /// - /// Stores the members of the geo-encoded sorted set stored at bounded by the provided - /// , centered at the point provided by the and . - /// - /// The key of the set. - /// The key to store the result at. - /// The longitude of the center point. - /// The latitude of the center point. - /// The shape to use to bound the geo search. - /// The maximum number of results to pull back. - /// Whether or not to terminate the search after finding results. Must be true of count is -1. - /// The order to sort by (defaults to unordered). - /// If set to true, the resulting set will be a regular sorted-set containing only distances, rather than a geo-encoded sorted-set. - /// The flags for this operation. - /// The size of the set stored at . - /// + /// Task GeoSearchAndStoreAsync(RedisKey sourceKey, RedisKey destinationKey, double longitude, double latitude, GeoSearchShape shape, int count = -1, bool demandClosest = true, Order? order = null, bool storeDistances = false, CommandFlags flags = CommandFlags.None); - /// - /// Decrements the number stored at field in the hash stored at key by decrement. - /// If key does not exist, a new key holding a hash is created. - /// If field does not exist the value is set to 0 before the operation is performed. - /// - /// The key of the hash. - /// The field in the hash to decrement. - /// The amount to decrement by. - /// The flags to use for this operation. - /// The value at field after the decrement operation. - /// - /// The range of values supported by HINCRBY is limited to 64 bit signed integers. - /// - /// + /// Task HashDecrementAsync(RedisKey key, RedisValue hashField, long value = 1, CommandFlags flags = CommandFlags.None); - /// - /// Decrement the specified field of an hash stored at key, and representing a floating point number, by the specified decrement. - /// If the field does not exist, it is set to 0 before performing the operation. - /// - /// The key of the hash. - /// The field in the hash to decrement. - /// The amount to decrement by. - /// The flags to use for this operation. - /// The value at field after the decrement operation. - /// - /// The precision of the output is fixed at 17 digits after the decimal point regardless of the actual internal precision of the computation. - /// - /// + /// Task HashDecrementAsync(RedisKey key, RedisValue hashField, double value, CommandFlags flags = CommandFlags.None); - /// - /// Removes the specified fields from the hash stored at key. - /// Non-existing fields are ignored. Non-existing keys are treated as empty hashes and this command returns 0. - /// - /// The key of the hash. - /// The field in the hash to delete. - /// The flags to use for this operation. - /// if the field was removed. - /// + /// Task HashDeleteAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); - /// - /// Removes the specified fields from the hash stored at key. - /// Non-existing fields are ignored. Non-existing keys are treated as empty hashes and this command returns 0. - /// - /// The key of the hash. - /// The fields in the hash to delete. - /// The flags to use for this operation. - /// The number of fields that were removed. - /// + /// Task HashDeleteAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); - /// - /// Returns if field is an existing field in the hash stored at key. - /// - /// The key of the hash. - /// The field in the hash to check. - /// The flags to use for this operation. - /// if the hash contains field, if the hash does not contain field, or key does not exist. - /// + /// Task HashExistsAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); - /// - /// Returns the value associated with field in the hash stored at key. - /// - /// The key of the hash. - /// The field in the hash to get. - /// The flags to use for this operation. - /// The value associated with field, or when field is not present in the hash or key does not exist. - /// + /// Task HashGetAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); - /// - /// Returns the value associated with field in the hash stored at key. - /// - /// The key of the hash. - /// The field in the hash to get. - /// The flags to use for this operation. - /// The value associated with field, or when field is not present in the hash or key does not exist. - /// + /// Task?> HashGetLeaseAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); - /// - /// Returns the values associated with the specified fields in the hash stored at key. - /// For every field that does not exist in the hash, a value is returned. - /// Because a non-existing keys are treated as empty hashes, running HMGET against a non-existing key will return a list of values. - /// - /// The key of the hash. - /// The fields in the hash to get. - /// The flags to use for this operation. - /// List of values associated with the given fields, in the same order as they are requested. - /// + /// Task HashGetAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); - /// - /// Returns all fields and values of the hash stored at key. - /// - /// The key of the hash to get all entries from. - /// The flags to use for this operation. - /// List of fields and their values stored in the hash, or an empty list when key does not exist. - /// + /// Task HashGetAllAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Increments the number stored at field in the hash stored at key by increment. - /// If key does not exist, a new key holding a hash is created. - /// If field does not exist the value is set to 0 before the operation is performed. - /// - /// The key of the hash. - /// The field in the hash to increment. - /// The amount to increment by. - /// The flags to use for this operation. - /// The value at field after the increment operation. - /// - /// The range of values supported by HINCRBY is limited to 64 bit signed integers. - /// - /// + /// Task HashIncrementAsync(RedisKey key, RedisValue hashField, long value = 1, CommandFlags flags = CommandFlags.None); - /// - /// Increment the specified field of an hash stored at key, and representing a floating point number, by the specified increment. - /// If the field does not exist, it is set to 0 before performing the operation. - /// - /// The key of the hash. - /// The field in the hash to increment. - /// The amount to increment by. - /// The flags to use for this operation. - /// The value at field after the increment operation. - /// - /// The precision of the output is fixed at 17 digits after the decimal point regardless of the actual internal precision of the computation. - /// - /// + /// Task HashIncrementAsync(RedisKey key, RedisValue hashField, double value, CommandFlags flags = CommandFlags.None); - /// - /// Returns all field names in the hash stored at key. - /// - /// The key of the hash. - /// The flags to use for this operation. - /// List of fields in the hash, or an empty list when key does not exist. - /// + /// Task HashKeysAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Returns the number of fields contained in the hash stored at key. - /// - /// The key of the hash. - /// The flags to use for this operation. - /// The number of fields in the hash, or 0 when key does not exist. - /// + /// Task HashLengthAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Gets a random field from the hash at . - /// - /// The key of the hash. - /// The flags to use for this operation. - /// A random hash field name or if the hash does not exist. - /// + /// Task HashRandomFieldAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Gets field names from the hash at . - /// - /// The key of the hash. - /// The number of fields to return. - /// The flags to use for this operation. - /// An array of hash field names of size of at most , or if the hash does not exist. - /// + /// Task HashRandomFieldsAsync(RedisKey key, long count, CommandFlags flags = CommandFlags.None); - /// - /// Gets field names and values from the hash at . - /// - /// The key of the hash. - /// The number of fields to return. - /// The flags to use for this operation. - /// An array of hash entries of size of at most , or if the hash does not exist. - /// + /// Task HashRandomFieldsWithValuesAsync(RedisKey key, long count, CommandFlags flags = CommandFlags.None); - /// - /// The HSCAN command is used to incrementally iterate over a hash. - /// Note: to resume an iteration via cursor, cast the original enumerable or enumerator to . - /// - /// The key of the hash. - /// The pattern of keys to get entries for. - /// The page size to iterate by. - /// The cursor position to start at. - /// The page offset to start at. - /// The flags to use for this operation. - /// Yields all elements of the hash matching the pattern. - /// + /// IAsyncEnumerable HashScanAsync(RedisKey key, RedisValue pattern = default, int pageSize = RedisBase.CursorUtils.DefaultLibraryPageSize, long cursor = RedisBase.CursorUtils.Origin, int pageOffset = 0, CommandFlags flags = CommandFlags.None); - /// - /// Sets the specified fields to their respective values in the hash stored at key. - /// This command overwrites any specified fields that already exist in the hash, leaving other unspecified fields untouched. - /// If key does not exist, a new key holding a hash is created. - /// - /// The key of the hash. - /// The entries to set in the hash. - /// The flags to use for this operation. - /// + /// Task HashSetAsync(RedisKey key, HashEntry[] hashFields, CommandFlags flags = CommandFlags.None); - /// - /// Sets field in the hash stored at key to value. - /// If key does not exist, a new key holding a hash is created. - /// If field already exists in the hash, it is overwritten. - /// - /// The key of the hash. - /// The field to set in the hash. - /// The value to set. - /// Which conditions under which to set the field value (defaults to always). - /// The flags to use for this operation. - /// if field is a new field in the hash and value was set, if field already exists in the hash and the value was updated. - /// - /// , - /// - /// + /// Task HashSetAsync(RedisKey key, RedisValue hashField, RedisValue value, When when = When.Always, CommandFlags flags = CommandFlags.None); - /// - /// Returns the string length of the value associated with field in the hash stored at key. - /// - /// The key of the hash. - /// The field containing the string - /// The flags to use for this operation. - /// The length of the string at field, or 0 when key does not exist. - /// + /// Task HashStringLengthAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); - /// - /// Returns all values in the hash stored at key. - /// - /// The key of the hash. - /// The flags to use for this operation. - /// List of values in the hash, or an empty list when key does not exist. - /// + /// Task HashValuesAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Adds the element to the HyperLogLog data structure stored at the variable name specified as first argument. - /// - /// The key of the hyperloglog. - /// The value to add. - /// The flags to use for this operation. - /// if at least 1 HyperLogLog internal register was altered, otherwise. - /// + /// Task HyperLogLogAddAsync(RedisKey key, RedisValue value, CommandFlags flags = CommandFlags.None); - /// - /// Adds all the element arguments to the HyperLogLog data structure stored at the variable name specified as first argument. - /// - /// The key of the hyperloglog. - /// The values to add. - /// The flags to use for this operation. - /// if at least 1 HyperLogLog internal register was altered, otherwise. - /// + /// Task HyperLogLogAddAsync(RedisKey key, RedisValue[] values, CommandFlags flags = CommandFlags.None); - /// - /// Returns the approximated cardinality computed by the HyperLogLog data structure stored at the specified variable, or 0 if the variable does not exist. - /// - /// The key of the hyperloglog. - /// The flags to use for this operation. - /// The approximated number of unique elements observed via HyperLogLogAdd. - /// + /// Task HyperLogLogLengthAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Returns the approximated cardinality of the union of the HyperLogLogs passed, by internally merging the HyperLogLogs stored at the provided keys into a temporary hyperLogLog, or 0 if the variable does not exist. - /// - /// The keys of the hyperloglogs. - /// The flags to use for this operation. - /// The approximated number of unique elements observed via HyperLogLogAdd. - /// + /// Task HyperLogLogLengthAsync(RedisKey[] keys, CommandFlags flags = CommandFlags.None); - /// - /// Merge multiple HyperLogLog values into an unique value that will approximate the cardinality of the union of the observed Sets of the source HyperLogLog structures. - /// - /// The key of the merged hyperloglog. - /// The key of the first hyperloglog to merge. - /// The key of the first hyperloglog to merge. - /// The flags to use for this operation. - /// + /// Task HyperLogLogMergeAsync(RedisKey destination, RedisKey first, RedisKey second, CommandFlags flags = CommandFlags.None); - /// - /// Merge multiple HyperLogLog values into an unique value that will approximate the cardinality of the union of the observed Sets of the source HyperLogLog structures. - /// - /// The key of the merged hyperloglog. - /// The keys of the hyperloglogs to merge. - /// The flags to use for this operation. - /// + /// Task HyperLogLogMergeAsync(RedisKey destination, RedisKey[] sourceKeys, CommandFlags flags = CommandFlags.None); - /// - /// Indicate exactly which redis server we are talking to. - /// - /// The key to check. - /// The flags to use for this operation. - /// The endpoint serving the key. + /// Task IdentifyEndpointAsync(RedisKey key = default, CommandFlags flags = CommandFlags.None); - /// - /// Copies the value from the to the specified . - /// - /// The key of the source value to copy. - /// The destination key to copy the source to. - /// The database ID to store in. If default (-1), current database is used. - /// Whether to overwrite an existing values at . If and the key exists, the copy will not succeed. - /// The flags to use for this operation. - /// if key was copied. if key was not copied. - /// + /// Task KeyCopyAsync(RedisKey sourceKey, RedisKey destinationKey, int destinationDatabase = -1, bool replace = false, CommandFlags flags = CommandFlags.None); - /// - /// Removes the specified key. A key is ignored if it does not exist. - /// If UNLINK is available (Redis 4.0+), it will be used. - /// - /// The key to delete. - /// The flags to use for this operation. - /// if the key was removed. - /// - /// , - /// - /// + /// Task KeyDeleteAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Removes the specified keys. A key is ignored if it does not exist. - /// If UNLINK is available (Redis 4.0+), it will be used. - /// - /// The keys to delete. - /// The flags to use for this operation. - /// The number of keys that were removed. - /// - /// , - /// - /// + /// Task KeyDeleteAsync(RedisKey[] keys, CommandFlags flags = CommandFlags.None); - /// - /// Serialize the value stored at key in a Redis-specific format and return it to the user. - /// The returned value can be synthesized back into a Redis key using the RESTORE command. - /// - /// The key to dump. - /// The flags to use for this operation. - /// The serialized value. - /// + /// Task KeyDumpAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Returns the internal encoding for the Redis object stored at . - /// - /// The key to dump. - /// The flags to use for this operation. - /// The Redis encoding for the value or is the key does not exist. - /// + /// Task KeyEncodingAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Returns if key exists. - /// - /// The key to check. - /// The flags to use for this operation. - /// if the key exists. if the key does not exist. - /// + /// Task KeyExistsAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Indicates how many of the supplied keys exists. - /// - /// The keys to check. - /// The flags to use for this operation. - /// The number of keys that existed. - /// + /// Task KeyExistsAsync(RedisKey[] keys, CommandFlags flags = CommandFlags.None); - /// - /// Set a timeout on . - /// After the timeout has expired, the key will automatically be deleted. - /// A key with an associated timeout is said to be volatile in Redis terminology. - /// - /// The key to set the expiration for. - /// The timeout to set. - /// The flags to use for this operation. - /// if the timeout was set. if key does not exist or the timeout could not be set. - /// - /// If key is updated before the timeout has expired, then the timeout is removed as if the PERSIST command was invoked on key. - /// - /// For Redis versions < 2.1.3, existing timeouts cannot be overwritten. - /// So, if key already has an associated timeout, it will do nothing and return 0. - /// - /// - /// Since Redis 2.1.3, you can update the timeout of a key. - /// It is also possible to remove the timeout using the PERSIST command. - /// See the page on key expiry for more information. - /// - /// - /// , - /// , - /// - /// - /// + /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] Task KeyExpireAsync(RedisKey key, TimeSpan? expiry, CommandFlags flags); - /// - /// Set a timeout on . - /// After the timeout has expired, the key will automatically be deleted. - /// A key with an associated timeout is said to be volatile in Redis terminology. - /// - /// The key to set the expiration for. - /// The timeout to set. - /// In Redis 7+, we choose under which condition the expiration will be set using . - /// The flags to use for this operation. - /// if the timeout was set. if key does not exist or the timeout could not be set. - /// - /// , - /// - /// + /// Task KeyExpireAsync(RedisKey key, TimeSpan? expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); - /// - /// Set a timeout on . - /// After the timeout has expired, the key will automatically be deleted. - /// A key with an associated timeout is said to be volatile in Redis terminology. - /// - /// The key to set the expiration for. - /// The exact date to expiry to set. - /// The flags to use for this operation. - /// if the timeout was set. if key does not exist or the timeout could not be set. - /// - /// If key is updated before the timeout has expired, then the timeout is removed as if the PERSIST command was invoked on key. - /// - /// For Redis versions < 2.1.3, existing timeouts cannot be overwritten. - /// So, if key already has an associated timeout, it will do nothing and return 0. - /// - /// - /// Since Redis 2.1.3, you can update the timeout of a key. - /// It is also possible to remove the timeout using the PERSIST command. - /// See the page on key expiry for more information. - /// - /// - /// , - /// , - /// - /// - /// + /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] Task KeyExpireAsync(RedisKey key, DateTime? expiry, CommandFlags flags); - /// - /// Set a timeout on . - /// After the timeout has expired, the key will automatically be deleted. - /// A key with an associated timeout is said to be volatile in Redis terminology. - /// - /// The key to set the expiration for. - /// The timeout to set. - /// In Redis 7+, we choose under which condition the expiration will be set using . - /// The flags to use for this operation. - /// if the timeout was set. if key does not exist or the timeout could not be set. - /// - /// , - /// - /// + /// Task KeyExpireAsync(RedisKey key, DateTime? expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); - /// - /// Returns the absolute time at which the given will expire, if it exists and has an expiration. - /// - /// The key to get the expiration for. - /// The flags to use for this operation. - /// The time at which the given key will expire, or if the key does not exist or has no associated expiration time. - /// - /// , - /// - /// + /// Task KeyExpireTimeAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Returns the logarithmic access frequency counter of the object stored at . - /// The command is only available when the maxmemory-policy configuration directive is set to - /// one of the LFU policies. - /// - /// The key to get a frequency count for. - /// The flags to use for this operation. - /// The number of logarithmic access frequency counter, ( if the key does not exist). - /// + /// Task KeyFrequencyAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Returns the time since the object stored at the specified key is idle (not requested by read or write operations). - /// - /// The key to get the time of. - /// The flags to use for this operation. - /// The time since the object stored at the specified key is idle. - /// + /// Task KeyIdleTimeAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Move key from the currently selected database (see SELECT) to the specified destination database. - /// When key already exists in the destination database, or it does not exist in the source database, it does nothing. - /// It is possible to use MOVE as a locking primitive because of this. - /// - /// The key to move. - /// The database to move the key to. - /// The flags to use for this operation. - /// if key was moved. if key was not moved. - /// + /// Task KeyMoveAsync(RedisKey key, int database, CommandFlags flags = CommandFlags.None); - /// - /// Remove the existing timeout on key, turning the key from volatile (a key with an expire set) to persistent (a key that will never expire as no timeout is associated). - /// - /// The key to persist. - /// The flags to use for this operation. - /// if the timeout was removed. if key does not exist or does not have an associated timeout. - /// + /// Task KeyPersistAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Return a random key from the currently selected database. - /// - /// The flags to use for this operation. - /// The random key, or when the database is empty. - /// + /// Task KeyRandomAsync(CommandFlags flags = CommandFlags.None); - /// - /// Returns the reference count of the object stored at . - /// - /// The key to get a reference count for. - /// The flags to use for this operation. - /// The number of references ( if the key does not exist). - /// + /// Task KeyRefCountAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Renames to . - /// It returns an error when the source and destination names are the same, or when key does not exist. - /// - /// The key to rename. - /// The key to rename to. - /// What conditions to rename under (defaults to always). - /// The flags to use for this operation. - /// if the key was renamed, otherwise. - /// - /// , - /// - /// + /// Task KeyRenameAsync(RedisKey key, RedisKey newKey, When when = When.Always, CommandFlags flags = CommandFlags.None); - /// - /// Create a key associated with a value that is obtained by deserializing the provided serialized value (obtained via DUMP). - /// If is 0 the key is created without any expire, otherwise the specified expire time (in milliseconds) is set. - /// - /// The key to restore. - /// The value of the key. - /// The expiry to set. - /// The flags to use for this operation. - /// + /// Task KeyRestoreAsync(RedisKey key, byte[] value, TimeSpan? expiry = null, CommandFlags flags = CommandFlags.None); - /// - /// Returns the remaining time to live of a key that has a timeout. - /// This introspection capability allows a Redis client to check how many seconds a given key will continue to be part of the dataset. - /// - /// The key to check. - /// The flags to use for this operation. - /// TTL, or when key does not exist or does not have a timeout. - /// + /// Task KeyTimeToLiveAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Alters the last access time of a key. - /// - /// The key to touch. - /// The flags to use for this operation. - /// if the key was touched, otherwise. - /// + /// Task KeyTouchAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Alters the last access time of the specified . A key is ignored if it does not exist. - /// - /// The keys to touch. - /// The flags to use for this operation. - /// The number of keys that were touched. - /// + /// Task KeyTouchAsync(RedisKey[] keys, CommandFlags flags = CommandFlags.None); - /// - /// Returns the string representation of the type of the value stored at key. - /// The different types that can be returned are: string, list, set, zset and hash. - /// - /// The key to get the type of. - /// The flags to use for this operation. - /// Type of key, or none when key does not exist. - /// + /// Task KeyTypeAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Returns the element at index in the list stored at key. - /// The index is zero-based, so 0 means the first element, 1 the second element and so on. - /// Negative indices can be used to designate elements starting at the tail of the list. - /// Here, -1 means the last element, -2 means the penultimate and so forth. - /// - /// The key of the list. - /// The index position to get the value at. - /// The flags to use for this operation. - /// The requested element, or when index is out of range. - /// + /// Task ListGetByIndexAsync(RedisKey key, long index, CommandFlags flags = CommandFlags.None); - /// - /// Inserts value in the list stored at key either before or after the reference value pivot. - /// When key does not exist, it is considered an empty list and no operation is performed. - /// - /// The key of the list. - /// The value to insert after. - /// The value to insert. - /// The flags to use for this operation. - /// The length of the list after the insert operation, or -1 when the value pivot was not found. - /// + /// Task ListInsertAfterAsync(RedisKey key, RedisValue pivot, RedisValue value, CommandFlags flags = CommandFlags.None); - /// - /// Inserts value in the list stored at key either before or after the reference value pivot. - /// When key does not exist, it is considered an empty list and no operation is performed. - /// - /// The key of the list. - /// The value to insert before. - /// The value to insert. - /// The flags to use for this operation. - /// The length of the list after the insert operation, or -1 when the value pivot was not found. - /// + /// Task ListInsertBeforeAsync(RedisKey key, RedisValue pivot, RedisValue value, CommandFlags flags = CommandFlags.None); - /// - /// Removes and returns the first element of the list stored at key. - /// - /// The key of the list. - /// The flags to use for this operation. - /// The value of the first element, or when key does not exist. - /// + /// Task ListLeftPopAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Removes and returns count elements from the head of the list stored at key. - /// If the list contains less than count elements, removes and returns the number of elements in the list. - /// - /// The key of the list. - /// The number of elements to remove - /// The flags to use for this operation. - /// Array of values that were popped, or if the key doesn't exist. - /// + /// Task ListLeftPopAsync(RedisKey key, long count, CommandFlags flags = CommandFlags.None); - /// - /// Removes and returns at most elements from the first non-empty list in . - /// Starts on the left side of the list. - /// - /// The keys to look through for elements to pop. - /// The maximum number of elements to pop from the list. - /// The flags to use for this operation. - /// A span of contiguous elements from the list, or if no non-empty lists are found. - /// + /// Task ListLeftPopAsync(RedisKey[] keys, long count, CommandFlags flags = CommandFlags.None); - /// - /// Scans through the list stored at looking for , returning the 0-based - /// index of the first matching element. - /// - /// The key of the list. - /// The element to search for. - /// The rank of the first element to return, within the sub-list of matching indexes in the case of multiple matches. - /// The maximum number of elements to scan through before stopping, defaults to 0 (a full scan of the list.) - /// The flags to use for this operation. - /// The 0-based index of the first matching element, or -1 if not found. - /// + /// Task ListPositionAsync(RedisKey key, RedisValue element, long rank = 1, long maxLength = 0, CommandFlags flags = CommandFlags.None); - /// - /// Scans through the list stored at looking for instances of , returning the 0-based - /// indexes of any matching elements. - /// - /// The key of the list. - /// The element to search for. - /// The number of matches to find. A count of 0 will return the indexes of all occurrences of the element. - /// The rank of the first element to return, within the sub-list of matching indexes in the case of multiple matches. - /// The maximum number of elements to scan through before stopping, defaults to 0 (a full scan of the list.) - /// The flags to use for this operation. - /// An array of at most of indexes of matching elements. If none are found, and empty array is returned. - /// + /// Task ListPositionsAsync(RedisKey key, RedisValue element, long count, long rank = 1, long maxLength = 0, CommandFlags flags = CommandFlags.None); - /// - /// Insert the specified value at the head of the list stored at key. - /// If key does not exist, it is created as empty list before performing the push operations. - /// - /// The key of the list. - /// The value to add to the head of the list. - /// Which conditions to add to the list under (defaults to always). - /// The flags to use for this operation. - /// The length of the list after the push operations. - /// - /// , - /// - /// + /// Task ListLeftPushAsync(RedisKey key, RedisValue value, When when = When.Always, CommandFlags flags = CommandFlags.None); - /// - /// Insert the specified value at the head of the list stored at key. - /// If key does not exist, it is created as empty list before performing the push operations. - /// - /// The key of the list. - /// The value to add to the head of the list. - /// Which conditions to add to the list under (defaults to always). - /// The flags to use for this operation. - /// The length of the list after the push operations. - /// - /// , - /// - /// + /// Task ListLeftPushAsync(RedisKey key, RedisValue[] values, When when = When.Always, CommandFlags flags = CommandFlags.None); - /// - /// Insert all the specified values at the head of the list stored at key. - /// If key does not exist, it is created as empty list before performing the push operations. - /// Elements are inserted one after the other to the head of the list, from the leftmost element to the rightmost element. - /// So for instance the command LPUSH mylist a b c will result into a list containing c as first element, b as second element and a as third element. - /// - /// The key of the list. - /// The values to add to the head of the list. - /// The flags to use for this operation. - /// The length of the list after the push operations. - /// + /// Task ListLeftPushAsync(RedisKey key, RedisValue[] values, CommandFlags flags); - /// - /// Returns the length of the list stored at key. If key does not exist, it is interpreted as an empty list and 0 is returned. - /// - /// The key of the list. - /// The flags to use for this operation. - /// The length of the list at key. - /// + /// Task ListLengthAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Returns and removes the first or last element of the list stored at , and pushes the element - /// as the first or last element of the list stored at . - /// - /// The key of the list to remove from. - /// The key of the list to move to. - /// What side of the list to remove from. - /// What side of the list to move to. - /// The flags to use for this operation. - /// The element being popped and pushed or if there is no element to move. - /// + /// Task ListMoveAsync(RedisKey sourceKey, RedisKey destinationKey, ListSide sourceSide, ListSide destinationSide, CommandFlags flags = CommandFlags.None); - /// - /// Returns the specified elements of the list stored at key. - /// The offsets start and stop are zero-based indexes, with 0 being the first element of the list (the head of the list), 1 being the next element and so on. - /// These offsets can also be negative numbers indicating offsets starting at the end of the list.For example, -1 is the last element of the list, -2 the penultimate, and so on. - /// Note that if you have a list of numbers from 0 to 100, LRANGE list 0 10 will return 11 elements, that is, the rightmost item is included. - /// - /// The key of the list. - /// The start index of the list. - /// The stop index of the list. - /// The flags to use for this operation. - /// List of elements in the specified range. - /// + /// Task ListRangeAsync(RedisKey key, long start = 0, long stop = -1, CommandFlags flags = CommandFlags.None); - /// - /// Removes the first count occurrences of elements equal to value from the list stored at key. - /// The count argument influences the operation in the following ways: - /// - /// count > 0: Remove elements equal to value moving from head to tail. - /// count < 0: Remove elements equal to value moving from tail to head. - /// count = 0: Remove all elements equal to value. - /// - /// - /// The key of the list. - /// The value to remove from the list. - /// The count behavior (see method summary). - /// The flags to use for this operation. - /// The number of removed elements. - /// + /// Task ListRemoveAsync(RedisKey key, RedisValue value, long count = 0, CommandFlags flags = CommandFlags.None); - /// - /// Removes and returns the last element of the list stored at key. - /// - /// The key of the list. - /// The flags to use for this operation. - /// The element being popped, or when key does not exist.. - /// + /// Task ListRightPopAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Removes and returns count elements from the end the list stored at key. - /// If the list contains less than count elements, removes and returns the number of elements in the list. - /// - /// The key of the list. - /// The number of elements to pop - /// The flags to use for this operation. - /// Array of values that were popped, or if the key doesn't exist. - /// + /// Task ListRightPopAsync(RedisKey key, long count, CommandFlags flags = CommandFlags.None); - /// - /// Removes and returns at most elements from the first non-empty list in . - /// Starts on the right side of the list. - /// - /// The keys to look through for elements to pop. - /// The maximum number of elements to pop from the list. - /// The flags to use for this operation. - /// A span of contiguous elements from the list, or if no non-empty lists are found. - /// + /// Task ListRightPopAsync(RedisKey[] keys, long count, CommandFlags flags = CommandFlags.None); - /// - /// Atomically returns and removes the last element (tail) of the list stored at source, and pushes the element at the first element (head) of the list stored at destination. - /// - /// The key of the source list. - /// The key of the destination list. - /// The flags to use for this operation. - /// The element being popped and pushed. - /// + /// Task ListRightPopLeftPushAsync(RedisKey source, RedisKey destination, CommandFlags flags = CommandFlags.None); - /// - /// Insert the specified value at the tail of the list stored at key. - /// If key does not exist, it is created as empty list before performing the push operation. - /// - /// The key of the list. - /// The value to add to the tail of the list. - /// Which conditions to add to the list under. - /// The flags to use for this operation. - /// The length of the list after the push operation. - /// - /// , - /// - /// + /// Task ListRightPushAsync(RedisKey key, RedisValue value, When when = When.Always, CommandFlags flags = CommandFlags.None); - /// - /// Insert the specified value at the tail of the list stored at key. - /// If key does not exist, it is created as empty list before performing the push operation. - /// - /// The key of the list. - /// The values to add to the tail of the list. - /// Which conditions to add to the list under. - /// The flags to use for this operation. - /// The length of the list after the push operation. - /// - /// , - /// - /// + /// Task ListRightPushAsync(RedisKey key, RedisValue[] values, When when = When.Always, CommandFlags flags = CommandFlags.None); - /// - /// Insert all the specified values at the tail of the list stored at key. - /// If key does not exist, it is created as empty list before performing the push operation. - /// Elements are inserted one after the other to the tail of the list, from the leftmost element to the rightmost element. - /// So for instance the command RPUSH mylist a b c will result into a list containing a as first element, b as second element and c as third element. - /// - /// The key of the list. - /// The values to add to the tail of the list. - /// The flags to use for this operation. - /// The length of the list after the push operation. - /// + /// Task ListRightPushAsync(RedisKey key, RedisValue[] values, CommandFlags flags); - /// - /// Sets the list element at index to value. - /// For more information on the index argument, see . - /// An error is returned for out of range indexes. - /// - /// The key of the list. - /// The index to set the value at. - /// The values to add to the list. - /// The flags to use for this operation. - /// + /// Task ListSetByIndexAsync(RedisKey key, long index, RedisValue value, CommandFlags flags = CommandFlags.None); - /// - /// Trim an existing list so that it will contain only the specified range of elements specified. - /// Both start and stop are zero-based indexes, where 0 is the first element of the list (the head), 1 the next element and so on. - /// For example: LTRIM foobar 0 2 will modify the list stored at foobar so that only the first three elements of the list will remain. - /// start and end can also be negative numbers indicating offsets from the end of the list, where -1 is the last element of the list, -2 the penultimate element and so on. - /// - /// The key of the list. - /// The start index of the list to trim to. - /// The end index of the list to trim to. - /// The flags to use for this operation. - /// + /// Task ListTrimAsync(RedisKey key, long start, long stop, CommandFlags flags = CommandFlags.None); - /// - /// Extends a lock, if the token value is correct. - /// - /// The key of the lock. - /// The value to set at the key. - /// The expiration of the lock key. - /// The flags to use for this operation. - /// if the lock was successfully extended. + /// Task LockExtendAsync(RedisKey key, RedisValue value, TimeSpan expiry, CommandFlags flags = CommandFlags.None); - /// - /// Queries the token held against a lock. - /// - /// The key of the lock. - /// The flags to use for this operation. - /// The current value of the lock, if any. + /// Task LockQueryAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Releases a lock, if the token value is correct. - /// - /// The key of the lock. - /// The value at the key that must match. - /// The flags to use for this operation. - /// if the lock was successfully released, otherwise. + /// Task LockReleaseAsync(RedisKey key, RedisValue value, CommandFlags flags = CommandFlags.None); - /// - /// Takes a lock (specifying a token value) if it is not already taken. - /// - /// The key of the lock. - /// The value to set at the key. - /// The expiration of the lock key. - /// The flags to use for this operation. - /// if the lock was successfully taken, otherwise. + /// Task LockTakeAsync(RedisKey key, RedisValue value, TimeSpan expiry, CommandFlags flags = CommandFlags.None); - /// - /// Posts a message to the given channel. - /// - /// The channel to publish to. - /// The message to send. - /// The flags to use for this operation. - /// - /// The number of clients that received the message *on the destination server*, - /// note that this doesn't mean much in a cluster as clients can get the message through other nodes. - /// - /// + /// Task PublishAsync(RedisChannel channel, RedisValue message, CommandFlags flags = CommandFlags.None); - /// - /// Execute an arbitrary command against the server; this is primarily intended for executing modules, - /// but may also be used to provide access to new features that lack a direct API. - /// - /// The command to run. - /// The arguments to pass for the command. - /// A dynamic representation of the command's result. - /// This API should be considered an advanced feature; inappropriate use can be harmful. + /// Task ExecuteAsync(string command, params object[] args); - /// - /// Execute an arbitrary command against the server; this is primarily intended for executing modules, - /// but may also be used to provide access to new features that lack a direct API. - /// - /// The command to run. - /// The arguments to pass for the command. - /// The flags to use for this operation. - /// A dynamic representation of the command's result. - /// This API should be considered an advanced feature; inappropriate use can be harmful. + /// Task ExecuteAsync(string command, ICollection? args, CommandFlags flags = CommandFlags.None); - /// - /// Execute a Lua script against the server. - /// - /// The script to execute. - /// The keys to execute against. - /// The values to execute against. - /// The flags to use for this operation. - /// A dynamic representation of the script's result. - /// - /// , - /// - /// + /// Task ScriptEvaluateAsync(string script, RedisKey[]? keys = null, RedisValue[]? values = null, CommandFlags flags = CommandFlags.None); - /// - /// Execute a Lua script against the server using just the SHA1 hash. - /// - /// The hash of the script to execute. - /// The keys to execute against. - /// The values to execute against. - /// The flags to use for this operation. - /// A dynamic representation of the script's result. - /// - /// Be aware that this method is not resilient to Redis server restarts. Use instead. - /// - /// + /// [EditorBrowsable(EditorBrowsableState.Never)] Task ScriptEvaluateAsync(byte[] hash, RedisKey[]? keys = null, RedisValue[]? values = null, CommandFlags flags = CommandFlags.None); - /// - /// Execute a lua script against the server, using previously prepared script. - /// Named parameters, if any, are provided by the `parameters` object. - /// - /// The script to execute. - /// The parameters to pass to the script. - /// The flags to use for this operation. - /// A dynamic representation of the script's result. - /// + /// Task ScriptEvaluateAsync(LuaScript script, object? parameters = null, CommandFlags flags = CommandFlags.None); - /// - /// Execute a lua script against the server, using previously prepared and loaded script. - /// This method sends only the SHA1 hash of the lua script to Redis. - /// Named parameters, if any, are provided by the `parameters` object. - /// - /// The already-loaded script to execute. - /// The parameters to pass to the script. - /// The flags to use for this operation. - /// A dynamic representation of the script's result. - /// + /// Task ScriptEvaluateAsync(LoadedLuaScript script, object? parameters = null, CommandFlags flags = CommandFlags.None); - /// - /// Read-only variant of the EVAL command that cannot execute commands that modify data, Execute a Lua script against the server. - /// - /// The script to execute. - /// The keys to execute against. - /// The values to execute against. - /// The flags to use for this operation. - /// A dynamic representation of the script's result. - /// - /// , - /// - /// + /// Task ScriptEvaluateReadOnlyAsync(string script, RedisKey[]? keys = null, RedisValue[]? values = null, CommandFlags flags = CommandFlags.None); - /// - /// Read-only variant of the EVALSHA command that cannot execute commands that modify data, Execute a Lua script against the server using just the SHA1 hash. - /// - /// The hash of the script to execute. - /// The keys to execute against. - /// The values to execute against. - /// The flags to use for this operation. - /// A dynamic representation of the script's result. - /// + /// Task ScriptEvaluateReadOnlyAsync(byte[] hash, RedisKey[]? keys = null, RedisValue[]? values = null, CommandFlags flags = CommandFlags.None); - /// - /// Add the specified member to the set stored at key. - /// Specified members that are already a member of this set are ignored. - /// If key does not exist, a new set is created before adding the specified members. - /// - /// The key of the set. - /// The value to add to the set. - /// The flags to use for this operation. - /// if the specified member was not already present in the set, else . - /// + /// Task SetAddAsync(RedisKey key, RedisValue value, CommandFlags flags = CommandFlags.None); - /// - /// Add the specified members to the set stored at key. - /// Specified members that are already a member of this set are ignored. - /// If key does not exist, a new set is created before adding the specified members. - /// - /// The key of the set. - /// The values to add to the set. - /// The flags to use for this operation. - /// The number of elements that were added to the set, not including all the elements already present into the set. - /// + /// Task SetAddAsync(RedisKey key, RedisValue[] values, CommandFlags flags = CommandFlags.None); - /// - /// Returns the members of the set resulting from the specified operation against the given sets. - /// - /// The operation to perform. - /// The key of the first set. - /// The key of the second set. - /// The flags to use for this operation. - /// List with members of the resulting set. - /// - /// , - /// , - /// - /// + /// Task SetCombineAsync(SetOperation operation, RedisKey first, RedisKey second, CommandFlags flags = CommandFlags.None); - /// - /// Returns the members of the set resulting from the specified operation against the given sets. - /// - /// The operation to perform. - /// The keys of the sets to operate on. - /// The flags to use for this operation. - /// List with members of the resulting set. - /// - /// , - /// , - /// - /// + /// Task SetCombineAsync(SetOperation operation, RedisKey[] keys, CommandFlags flags = CommandFlags.None); - /// - /// This command is equal to SetCombine, but instead of returning the resulting set, it is stored in destination. - /// If destination already exists, it is overwritten. - /// - /// The operation to perform. - /// The key of the destination set. - /// The key of the first set. - /// The key of the second set. - /// The flags to use for this operation. - /// The number of elements in the resulting set. - /// - /// , - /// , - /// - /// + /// Task SetCombineAndStoreAsync(SetOperation operation, RedisKey destination, RedisKey first, RedisKey second, CommandFlags flags = CommandFlags.None); - /// - /// This command is equal to SetCombine, but instead of returning the resulting set, it is stored in destination. - /// If destination already exists, it is overwritten. - /// - /// The operation to perform. - /// The key of the destination set. - /// The keys of the sets to operate on. - /// The flags to use for this operation. - /// The number of elements in the resulting set. - /// - /// , - /// , - /// - /// + /// Task SetCombineAndStoreAsync(SetOperation operation, RedisKey destination, RedisKey[] keys, CommandFlags flags = CommandFlags.None); - /// - /// Returns whether is a member of the set stored at . - /// - /// The key of the set. - /// The value to check for. - /// The flags to use for this operation. - /// - /// if the element is a member of the set. - /// if the element is not a member of the set, or if key does not exist. - /// - /// + /// Task SetContainsAsync(RedisKey key, RedisValue value, CommandFlags flags = CommandFlags.None); - /// - /// Returns whether each of is a member of the set stored at . - /// - /// The key of the set. - /// The members to check for. - /// The flags to use for this operation. - /// - /// if the element is a member of the set. - /// if the element is not a member of the set, or if key does not exist. - /// - /// + /// Task SetContainsAsync(RedisKey key, RedisValue[] values, CommandFlags flags = CommandFlags.None); - /// - /// - /// Returns the set cardinality (number of elements) of the intersection between the sets stored at the given . - /// - /// - /// If the intersection cardinality reaches partway through the computation, - /// the algorithm will exit and yield as the cardinality. - /// - /// - /// The keys of the sets. - /// The number of elements to check (defaults to 0 and means unlimited). - /// The flags to use for this operation. - /// The cardinality (number of elements) of the set, or 0 if key does not exist. - /// + /// Task SetIntersectionLengthAsync(RedisKey[] keys, long limit = 0, CommandFlags flags = CommandFlags.None); - /// - /// Returns the set cardinality (number of elements) of the set stored at key. - /// - /// The key of the set. - /// The flags to use for this operation. - /// The cardinality (number of elements) of the set, or 0 if key does not exist. - /// + /// Task SetLengthAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Returns all the members of the set value stored at key. - /// - /// The key of the set. - /// The flags to use for this operation. - /// All elements of the set. - /// + /// Task SetMembersAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Move member from the set at source to the set at destination. - /// This operation is atomic. In every given moment the element will appear to be a member of source or destination for other clients. - /// When the specified element already exists in the destination set, it is only removed from the source set. - /// - /// The key of the source set. - /// The key of the destination set. - /// The value to move. - /// The flags to use for this operation. - /// - /// if the element is moved. - /// if the element is not a member of source and no operation was performed. - /// - /// + /// Task SetMoveAsync(RedisKey source, RedisKey destination, RedisValue value, CommandFlags flags = CommandFlags.None); - /// - /// Removes and returns a random element from the set value stored at key. - /// - /// The key of the set. - /// The flags to use for this operation. - /// The removed element, or when key does not exist. - /// + /// Task SetPopAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Removes and returns the specified number of random elements from the set value stored at key. - /// - /// The key of the set. - /// The number of elements to return. - /// The flags to use for this operation. - /// An array of elements, or an empty array when key does not exist. - /// + /// Task SetPopAsync(RedisKey key, long count, CommandFlags flags = CommandFlags.None); - /// - /// Return a random element from the set value stored at . - /// - /// The key of the set. - /// The flags to use for this operation. - /// The randomly selected element, or when does not exist. - /// + /// Task SetRandomMemberAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Return an array of count distinct elements if count is positive. - /// If called with a negative count the behavior changes and the command is allowed to return the same element multiple times. - /// In this case the number of returned elements is the absolute value of the specified count. - /// - /// The key of the set. - /// The count of members to get. - /// The flags to use for this operation. - /// An array of elements, or an empty array when does not exist. - /// + /// Task SetRandomMembersAsync(RedisKey key, long count, CommandFlags flags = CommandFlags.None); - /// - /// Remove the specified member from the set stored at key. - /// Specified members that are not a member of this set are ignored. - /// - /// The key of the set. - /// The value to remove. - /// The flags to use for this operation. - /// if the specified member was already present in the set, otherwise. - /// + /// Task SetRemoveAsync(RedisKey key, RedisValue value, CommandFlags flags = CommandFlags.None); - /// - /// Remove the specified members from the set stored at key. - /// Specified members that are not a member of this set are ignored. - /// - /// The key of the set. - /// The values to remove. - /// The flags to use for this operation. - /// The number of members that were removed from the set, not including non existing members. - /// + /// Task SetRemoveAsync(RedisKey key, RedisValue[] values, CommandFlags flags = CommandFlags.None); - /// - /// The SSCAN command is used to incrementally iterate over set. - /// Note: to resume an iteration via cursor, cast the original enumerable or enumerator to . - /// - /// The key of the set. - /// The pattern to match. - /// The page size to iterate by. - /// The cursor position to start at. - /// The page offset to start at. - /// The flags to use for this operation. - /// Yields all matching elements of the set. - /// + /// IAsyncEnumerable SetScanAsync(RedisKey key, RedisValue pattern = default, int pageSize = RedisBase.CursorUtils.DefaultLibraryPageSize, long cursor = RedisBase.CursorUtils.Origin, int pageOffset = 0, CommandFlags flags = CommandFlags.None); - /// - /// Sorts a list, set or sorted set (numerically or alphabetically, ascending by default). - /// By default, the elements themselves are compared, but the values can also be used to perform external key-lookups using the by parameter. - /// By default, the elements themselves are returned, but external key-lookups (one or many) can be performed instead by specifying - /// the get parameter (note that # specifies the element itself, when used in get). - /// Referring to the redis SORT documentation for examples is recommended. - /// When used in hashes, by and get can be used to specify fields using -> notation (again, refer to redis documentation). - /// Uses SORT_RO when possible. - /// - /// The key of the list, set, or sorted set. - /// How many entries to skip on the return. - /// How many entries to take on the return. - /// The ascending or descending order (defaults to ascending). - /// The sorting method (defaults to numeric). - /// The key pattern to sort by, if any. e.g. ExternalKey_* would sort by ExternalKey_{listvalue} as a lookup. - /// The key pattern to sort by, if any e.g. ExternalKey_* would return the value of ExternalKey_{listvalue} for each entry. - /// The flags to use for this operation. - /// The sorted elements, or the external values if get is specified. - /// - /// , - /// - /// + /// Task SortAsync(RedisKey key, long skip = 0, long take = -1, Order order = Order.Ascending, SortType sortType = SortType.Numeric, RedisValue by = default, RedisValue[]? get = null, CommandFlags flags = CommandFlags.None); - /// - /// Sorts a list, set or sorted set (numerically or alphabetically, ascending by default). - /// By default, the elements themselves are compared, but the values can also be used to perform external key-lookups using the by parameter. - /// By default, the elements themselves are returned, but external key-lookups (one or many) can be performed instead by specifying - /// the get parameter (note that # specifies the element itself, when used in get). - /// Referring to the redis SORT documentation for examples is recommended. - /// When used in hashes, by and get can be used to specify fields using -> notation (again, refer to redis documentation). - /// - /// The destination key to store results in. - /// The key of the list, set, or sorted set. - /// How many entries to skip on the return. - /// How many entries to take on the return. - /// The ascending or descending order (defaults to ascending). - /// The sorting method (defaults to numeric). - /// The key pattern to sort by, if any. e.g. ExternalKey_* would sort by ExternalKey_{listvalue} as a lookup. - /// The key pattern to sort by, if any e.g. ExternalKey_* would return the value of ExternalKey_{listvalue} for each entry. - /// The flags to use for this operation. - /// The number of elements stored in the new list. - /// + /// Task SortAndStoreAsync(RedisKey destination, RedisKey key, long skip = 0, long take = -1, Order order = Order.Ascending, SortType sortType = SortType.Numeric, RedisValue by = default, RedisValue[]? get = null, CommandFlags flags = CommandFlags.None); - /// + /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] Task SortedSetAddAsync(RedisKey key, RedisValue member, double score, CommandFlags flags); - /// + /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] Task SortedSetAddAsync(RedisKey key, RedisValue member, double score, When when, CommandFlags flags = CommandFlags.None); - /// - /// Adds the specified member with the specified score to the sorted set stored at key. - /// If the specified member is already a member of the sorted set, the score is updated and the element reinserted at the right position to ensure the correct ordering. - /// - /// The key of the sorted set. - /// The member to add to the sorted set. - /// The score for the member to add to the sorted set. - /// What conditions to add the element under (defaults to always). - /// The flags to use for this operation. - /// if the value was added. if it already existed (the score is still updated). - /// + /// Task SortedSetAddAsync(RedisKey key, RedisValue member, double score, SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None); - /// + /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] Task SortedSetAddAsync(RedisKey key, SortedSetEntry[] values, CommandFlags flags); - /// + /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] Task SortedSetAddAsync(RedisKey key, SortedSetEntry[] values, When when, CommandFlags flags = CommandFlags.None); - /// - /// Adds all the specified members with the specified scores to the sorted set stored at key. - /// If a specified member is already a member of the sorted set, the score is updated and the element reinserted at the right position to ensure the correct ordering. - /// - /// The key of the sorted set. - /// The members and values to add to the sorted set. - /// What conditions to add the element under (defaults to always). - /// The flags to use for this operation. - /// The number of elements added to the sorted sets, not including elements already existing for which the score was updated. - /// + /// Task SortedSetAddAsync(RedisKey key, SortedSetEntry[] values, SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None); - /// - /// Computes a set operation for multiple sorted sets (optionally using per-set ), - /// optionally performing a specific aggregation (defaults to ). - /// cannot be used with weights or aggregation. - /// - /// The operation to perform. - /// The keys of the sorted sets. - /// The optional weights per set that correspond to . - /// The aggregation method (defaults to ). - /// The flags to use for this operation. - /// The resulting sorted set. - /// - /// , - /// , - /// - /// + /// Task SortedSetCombineAsync(SetOperation operation, RedisKey[] keys, double[]? weights = null, Aggregate aggregate = Aggregate.Sum, CommandFlags flags = CommandFlags.None); - /// - /// Computes a set operation for multiple sorted sets (optionally using per-set ), - /// optionally performing a specific aggregation (defaults to ). - /// cannot be used with weights or aggregation. - /// - /// The operation to perform. - /// The keys of the sorted sets. - /// The optional weights per set that correspond to . - /// The aggregation method (defaults to ). - /// The flags to use for this operation. - /// The resulting sorted set with scores. - /// - /// , - /// , - /// - /// + /// Task SortedSetCombineWithScoresAsync(SetOperation operation, RedisKey[] keys, double[]? weights = null, Aggregate aggregate = Aggregate.Sum, CommandFlags flags = CommandFlags.None); - /// - /// Computes a set operation over two sorted sets, and stores the result in destination, optionally performing - /// a specific aggregation (defaults to sum). - /// cannot be used with aggregation. - /// - /// The operation to perform. - /// The key to store the results in. - /// The key of the first sorted set. - /// The key of the second sorted set. - /// The aggregation method (defaults to sum). - /// The flags to use for this operation. - /// The number of elements in the resulting sorted set at destination. - /// - /// , - /// , - /// - /// + /// Task SortedSetCombineAndStoreAsync(SetOperation operation, RedisKey destination, RedisKey first, RedisKey second, Aggregate aggregate = Aggregate.Sum, CommandFlags flags = CommandFlags.None); - /// - /// Computes a set operation over multiple sorted sets (optionally using per-set weights), and stores the result in destination, optionally performing - /// a specific aggregation (defaults to sum). - /// cannot be used with aggregation. - /// - /// The operation to perform. - /// The key to store the results in. - /// The keys of the sorted sets. - /// The optional weights per set that correspond to . - /// The aggregation method (defaults to sum). - /// The flags to use for this operation. - /// The number of elements in the resulting sorted set at destination. - /// - /// , - /// , - /// - /// - Task SortedSetCombineAndStoreAsync(SetOperation operation, RedisKey destination, RedisKey[] keys, double[]? weights = null, Aggregate aggregate = Aggregate.Sum, CommandFlags flags = CommandFlags.None); - - /// - /// Decrements the score of member in the sorted set stored at key by decrement. - /// If member does not exist in the sorted set, it is added with -decrement as its score (as if its previous score was 0.0). - /// - /// The key of the sorted set. - /// The member to decrement. - /// The amount to decrement by. - /// The flags to use for this operation. - /// The new score of member. - /// + /// + Task SortedSetCombineAndStoreAsync(SetOperation operation, RedisKey destination, RedisKey[] keys, double[]? weights = null, Aggregate aggregate = Aggregate.Sum, CommandFlags flags = CommandFlags.None); + + /// Task SortedSetDecrementAsync(RedisKey key, RedisValue member, double value, CommandFlags flags = CommandFlags.None); - /// - /// Increments the score of member in the sorted set stored at key by increment. If member does not exist in the sorted set, it is added with increment as its score (as if its previous score was 0.0). - /// - /// The key of the sorted set. - /// The member to increment. - /// The amount to increment by. - /// The flags to use for this operation. - /// The new score of member. - /// + /// Task SortedSetIncrementAsync(RedisKey key, RedisValue member, double value, CommandFlags flags = CommandFlags.None); - /// - /// Returns the cardinality of the intersection of the sorted sets at . - /// - /// The keys of the sorted sets. - /// If the intersection cardinality reaches partway through the computation, the algorithm will exit and yield as the cardinality (defaults to 0 meaning unlimited). - /// The flags to use for this operation. - /// The number of elements in the resulting intersection. - /// + /// Task SortedSetIntersectionLengthAsync(RedisKey[] keys, long limit = 0, CommandFlags flags = CommandFlags.None); - /// - /// Returns the sorted set cardinality (number of elements) of the sorted set stored at key. - /// - /// The key of the sorted set. - /// The min score to filter by (defaults to negative infinity). - /// The max score to filter by (defaults to positive infinity). - /// Whether to exclude and from the range check (defaults to both inclusive). - /// The flags to use for this operation. - /// The cardinality (number of elements) of the sorted set, or 0 if key does not exist. - /// + /// Task SortedSetLengthAsync(RedisKey key, double min = double.NegativeInfinity, double max = double.PositiveInfinity, Exclude exclude = Exclude.None, CommandFlags flags = CommandFlags.None); - /// - /// When all the elements in a sorted set are inserted with the same score, in order to force lexicographical ordering. - /// This command returns the number of elements in the sorted set at key with a value between min and max. - /// - /// The key of the sorted set. - /// The min value to filter by. - /// The max value to filter by. - /// Whether to exclude and from the range check (defaults to both inclusive). - /// The flags to use for this operation. - /// The number of elements in the specified score range. - /// + /// Task SortedSetLengthByValueAsync(RedisKey key, RedisValue min, RedisValue max, Exclude exclude = Exclude.None, CommandFlags flags = CommandFlags.None); - /// - /// Returns a random element from the sorted set value stored at . - /// - /// The key of the sorted set. - /// The flags to use for this operation. - /// The randomly selected element, or when does not exist. - /// + /// Task SortedSetRandomMemberAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Returns an array of random elements from the sorted set value stored at . - /// - /// The key of the sorted set. - /// - /// - /// If the provided count argument is positive, returns an array of distinct elements. - /// The array's length is either or the sorted set's cardinality (ZCARD), whichever is lower. - /// - /// - /// If called with a negative count, the behavior changes and the command is allowed to return the same element multiple times. - /// In this case, the number of returned elements is the absolute value of the specified count. - /// - /// - /// The flags to use for this operation. - /// The randomly selected elements, or an empty array when does not exist. - /// + /// Task SortedSetRandomMembersAsync(RedisKey key, long count, CommandFlags flags = CommandFlags.None); - /// - /// Returns an array of random elements from the sorted set value stored at . - /// - /// The key of the sorted set. - /// - /// - /// If the provided count argument is positive, returns an array of distinct elements. - /// The array's length is either or the sorted set's cardinality (ZCARD), whichever is lower. - /// - /// - /// If called with a negative count, the behavior changes and the command is allowed to return the same element multiple times. - /// In this case, the number of returned elements is the absolute value of the specified count. - /// - /// - /// The flags to use for this operation. - /// The randomly selected elements with scores, or an empty array when does not exist. - /// + /// Task SortedSetRandomMembersWithScoresAsync(RedisKey key, long count, CommandFlags flags = CommandFlags.None); - /// - /// Returns the specified range of elements in the sorted set stored at key. - /// By default the elements are considered to be ordered from the lowest to the highest score. - /// Lexicographical order is used for elements with equal score. - /// Both start and stop are zero-based indexes, where 0 is the first element, 1 is the next element and so on. - /// They can also be negative numbers indicating offsets from the end of the sorted set, with -1 being the last element of the sorted set, -2 the penultimate element and so on. - /// - /// The key of the sorted set. - /// The start index to get. - /// The stop index to get. - /// The order to sort by (defaults to ascending). - /// The flags to use for this operation. - /// List of elements in the specified range. - /// - /// , - /// - /// + /// Task SortedSetRangeByRankAsync(RedisKey key, long start = 0, long stop = -1, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None); - /// - /// Takes the specified range of elements in the sorted set of the - /// and stores them in a new sorted set at the . - /// - /// The sorted set to take the range from. - /// Where the resulting set will be stored. - /// The starting point in the sorted set. If is , this should be a string. - /// The stopping point in the range of the sorted set. If is , this should be a string. - /// The ordering criteria to use for the range. Choices are , , and (defaults to ). - /// Whether to exclude and from the range check (defaults to both inclusive). - /// - /// The direction to consider the and in. - /// If , the must be smaller than the . - /// If , must be smaller than . - /// - /// The number of elements into the sorted set to skip. Note: this iterates after sorting so incurs O(n) cost for large values. - /// The maximum number of elements to pull into the new () set. - /// The flags to use for this operation. - /// The cardinality of (number of elements in) the newly created sorted set. - /// + /// Task SortedSetRangeAndStoreAsync( RedisKey sourceKey, RedisKey destinationKey, @@ -1858,46 +476,12 @@ Task SortedSetRangeAndStoreAsync( long? take = null, CommandFlags flags = CommandFlags.None); - /// - /// Returns the specified range of elements in the sorted set stored at key. - /// By default the elements are considered to be ordered from the lowest to the highest score. - /// Lexicographical order is used for elements with equal score. - /// Both start and stop are zero-based indexes, where 0 is the first element, 1 is the next element and so on. - /// They can also be negative numbers indicating offsets from the end of the sorted set, with -1 being the last element of the sorted set, -2 the penultimate element and so on. - /// - /// The key of the sorted set. - /// The start index to get. - /// The stop index to get. - /// The order to sort by (defaults to ascending). - /// The flags to use for this operation. - /// List of elements in the specified range. - /// - /// , - /// - /// + /// Task SortedSetRangeByRankWithScoresAsync(RedisKey key, long start = 0, long stop = -1, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None); - /// - /// Returns the specified range of elements in the sorted set stored at key. - /// By default the elements are considered to be ordered from the lowest to the highest score. - /// Lexicographical order is used for elements with equal score. - /// Start and stop are used to specify the min and max range for score values. - /// Similar to other range methods the values are inclusive. - /// - /// The key of the sorted set. - /// The minimum score to filter by. - /// The maximum score to filter by. - /// Which of and to exclude (defaults to both inclusive). - /// The order to sort by (defaults to ascending). - /// How many items to skip. - /// How many items to take. - /// The flags to use for this operation. - /// List of elements in the specified score range. - /// - /// , - /// - /// - Task SortedSetRangeByScoreAsync(RedisKey key, + /// + Task SortedSetRangeByScoreAsync( + RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity, Exclude exclude = Exclude.None, @@ -1906,27 +490,9 @@ Task SortedSetRangeByScoreAsync(RedisKey key, long take = -1, CommandFlags flags = CommandFlags.None); - /// - /// Returns the specified range of elements in the sorted set stored at key. - /// By default the elements are considered to be ordered from the lowest to the highest score. - /// Lexicographical order is used for elements with equal score. - /// Start and stop are used to specify the min and max range for score values. - /// Similar to other range methods the values are inclusive. - /// - /// The key of the sorted set. - /// The minimum score to filter by. - /// The maximum score to filter by. - /// Which of and to exclude (defaults to both inclusive). - /// The order to sort by (defaults to ascending). - /// How many items to skip. - /// How many items to take. - /// The flags to use for this operation. - /// List of elements in the specified score range. - /// - /// , - /// - /// - Task SortedSetRangeByScoreWithScoresAsync(RedisKey key, + /// + Task SortedSetRangeByScoreWithScoresAsync( + RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity, Exclude exclude = Exclude.None, @@ -1935,20 +501,9 @@ Task SortedSetRangeByScoreWithScoresAsync(RedisKey key, long take = -1, CommandFlags flags = CommandFlags.None); - /// - /// When all the elements in a sorted set are inserted with the same score, in order to force lexicographical ordering. - /// This command returns all the elements in the sorted set at key with a value between min and max. - /// - /// The key of the sorted set. - /// The min value to filter by. - /// The max value to filter by. - /// Which of and to exclude (defaults to both inclusive). - /// How many items to skip. - /// How many items to take. - /// The flags to use for this operation. - /// List of elements in the specified score range. - /// - Task SortedSetRangeByValueAsync(RedisKey key, + /// + Task SortedSetRangeByValueAsync( + RedisKey key, RedisValue min, RedisValue max, Exclude exclude, @@ -1956,24 +511,9 @@ Task SortedSetRangeByValueAsync(RedisKey key, long take = -1, CommandFlags flags = CommandFlags.None); // defaults removed to avoid ambiguity with overload with order - /// - /// When all the elements in a sorted set are inserted with the same score, in order to force lexicographical ordering. - /// This command returns all the elements in the sorted set at key with a value between min and max. - /// - /// The key of the sorted set. - /// The min value to filter by. - /// The max value to filter by. - /// Which of and to exclude (defaults to both inclusive). - /// Whether to order the data ascending or descending - /// How many items to skip. - /// How many items to take. - /// The flags to use for this operation. - /// List of elements in the specified score range. - /// - /// , - /// - /// - Task SortedSetRangeByValueAsync(RedisKey key, + /// + Task SortedSetRangeByValueAsync( + RedisKey key, RedisValue min = default, RedisValue max = default, Exclude exclude = Exclude.None, @@ -1982,924 +522,239 @@ Task SortedSetRangeByValueAsync(RedisKey key, long take = -1, CommandFlags flags = CommandFlags.None); - /// - /// Returns the rank of member in the sorted set stored at key, by default with the scores ordered from low to high. - /// The rank (or index) is 0-based, which means that the member with the lowest score has rank 0. - /// - /// The key of the sorted set. - /// The member to get the rank of. - /// The order to sort by (defaults to ascending). - /// The flags to use for this operation. - /// If member exists in the sorted set, the rank of member. If member does not exist in the sorted set or key does not exist, . - /// - /// , - /// - /// + /// Task SortedSetRankAsync(RedisKey key, RedisValue member, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None); - /// - /// Removes the specified member from the sorted set stored at key. Non existing members are ignored. - /// - /// The key of the sorted set. - /// The member to remove. - /// The flags to use for this operation. - /// if the member existed in the sorted set and was removed. otherwise. - /// + /// Task SortedSetRemoveAsync(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None); - /// - /// Removes the specified members from the sorted set stored at key. Non existing members are ignored. - /// - /// The key of the sorted set. - /// The members to remove. - /// The flags to use for this operation. - /// The number of members removed from the sorted set, not including non existing members. - /// + /// Task SortedSetRemoveAsync(RedisKey key, RedisValue[] members, CommandFlags flags = CommandFlags.None); - /// - /// Removes all elements in the sorted set stored at key with rank between start and stop. - /// Both start and stop are 0 -based indexes with 0 being the element with the lowest score. - /// These indexes can be negative numbers, where they indicate offsets starting at the element with the highest score. - /// For example: -1 is the element with the highest score, -2 the element with the second highest score and so forth. - /// - /// The key of the sorted set. - /// The minimum rank to remove. - /// The maximum rank to remove. - /// The flags to use for this operation. - /// The number of elements removed. - /// + /// Task SortedSetRemoveRangeByRankAsync(RedisKey key, long start, long stop, CommandFlags flags = CommandFlags.None); - /// - /// Removes all elements in the sorted set stored at key with a score between min and max (inclusive by default). - /// - /// The key of the sorted set. - /// The minimum score to remove. - /// The maximum score to remove. - /// Which of and to exclude (defaults to both inclusive). - /// The flags to use for this operation. - /// The number of elements removed. - /// + /// Task SortedSetRemoveRangeByScoreAsync(RedisKey key, double start, double stop, Exclude exclude = Exclude.None, CommandFlags flags = CommandFlags.None); - /// - /// When all the elements in a sorted set are inserted with the same score, in order to force lexicographical ordering. - /// This command removes all elements in the sorted set stored at key between the lexicographical range specified by min and max. - /// - /// The key of the sorted set. - /// The minimum value to remove. - /// The maximum value to remove. - /// Which of and to exclude (defaults to both inclusive). - /// The flags to use for this operation. - /// The number of elements removed. - /// + /// Task SortedSetRemoveRangeByValueAsync(RedisKey key, RedisValue min, RedisValue max, Exclude exclude = Exclude.None, CommandFlags flags = CommandFlags.None); - /// - /// The ZSCAN command is used to incrementally iterate over a sorted set. - /// - /// The key of the sorted set. - /// The pattern to match. - /// The page size to iterate by. - /// The cursor position to start at. - /// The page offset to start at. - /// The flags to use for this operation. - /// Yields all matching elements of the sorted set. - /// - IAsyncEnumerable SortedSetScanAsync(RedisKey key, + /// + IAsyncEnumerable SortedSetScanAsync( + RedisKey key, RedisValue pattern = default, int pageSize = RedisBase.CursorUtils.DefaultLibraryPageSize, long cursor = RedisBase.CursorUtils.Origin, int pageOffset = 0, CommandFlags flags = CommandFlags.None); - /// - /// Returns the score of member in the sorted set at key. - /// If member does not exist in the sorted set, or key does not exist, is returned. - /// - /// The key of the sorted set. - /// The member to get a score for. - /// The flags to use for this operation. - /// The score of the member. - /// + /// Task SortedSetScoreAsync(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None); - /// - /// Returns the scores of members in the sorted set at . - /// If a member does not exist in the sorted set, or key does not exist, is returned. - /// - /// The key of the sorted set. - /// The members to get a score for. - /// The flags to use for this operation. - /// - /// The scores of the members in the same order as the array. - /// If a member does not exist in the set, is returned. - /// - /// + /// Task SortedSetScoresAsync(RedisKey key, RedisValue[] members, CommandFlags flags = CommandFlags.None); - /// - /// Same as but return the number of the elements changed. - /// - /// The key of the sorted set. - /// The member to add/update to the sorted set. - /// The score for the member to add/update to the sorted set. - /// What conditions to add the element under (defaults to always). - /// The flags to use for this operation. - /// The number of elements changed. - /// + /// Task SortedSetUpdateAsync(RedisKey key, RedisValue member, double score, SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None); - /// - /// Same as but return the number of the elements changed. - /// - /// The key of the sorted set. - /// The members and values to add/update to the sorted set. - /// What conditions to add the element under (defaults to always). - /// The flags to use for this operation. - /// The number of elements changed. - /// + /// Task SortedSetUpdateAsync(RedisKey key, SortedSetEntry[] values, SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None); - /// - /// Removes and returns the first element from the sorted set stored at key, by default with the scores ordered from low to high. - /// - /// The key of the sorted set. - /// The order to sort by (defaults to ascending). - /// The flags to use for this operation. - /// The removed element, or when key does not exist. - /// - /// , - /// - /// + /// Task SortedSetPopAsync(RedisKey key, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None); - /// - /// Removes and returns the specified number of first elements from the sorted set stored at key, by default with the scores ordered from low to high. - /// - /// The key of the sorted set. - /// The number of elements to return. - /// The order to sort by (defaults to ascending). - /// The flags to use for this operation. - /// An array of elements, or an empty array when key does not exist. - /// - /// , - /// - /// + /// Task SortedSetPopAsync(RedisKey key, long count, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None); - /// - /// Removes and returns up to entries from the first non-empty sorted set in . - /// Returns if none of the sets exist or contain any elements. - /// - /// The keys to check. - /// The maximum number of records to pop out of the sorted set. - /// The order to sort by when popping items out of the set. - /// The flags to use for the operation. - /// A contiguous collection of sorted set entries with the key they were popped from, or if no non-empty sorted sets are found. - /// + /// Task SortedSetPopAsync(RedisKey[] keys, long count, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None); - /// - /// Allow the consumer to mark a pending message as correctly processed. Returns the number of messages acknowledged. - /// - /// The key of the stream. - /// The name of the consumer group that received the message. - /// The ID of the message to acknowledge. - /// The flags to use for this operation. - /// The number of messages acknowledged. - /// + /// Task StreamAcknowledgeAsync(RedisKey key, RedisValue groupName, RedisValue messageId, CommandFlags flags = CommandFlags.None); - /// - /// Allow the consumer to mark a pending message as correctly processed. Returns the number of messages acknowledged. - /// - /// The key of the stream. - /// The name of the consumer group that received the message. - /// The IDs of the messages to acknowledge. - /// The flags to use for this operation. - /// The number of messages acknowledged. - /// + /// Task StreamAcknowledgeAsync(RedisKey key, RedisValue groupName, RedisValue[] messageIds, CommandFlags flags = CommandFlags.None); - /// - /// Adds an entry using the specified values to the given stream key. - /// If key does not exist, a new key holding a stream is created. - /// The command returns the ID of the newly created stream entry. - /// - /// The key of the stream. - /// The field name for the stream entry. - /// The value to set in the stream entry. - /// The ID to assign to the stream entry, defaults to an auto-generated ID ("*"). - /// The maximum length of the stream. - /// If true, the "~" argument is used to allow the stream to exceed max length by a small number. This improves performance when removing messages. - /// The flags to use for this operation. - /// The ID of the newly created message. - /// + /// Task StreamAddAsync(RedisKey key, RedisValue streamField, RedisValue streamValue, RedisValue? messageId = null, int? maxLength = null, bool useApproximateMaxLength = false, CommandFlags flags = CommandFlags.None); - /// - /// Adds an entry using the specified values to the given stream key. - /// If key does not exist, a new key holding a stream is created. - /// The command returns the ID of the newly created stream entry. - /// - /// The key of the stream. - /// The fields and their associated values to set in the stream entry. - /// The ID to assign to the stream entry, defaults to an auto-generated ID ("*"). - /// The maximum length of the stream. - /// If true, the "~" argument is used to allow the stream to exceed max length by a small number. This improves performance when removing messages. - /// The flags to use for this operation. - /// The ID of the newly created message. - /// + /// Task StreamAddAsync(RedisKey key, NameValueEntry[] streamPairs, RedisValue? messageId = null, int? maxLength = null, bool useApproximateMaxLength = false, CommandFlags flags = CommandFlags.None); - /// - /// Change ownership of messages consumed, but not yet acknowledged, by a different consumer. - /// Messages that have been idle for more than will be claimed. - /// - /// The key of the stream. - /// The consumer group. - /// The consumer claiming the messages(s). - /// The minimum idle time threshold for pending messages to be claimed. - /// The starting ID to scan for pending messages that have an idle time greater than . - /// The upper limit of the number of entries that the command attempts to claim. If , Redis will default the value to 100. - /// The flags to use for this operation. - /// An instance of . - /// + /// Task StreamAutoClaimAsync(RedisKey key, RedisValue consumerGroup, RedisValue claimingConsumer, long minIdleTimeInMs, RedisValue startAtId, int? count = null, CommandFlags flags = CommandFlags.None); - /// - /// Change ownership of messages consumed, but not yet acknowledged, by a different consumer. - /// Messages that have been idle for more than will be claimed. - /// The result will contain the claimed message IDs instead of a instance. - /// - /// The key of the stream. - /// The consumer group. - /// The consumer claiming the messages(s). - /// The minimum idle time threshold for pending messages to be claimed. - /// The starting ID to scan for pending messages that have an idle time greater than . - /// The upper limit of the number of entries that the command attempts to claim. If , Redis will default the value to 100. - /// The flags to use for this operation. - /// An instance of . - /// + /// Task StreamAutoClaimIdsOnlyAsync(RedisKey key, RedisValue consumerGroup, RedisValue claimingConsumer, long minIdleTimeInMs, RedisValue startAtId, int? count = null, CommandFlags flags = CommandFlags.None); - /// - /// Change ownership of messages consumed, but not yet acknowledged, by a different consumer. - /// This method returns the complete message for the claimed message(s). - /// - /// The key of the stream. - /// The consumer group. - /// The consumer claiming the given message(s). - /// The minimum message idle time to allow the reassignment of the message(s). - /// The IDs of the messages to claim for the given consumer. - /// The flags to use for this operation. - /// The messages successfully claimed by the given consumer. - /// + /// Task StreamClaimAsync(RedisKey key, RedisValue consumerGroup, RedisValue claimingConsumer, long minIdleTimeInMs, RedisValue[] messageIds, CommandFlags flags = CommandFlags.None); - /// - /// Change ownership of messages consumed, but not yet acknowledged, by a different consumer. - /// This method returns the IDs for the claimed message(s). - /// - /// The key of the stream. - /// The consumer group. - /// The consumer claiming the given message(s). - /// The minimum message idle time to allow the reassignment of the message(s). - /// The IDs of the messages to claim for the given consumer. - /// The flags to use for this operation. - /// The message IDs for the messages successfully claimed by the given consumer. - /// + /// Task StreamClaimIdsOnlyAsync(RedisKey key, RedisValue consumerGroup, RedisValue claimingConsumer, long minIdleTimeInMs, RedisValue[] messageIds, CommandFlags flags = CommandFlags.None); - /// - /// Set the position from which to read a stream for a consumer group. - /// - /// The key of the stream. - /// The name of the consumer group. - /// The position from which to read for the consumer group. - /// The flags to use for this operation. - /// if successful, otherwise. - /// + /// Task StreamConsumerGroupSetPositionAsync(RedisKey key, RedisValue groupName, RedisValue position, CommandFlags flags = CommandFlags.None); - /// - /// Retrieve information about the consumers for the given consumer group. - /// This is the equivalent of calling "XINFO GROUPS key group". - /// - /// The key of the stream. - /// The consumer group name. - /// The flags to use for this operation. - /// An instance of for each of the consumer group's consumers. - /// + /// Task StreamConsumerInfoAsync(RedisKey key, RedisValue groupName, CommandFlags flags = CommandFlags.None); - /// - /// Create a consumer group for the given stream. - /// - /// The key of the stream. - /// The name of the group to create. - /// The position to begin reading the stream. Defaults to . - /// The flags to use for this operation. - /// if the group was created, otherwise. - /// + /// Task StreamCreateConsumerGroupAsync(RedisKey key, RedisValue groupName, RedisValue? position, CommandFlags flags); - /// - /// Create a consumer group for the given stream. - /// - /// The key of the stream. - /// The name of the group to create. - /// The position to begin reading the stream. Defaults to . - /// Create the stream if it does not already exist. - /// The flags to use for this operation. - /// if the group was created, otherwise. - /// + /// Task StreamCreateConsumerGroupAsync(RedisKey key, RedisValue groupName, RedisValue? position = null, bool createStream = true, CommandFlags flags = CommandFlags.None); - /// - /// Delete messages in the stream. This method does not delete the stream. - /// - /// The key of the stream. - /// The IDs of the messages to delete. - /// The flags to use for this operation. - /// Returns the number of messages successfully deleted from the stream. - /// + /// Task StreamDeleteAsync(RedisKey key, RedisValue[] messageIds, CommandFlags flags = CommandFlags.None); - /// - /// Delete a consumer from a consumer group. - /// - /// The key of the stream. - /// The name of the consumer group. - /// The name of the consumer. - /// The flags to use for this operation. - /// The number of messages that were pending for the deleted consumer. - /// + /// Task StreamDeleteConsumerAsync(RedisKey key, RedisValue groupName, RedisValue consumerName, CommandFlags flags = CommandFlags.None); - /// - /// Delete a consumer group. - /// - /// The key of the stream. - /// The name of the consumer group. - /// The flags to use for this operation. - /// if deleted, otherwise. - /// + /// Task StreamDeleteConsumerGroupAsync(RedisKey key, RedisValue groupName, CommandFlags flags = CommandFlags.None); - /// - /// Retrieve information about the groups created for the given stream. This is the equivalent of calling "XINFO GROUPS key". - /// - /// The key of the stream. - /// The flags to use for this operation. - /// An instance of for each of the stream's groups. - /// + /// Task StreamGroupInfoAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Retrieve information about the given stream. This is the equivalent of calling "XINFO STREAM key". - /// - /// The key of the stream. - /// The flags to use for this operation. - /// A instance with information about the stream. - /// + /// Task StreamInfoAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Return the number of entries in a stream. - /// - /// The key of the stream. - /// The flags to use for this operation. - /// The number of entries inside the given stream. - /// + /// Task StreamLengthAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// View information about pending messages for a stream. - /// A pending message is a message read using StreamReadGroup (XREADGROUP) but not yet acknowledged. - /// - /// The key of the stream. - /// The name of the consumer group - /// The flags to use for this operation. - /// - /// An instance of . - /// contains the number of pending messages. - /// The highest and lowest ID of the pending messages, and the consumers with their pending message count. - /// - /// The equivalent of calling XPENDING key group. - /// + /// Task StreamPendingAsync(RedisKey key, RedisValue groupName, CommandFlags flags = CommandFlags.None); - /// - /// View information about each pending message. - /// - /// The key of the stream. - /// The name of the consumer group. - /// The maximum number of pending messages to return. - /// The consumer name for the pending messages. Pass RedisValue.Null to include pending messages for all consumers. - /// The minimum ID from which to read the stream of pending messages. The method will default to reading from the beginning of the stream. - /// The maximum ID to read to within the stream of pending messages. The method will default to reading to the end of the stream. - /// The flags to use for this operation. - /// An instance of for each pending message. - /// Equivalent of calling XPENDING key group start-id end-id count consumer-name. - /// + /// Task StreamPendingMessagesAsync(RedisKey key, RedisValue groupName, int count, RedisValue consumerName, RedisValue? minId = null, RedisValue? maxId = null, CommandFlags flags = CommandFlags.None); - /// - /// Read a stream using the given range of IDs. - /// - /// The key of the stream. - /// The minimum ID from which to read the stream. The method will default to reading from the beginning of the stream. - /// The maximum ID to read to within the stream. The method will default to reading to the end of the stream. - /// The maximum number of messages to return. - /// The order of the messages. will execute XRANGE and will execute XREVRANGE. - /// The flags to use for this operation. - /// Returns an instance of for each message returned. - /// + /// Task StreamRangeAsync(RedisKey key, RedisValue? minId = null, RedisValue? maxId = null, int? count = null, Order messageOrder = Order.Ascending, CommandFlags flags = CommandFlags.None); - /// - /// Read from a single stream. - /// - /// The key of the stream. - /// The position from which to read the stream. - /// The maximum number of messages to return. - /// The flags to use for this operation. - /// Returns an instance of for each message returned. - /// - /// Equivalent of calling XREAD COUNT num STREAMS key id. - /// - /// + /// Task StreamReadAsync(RedisKey key, RedisValue position, int? count = null, CommandFlags flags = CommandFlags.None); - /// - /// Read from multiple streams. - /// - /// Array of streams and the positions from which to begin reading for each stream. - /// The maximum number of messages to return from each stream. - /// The flags to use for this operation. - /// A value of for each stream. - /// - /// Equivalent of calling XREAD COUNT num STREAMS key1 key2 id1 id2. - /// - /// + /// Task StreamReadAsync(StreamPosition[] streamPositions, int? countPerStream = null, CommandFlags flags = CommandFlags.None); - /// - /// Read messages from a stream into an associated consumer group. - /// - /// The key of the stream. - /// The name of the consumer group. - /// The consumer name. - /// The position from which to read the stream. Defaults to when . - /// The maximum number of messages to return. - /// The flags to use for this operation. - /// Returns a value of for each message returned. - /// + /// Task StreamReadGroupAsync(RedisKey key, RedisValue groupName, RedisValue consumerName, RedisValue? position, int? count, CommandFlags flags); - /// - /// Read messages from a stream into an associated consumer group. - /// - /// The key of the stream. - /// The name of the consumer group. - /// The consumer name. - /// The position from which to read the stream. Defaults to when . - /// The maximum number of messages to return. - /// When true, the message will not be added to the pending message list. - /// The flags to use for this operation. - /// Returns a value of for each message returned. - /// + /// Task StreamReadGroupAsync(RedisKey key, RedisValue groupName, RedisValue consumerName, RedisValue? position = null, int? count = null, bool noAck = false, CommandFlags flags = CommandFlags.None); - /// - /// Read from multiple streams into the given consumer group. - /// The consumer group with the given will need to have been created for each stream prior to calling this method. - /// - /// Array of streams and the positions from which to begin reading for each stream. - /// The name of the consumer group. - /// - /// The maximum number of messages to return from each stream. - /// The flags to use for this operation. - /// A value of for each stream. - /// - /// Equivalent of calling XREADGROUP GROUP groupName consumerName COUNT countPerStream STREAMS stream1 stream2 id1 id2. - /// - /// + /// Task StreamReadGroupAsync(StreamPosition[] streamPositions, RedisValue groupName, RedisValue consumerName, int? countPerStream, CommandFlags flags); - /// - /// Read from multiple streams into the given consumer group. - /// The consumer group with the given will need to have been created for each stream prior to calling this method. - /// - /// Array of streams and the positions from which to begin reading for each stream. - /// The name of the consumer group. - /// - /// The maximum number of messages to return from each stream. - /// When true, the message will not be added to the pending message list. - /// The flags to use for this operation. - /// A value of for each stream. - /// - /// Equivalent of calling XREADGROUP GROUP groupName consumerName COUNT countPerStream STREAMS stream1 stream2 id1 id2. - /// - /// + /// Task StreamReadGroupAsync(StreamPosition[] streamPositions, RedisValue groupName, RedisValue consumerName, int? countPerStream = null, bool noAck = false, CommandFlags flags = CommandFlags.None); - /// - /// Trim the stream to a specified maximum length. - /// - /// The key of the stream. - /// The maximum length of the stream. - /// If true, the "~" argument is used to allow the stream to exceed max length by a small number. This improves performance when removing messages. - /// The flags to use for this operation. - /// The number of messages removed from the stream. - /// + /// Task StreamTrimAsync(RedisKey key, int maxLength, bool useApproximateMaxLength = false, CommandFlags flags = CommandFlags.None); - /// - /// If key already exists and is a string, this command appends the value at the end of the string. - /// If key does not exist it is created and set as an empty string, so APPEND will be similar to SET in this special case. - /// - /// The key of the string. - /// The value to append to the string. - /// The flags to use for this operation. - /// The length of the string after the append operation. - /// + /// Task StringAppendAsync(RedisKey key, RedisValue value, CommandFlags flags = CommandFlags.None); - /// + /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] Task StringBitCountAsync(RedisKey key, long start, long end, CommandFlags flags); - /// - /// Count the number of set bits (population counting) in a string. - /// By default all the bytes contained in the string are examined. - /// It is possible to specify the counting operation only in an interval passing the additional arguments start and end. - /// Like for the GETRANGE command start and end can contain negative values in order to index bytes starting from the end of the string, where -1 is the last byte, -2 is the penultimate, and so forth. - /// - /// The key of the string. - /// The start byte to count at. - /// The end byte to count at. - /// In Redis 7+, we can choose if and specify a bit index or byte index (defaults to ). - /// The flags to use for this operation. - /// The number of bits set to 1. - /// + /// Task StringBitCountAsync(RedisKey key, long start = 0, long end = -1, StringIndexType indexType = StringIndexType.Byte, CommandFlags flags = CommandFlags.None); - /// - /// Perform a bitwise operation between multiple keys (containing string values) and store the result in the destination key. - /// The BITOP command supports four bitwise operations; note that NOT is a unary operator: the second key should be omitted in this case - /// and only the first key will be considered. - /// The result of the operation is always stored at . - /// - /// The operation to perform. - /// The destination key to store the result in. - /// The first key to get the bit value from. - /// The second key to get the bit value from. - /// The flags to use for this operation. - /// The size of the string stored in the destination key, that is equal to the size of the longest input string. - /// + /// Task StringBitOperationAsync(Bitwise operation, RedisKey destination, RedisKey first, RedisKey second = default, CommandFlags flags = CommandFlags.None); - /// - /// Perform a bitwise operation between multiple keys (containing string values) and store the result in the destination key. - /// The BITOP command supports four bitwise operations; note that NOT is a unary operator. - /// The result of the operation is always stored at . - /// - /// The operation to perform. - /// The destination key to store the result in. - /// The keys to get the bit values from. - /// The flags to use for this operation. - /// The size of the string stored in the destination key, that is equal to the size of the longest input string. - /// + /// Task StringBitOperationAsync(Bitwise operation, RedisKey destination, RedisKey[] keys, CommandFlags flags = CommandFlags.None); - /// + /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] Task StringBitPositionAsync(RedisKey key, bool bit, long start, long end, CommandFlags flags); - /// - /// Return the position of the first bit set to 1 or 0 in a string. - /// The position is returned thinking at the string as an array of bits from left to right where the first byte most significant bit is at position 0, the second byte most significant bit is at position 8 and so forth. - /// A and may be specified - these are in bytes, not bits. - /// and can contain negative values in order to index bytes starting from the end of the string, where -1 is the last byte, -2 is the penultimate, and so forth. - /// - /// The key of the string. - /// True to check for the first 1 bit, false to check for the first 0 bit. - /// The position to start looking (defaults to 0). - /// The position to stop looking (defaults to -1, unlimited). - /// In Redis 7+, we can choose if and specify a bit index or byte index (defaults to ). - /// The flags to use for this operation. - /// - /// The command returns the position of the first bit set to 1 or 0 according to the request. - /// If we look for set bits(the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is returned. - /// - /// + /// Task StringBitPositionAsync(RedisKey key, bool bit, long start = 0, long end = -1, StringIndexType indexType = StringIndexType.Byte, CommandFlags flags = CommandFlags.None); - /// - /// Decrements the number stored at key by decrement. - /// If the key does not exist, it is set to 0 before performing the operation. - /// An error is returned if the key contains a value of the wrong type or contains a string that is not representable as integer. - /// This operation is limited to 64 bit signed integers. - /// - /// The key of the string. - /// The amount to decrement by (defaults to 1). - /// The flags to use for this operation. - /// The value of key after the decrement. - /// - /// , - /// - /// + /// Task StringDecrementAsync(RedisKey key, long value = 1, CommandFlags flags = CommandFlags.None); - /// - /// Decrements the string representing a floating point number stored at key by the specified decrement. - /// If the key does not exist, it is set to 0 before performing the operation. - /// The precision of the output is fixed at 17 digits after the decimal point regardless of the actual internal precision of the computation. - /// - /// The key of the string. - /// The amount to decrement by (defaults to 1). - /// The flags to use for this operation. - /// The value of key after the decrement. - /// + /// Task StringDecrementAsync(RedisKey key, double value, CommandFlags flags = CommandFlags.None); - /// - /// Get the value of key. If the key does not exist the special value is returned. - /// An error is returned if the value stored at key is not a string, because GET only handles string values. - /// - /// The key of the string. - /// The flags to use for this operation. - /// The value of key, or when key does not exist. - /// + /// Task StringGetAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Returns the values of all specified keys. - /// For every key that does not hold a string value or does not exist, the special value is returned. - /// - /// The keys of the strings. - /// The flags to use for this operation. - /// The values of the strings with for keys do not exist. - /// + /// Task StringGetAsync(RedisKey[] keys, CommandFlags flags = CommandFlags.None); - /// - /// Get the value of key. If the key does not exist the special value is returned. - /// An error is returned if the value stored at key is not a string, because GET only handles string values. - /// - /// The key of the string. - /// The flags to use for this operation. - /// The value of key, or when key does not exist. - /// + /// Task?> StringGetLeaseAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Returns the bit value at offset in the string value stored at key. - /// When offset is beyond the string length, the string is assumed to be a contiguous space with 0 bits. - /// - /// The key of the string. - /// The offset in the string to get a bit at. - /// The flags to use for this operation. - /// The bit value stored at offset. - /// + /// Task StringGetBitAsync(RedisKey key, long offset, CommandFlags flags = CommandFlags.None); - /// - /// Returns the substring of the string value stored at key, determined by the offsets start and end (both are inclusive). - /// Negative offsets can be used in order to provide an offset starting from the end of the string. - /// So -1 means the last character, -2 the penultimate and so forth. - /// - /// The key of the string. - /// The start index of the substring to get. - /// The end index of the substring to get. - /// The flags to use for this operation. - /// The substring of the string value stored at key. - /// + /// Task StringGetRangeAsync(RedisKey key, long start, long end, CommandFlags flags = CommandFlags.None); - /// - /// Atomically sets key to value and returns the old value stored at key. - /// - /// The key of the string. - /// The value to replace the existing value with. - /// The flags to use for this operation. - /// The old value stored at key, or when key did not exist. - /// + /// Task StringGetSetAsync(RedisKey key, RedisValue value, CommandFlags flags = CommandFlags.None); - /// - /// Gets the value of and update its (relative) expiry. - /// If the key does not exist, the result will be . - /// - /// The key of the string. - /// The expiry to set. will remove expiry. - /// The flags to use for this operation. - /// The value of key, or when key does not exist. - /// + /// Task StringGetSetExpiryAsync(RedisKey key, TimeSpan? expiry, CommandFlags flags = CommandFlags.None); - /// - /// Gets the value of and update its (absolute) expiry. - /// If the key does not exist, the result will be . - /// - /// The key of the string. - /// The exact date and time to expire at. will remove expiry. - /// The flags to use for this operation. - /// The value of key, or when key does not exist. - /// + /// Task StringGetSetExpiryAsync(RedisKey key, DateTime expiry, CommandFlags flags = CommandFlags.None); - /// - /// Get the value of key and delete the key. - /// If the key does not exist the special value is returned. - /// An error is returned if the value stored at key is not a string, because GET only handles string values. - /// - /// The key of the string. - /// The flags to use for this operation. - /// The value of key, or when key does not exist. - /// + /// Task StringGetDeleteAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Get the value of key. - /// If the key does not exist the special value is returned. - /// An error is returned if the value stored at key is not a string, because GET only handles string values. - /// - /// The key of the string. - /// The flags to use for this operation. - /// The value of key and its expiry, or when key does not exist. - /// + /// Task StringGetWithExpiryAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Increments the number stored at key by increment. - /// If the key does not exist, it is set to 0 before performing the operation. - /// An error is returned if the key contains a value of the wrong type or contains a string that is not representable as integer. - /// This operation is limited to 64 bit signed integers. - /// - /// The key of the string. - /// The amount to increment by (defaults to 1). - /// The flags to use for this operation. - /// The value of key after the increment. - /// - /// , - /// - /// + /// Task StringIncrementAsync(RedisKey key, long value = 1, CommandFlags flags = CommandFlags.None); - /// - /// Increments the string representing a floating point number stored at key by the specified increment. - /// If the key does not exist, it is set to 0 before performing the operation. - /// The precision of the output is fixed at 17 digits after the decimal point regardless of the actual internal precision of the computation. - /// - /// The key of the string. - /// The amount to increment by (defaults to 1). - /// The flags to use for this operation. - /// The value of key after the increment. - /// + /// Task StringIncrementAsync(RedisKey key, double value, CommandFlags flags = CommandFlags.None); - /// - /// Returns the length of the string value stored at key. - /// - /// The key of the string. - /// The flags to use for this operation. - /// The length of the string at key, or 0 when key does not exist. - /// + /// Task StringLengthAsync(RedisKey key, CommandFlags flags = CommandFlags.None); - /// - /// Implements the longest common subsequence algorithm between the values at and , - /// returning a string containing the common sequence. - /// Note that this is different than the longest common string algorithm, - /// since matching characters in the string does not need to be contiguous. - /// - /// The key of the first string. - /// The key of the second string. - /// The flags to use for this operation. - /// A string (sequence of characters) of the LCS match. - /// + /// Task StringLongestCommonSubsequenceAsync(RedisKey first, RedisKey second, CommandFlags flags = CommandFlags.None); - /// - /// Implements the longest common subsequence algorithm between the values at and , - /// returning the legnth of the common sequence. - /// Note that this is different than the longest common string algorithm, - /// since matching characters in the string does not need to be contiguous. - /// - /// The key of the first string. - /// The key of the second string. - /// The flags to use for this operation. - /// The length of the LCS match. - /// + /// t Task StringLongestCommonSubsequenceLengthAsync(RedisKey first, RedisKey second, CommandFlags flags = CommandFlags.None); - /// - /// Implements the longest common subsequence algorithm between the values at and , - /// returning a list of all common sequences. - /// Note that this is different than the longest common string algorithm, - /// since matching characters in the string does not need to be contiguous. - /// - /// The key of the first string. - /// The key of the second string. - /// Can be used to restrict the list of matches to the ones of a given minimum length. - /// The flags to use for this operation. - /// The result of LCS algorithm, based on the given parameters. - /// + /// Task StringLongestCommonSubsequenceWithMatchesAsync(RedisKey first, RedisKey second, long minLength = 0, CommandFlags flags = CommandFlags.None); - /// + /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] Task StringSetAsync(RedisKey key, RedisValue value, TimeSpan? expiry, When when); - /// + /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] Task StringSetAsync(RedisKey key, RedisValue value, TimeSpan? expiry, When when, CommandFlags flags); - /// - /// Set key to hold the string value. If key already holds a value, it is overwritten, regardless of its type. - /// - /// The key of the string. - /// The value to set. - /// The expiry to set. - /// Whether to maintain the existing key's TTL (KEEPTTL flag). - /// Which condition to set the value under (defaults to always). - /// The flags to use for this operation. - /// if the string was set, otherwise. - /// + /// Task StringSetAsync(RedisKey key, RedisValue value, TimeSpan? expiry = null, bool keepTtl = false, When when = When.Always, CommandFlags flags = CommandFlags.None); - /// - /// Sets the given keys to their respective values. - /// If is specified, this will not perform any operation at all even if just a single key already exists. - /// - /// The keys and values to set. - /// Which condition to set the value under (defaults to always). - /// The flags to use for this operation. - /// if the keys were set, otherwise. - /// - /// , - /// - /// + /// Task StringSetAsync(KeyValuePair[] values, When when = When.Always, CommandFlags flags = CommandFlags.None); - /// - /// Atomically sets key to value and returns the previous value (if any) stored at . - /// - /// The key of the string. - /// The value to set. - /// The expiry to set. - /// Which condition to set the value under (defaults to ). - /// The flags to use for this operation. - /// The previous value stored at , or when key did not exist. - /// - /// This method uses the SET command with the GET option introduced in Redis 6.2.0 instead of the deprecated GETSET command. - /// - /// + /// Task StringSetAndGetAsync(RedisKey key, RedisValue value, TimeSpan? expiry, When when, CommandFlags flags); - /// - /// Atomically sets key to value and returns the previous value (if any) stored at . - /// - /// The key of the string. - /// The value to set. - /// The expiry to set. - /// Whether to maintain the existing key's TTL (KEEPTTL flag). - /// Which condition to set the value under (defaults to ). - /// The flags to use for this operation. - /// The previous value stored at , or when key did not exist. - /// This method uses the SET command with the GET option introduced in Redis 6.2.0 instead of the deprecated GETSET command. - /// + /// Task StringSetAndGetAsync(RedisKey key, RedisValue value, TimeSpan? expiry = null, bool keepTtl = false, When when = When.Always, CommandFlags flags = CommandFlags.None); - /// - /// Sets or clears the bit at offset in the string value stored at key. - /// The bit is either set or cleared depending on value, which can be either 0 or 1. - /// When key does not exist, a new string value is created.The string is grown to make sure it can hold a bit at offset. - /// - /// The key of the string. - /// The offset in the string to set . - /// The bit value to set, true for 1, false for 0. - /// The flags to use for this operation. - /// The original bit value stored at offset. - /// + /// Task StringSetBitAsync(RedisKey key, long offset, bool bit, CommandFlags flags = CommandFlags.None); - /// - /// Overwrites part of the string stored at key, starting at the specified offset, for the entire length of value. - /// If the offset is larger than the current length of the string at key, the string is padded with zero-bytes to make offset fit. - /// Non-existing keys are considered as empty strings, so this command will make sure it holds a string large enough to be able to set value at offset. - /// - /// The key of the string. - /// The offset in the string to overwrite. - /// The value to overwrite with. - /// The flags to use for this operation. - /// The length of the string after it was modified by the command. - /// + /// Task StringSetRangeAsync(RedisKey key, long offset, RedisValue value, CommandFlags flags = CommandFlags.None); } } diff --git a/src/StackExchange.Redis/Interfaces/IServer.cs b/src/StackExchange.Redis/Interfaces/IServer.cs index 94baf5cd6..fad2d4232 100644 --- a/src/StackExchange.Redis/Interfaces/IServer.cs +++ b/src/StackExchange.Redis/Interfaces/IServer.cs @@ -34,7 +34,7 @@ public partial interface IServer : IRedis bool IsConnected { get; } /// - /// The protocol being used to communicate with this server (if not connected/known, then the anticipated protocol from the configuration is returned, assuming success) + /// The protocol being used to communicate with this server (if not connected/known, then the anticipated protocol from the configuration is returned, assuming success). /// RedisProtocol Protocol { get; } @@ -110,15 +110,14 @@ public partial interface IServer : IRedis /// /// The CLIENT KILL command closes multiple connections that match the specified filters. /// - /// - /// - /// + /// The filter to use in choosing which clients to kill. + /// The command flags to use. + /// the number of clients killed. long ClientKill(ClientKillFilter filter, CommandFlags flags = CommandFlags.None); /// Task ClientKillAsync(ClientKillFilter filter, CommandFlags flags = CommandFlags.None); - /// /// The CLIENT LIST command returns information and statistics about the client connections server in a mostly human readable format. /// @@ -350,8 +349,9 @@ public partial interface IServer : IRedis /// /// Warning: consider KEYS as a command that should only be used in production environments with extreme care. /// + /// See /// , - /// + /// . /// /// IEnumerable Keys(int database = -1, RedisValue pattern = default, int pageSize = RedisBase.CursorUtils.DefaultLibraryPageSize, long cursor = RedisBase.CursorUtils.Origin, int pageOffset = 0, CommandFlags flags = CommandFlags.None); @@ -400,10 +400,11 @@ public partial interface IServer : IRedis /// The method of the save (e.g. background or foreground). /// The command flags to use. /// + /// See /// , /// , /// , - /// + /// . /// void Save(SaveType type, CommandFlags flags = CommandFlags.None); @@ -589,8 +590,9 @@ public partial interface IServer : IRedis /// /// The full text result of latency doctor. /// + /// See /// , - /// + /// . /// string LatencyDoctor(CommandFlags flags = CommandFlags.None); @@ -602,8 +604,9 @@ public partial interface IServer : IRedis /// /// The number of events that were reset. /// + /// See /// , - /// + /// . /// long LatencyReset(string[]? eventNames = null, CommandFlags flags = CommandFlags.None); @@ -615,8 +618,9 @@ public partial interface IServer : IRedis /// /// An array of latency history entries. /// + /// See /// , - /// + /// . /// LatencyHistoryEntry[] LatencyHistory(string eventName, CommandFlags flags = CommandFlags.None); @@ -628,8 +632,9 @@ public partial interface IServer : IRedis /// /// An array of the latest latency history entries. /// + /// See /// , - /// + /// . /// LatencyLatestEntry[] LatencyLatest(CommandFlags flags = CommandFlags.None); @@ -784,7 +789,7 @@ public partial interface IServer : IRedis internal static class IServerExtensions { /// - /// For testing only: Break the connection without mercy or thought + /// For testing only: Break the connection without mercy or thought. /// /// The server to simulate failure on. /// The type of failure(s) to simulate. diff --git a/src/StackExchange.Redis/Interfaces/ISubscriber.cs b/src/StackExchange.Redis/Interfaces/ISubscriber.cs index b81ed3af4..e0c509f49 100644 --- a/src/StackExchange.Redis/Interfaces/ISubscriber.cs +++ b/src/StackExchange.Redis/Interfaces/ISubscriber.cs @@ -52,8 +52,9 @@ public interface ISubscriber : IRedis /// The handler to invoke when a message is received on . /// The command flags to use. /// + /// See /// , - /// + /// . /// void Subscribe(RedisChannel channel, Action handler, CommandFlags flags = CommandFlags.None); @@ -65,10 +66,11 @@ public interface ISubscriber : IRedis /// /// The redis channel to subscribe to. /// The command flags to use. - /// A channel that represents this source + /// A channel that represents this source. /// + /// See /// , - /// + /// . /// ChannelMessageQueue Subscribe(RedisChannel channel, CommandFlags flags = CommandFlags.None); @@ -91,8 +93,9 @@ public interface ISubscriber : IRedis /// The handler to no longer invoke when a message is received on . /// The command flags to use. /// + /// See /// , - /// + /// . /// void Unsubscribe(RedisChannel channel, Action? handler = null, CommandFlags flags = CommandFlags.None); @@ -104,8 +107,9 @@ public interface ISubscriber : IRedis /// /// The command flags to use. /// + /// See /// , - /// + /// . /// void UnsubscribeAll(CommandFlags flags = CommandFlags.None); diff --git a/src/StackExchange.Redis/InternalErrorEventArgs.cs b/src/StackExchange.Redis/InternalErrorEventArgs.cs index 8693d66f7..f664f4d62 100644 --- a/src/StackExchange.Redis/InternalErrorEventArgs.cs +++ b/src/StackExchange.Redis/InternalErrorEventArgs.cs @@ -25,12 +25,12 @@ internal InternalErrorEventArgs(EventHandler? handler, o /// This constructor is only for testing purposes. /// /// The source of the event. - /// + /// The endpoint (if any) involved in the event. /// Redis connection type. /// The exception that occurred. /// Origin. public InternalErrorEventArgs(object sender, EndPoint endpoint, ConnectionType connectionType, Exception exception, string origin) - : this (null, sender, endpoint, connectionType, exception, origin) + : this(null, sender, endpoint, connectionType, exception, origin) { } diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs index e34cad895..f6821af1d 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs @@ -117,7 +117,6 @@ public Task HashRandomFieldsAsync(RedisKey key, long count, Comman public Task HashRandomFieldsWithValuesAsync(RedisKey key, long count, CommandFlags flags = CommandFlags.None) => Inner.HashRandomFieldsWithValuesAsync(ToInner(key), count, flags); - public IAsyncEnumerable HashScanAsync(RedisKey key, RedisValue pattern, int pageSize, long cursor, int pageOffset, CommandFlags flags) => Inner.HashScanAsync(ToInner(key), pattern, pageSize, cursor, pageOffset, flags); diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs index d1c47aeab..e2b484935 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs @@ -33,7 +33,7 @@ public bool GeoAdd(RedisKey key, GeoEntry value, CommandFlags flags = CommandFla public bool GeoRemove(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None) => Inner.GeoRemove(ToInner(key), member, flags); - public double? GeoDistance(RedisKey key, RedisValue member1, RedisValue member2, GeoUnit unit = GeoUnit.Meters,CommandFlags flags = CommandFlags.None) => + public double? GeoDistance(RedisKey key, RedisValue member1, RedisValue member2, GeoUnit unit = GeoUnit.Meters, CommandFlags flags = CommandFlags.None) => Inner.GeoDistance(ToInner(key), member1, member2, unit, flags); public string?[] GeoHash(RedisKey key, RedisValue[] members, CommandFlags flags = CommandFlags.None) => @@ -48,7 +48,7 @@ public bool GeoRemove(RedisKey key, RedisValue member, CommandFlags flags = Comm public GeoPosition? GeoPosition(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None) => Inner.GeoPosition(ToInner(key), member, flags); - public GeoRadiusResult[] GeoRadius(RedisKey key, RedisValue member, double radius, GeoUnit unit = GeoUnit.Meters, int count = -1, Order? order = null,GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None) => + public GeoRadiusResult[] GeoRadius(RedisKey key, RedisValue member, double radius, GeoUnit unit = GeoUnit.Meters, int count = -1, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None) => Inner.GeoRadius(ToInner(key), member, radius, unit, count, order, options, flags); public GeoRadiusResult[] GeoRadius(RedisKey key, double longitude, double latitude, double radius, GeoUnit unit = GeoUnit.Meters, int count = -1, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None) => @@ -407,7 +407,7 @@ public long SortedSetAdd(RedisKey key, SortedSetEntry[] values, CommandFlags fla public long SortedSetAdd(RedisKey key, SortedSetEntry[] values, When when = When.Always, CommandFlags flags = CommandFlags.None) => Inner.SortedSetAdd(ToInner(key), values, when, flags); - public long SortedSetAdd(RedisKey key, SortedSetEntry[] values,SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None) => + public long SortedSetAdd(RedisKey key, SortedSetEntry[] values, SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None) => Inner.SortedSetAdd(ToInner(key), values, when, flags); public bool SortedSetAdd(RedisKey key, RedisValue member, double score, CommandFlags flags) => @@ -510,7 +510,7 @@ public long SortedSetRemoveRangeByValue(RedisKey key, RedisValue min, RedisValue public double?[] SortedSetScores(RedisKey key, RedisValue[] members, CommandFlags flags = CommandFlags.None) => Inner.SortedSetScores(ToInner(key), members, flags); - public long SortedSetUpdate(RedisKey key, SortedSetEntry[] values,SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None) => + public long SortedSetUpdate(RedisKey key, SortedSetEntry[] values, SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None) => Inner.SortedSetUpdate(ToInner(key), values, when, flags); public bool SortedSetUpdate(RedisKey key, RedisValue member, double score, SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None) => @@ -707,7 +707,7 @@ IEnumerable IDatabase.HashScan(RedisKey key, RedisValue pattern, int => Inner.HashScan(ToInner(key), pattern, pageSize, cursor, pageOffset, flags); IEnumerable IDatabase.SetScan(RedisKey key, RedisValue pattern, int pageSize, CommandFlags flags) - => Inner.SetScan(ToInner(key), pattern, pageSize, flags); + => Inner.SetScan(ToInner(key), pattern, pageSize, flags); IEnumerable IDatabase.SetScan(RedisKey key, RedisValue pattern, int pageSize, long cursor, int pageOffset, CommandFlags flags) => Inner.SetScan(ToInner(key), pattern, pageSize, cursor, pageOffset, flags); diff --git a/src/StackExchange.Redis/LuaScript.cs b/src/StackExchange.Redis/LuaScript.cs index 6e4ac7cd3..8a9bdbcc1 100644 --- a/src/StackExchange.Redis/LuaScript.cs +++ b/src/StackExchange.Redis/LuaScript.cs @@ -189,7 +189,7 @@ public LoadedLuaScript Load(IServer server, CommandFlags flags = CommandFlags.No /// Loads this LuaScript into the given IServer so it can be run with it's SHA1 hash, instead of /// using the implicit SHA1 hash that's calculated after the script is sent to the server for the first time. /// - /// Note: the FireAndForget command flag cannot be set + /// Note: the FireAndForget command flag cannot be set. /// /// The server to load the script on. /// The command flags to use. diff --git a/src/StackExchange.Redis/Maintenance/AzureMaintenanceEvent.cs b/src/StackExchange.Redis/Maintenance/AzureMaintenanceEvent.cs index 330b27683..75bcb6de9 100644 --- a/src/StackExchange.Redis/Maintenance/AzureMaintenanceEvent.cs +++ b/src/StackExchange.Redis/Maintenance/AzureMaintenanceEvent.cs @@ -114,7 +114,7 @@ internal AzureMaintenanceEvent(string azureEvent) } } - internal async static Task AddListenerAsync(ConnectionMultiplexer multiplexer, Action? log = null) + internal static async Task AddListenerAsync(ConnectionMultiplexer multiplexer, Action? log = null) { if (!multiplexer.CommandMap.IsAvailable(RedisCommand.SUBSCRIBE)) { diff --git a/src/StackExchange.Redis/Message.cs b/src/StackExchange.Redis/Message.cs index 3cdb4c997..876f718c2 100644 --- a/src/StackExchange.Redis/Message.cs +++ b/src/StackExchange.Redis/Message.cs @@ -1,6 +1,4 @@ -using Microsoft.Extensions.Logging; -using StackExchange.Redis.Profiling; -using System; +using System; using System.Buffers.Binary; using System.Collections.Generic; using System.Diagnostics; @@ -8,6 +6,8 @@ using System.Runtime.CompilerServices; using System.Text; using System.Threading; +using Microsoft.Extensions.Logging; +using StackExchange.Redis.Profiling; namespace StackExchange.Redis { @@ -166,7 +166,7 @@ internal void PrepareToResend(ServerEndPoint resendTo, bool isMoved) public virtual string CommandAndKey => Command.ToString(); /// - /// Things with the potential to cause harm, or to reveal configuration information + /// Things with the potential to cause harm, or to reveal configuration information. /// public bool IsAdmin { @@ -307,29 +307,79 @@ public static Message Create(int db, CommandFlags flags, RedisCommand command, i public static Message Create(int db, CommandFlags flags, RedisCommand command, in RedisValue value0, in RedisValue value1, in RedisValue value2, in RedisValue value3, in RedisValue value4) => new CommandValueValueValueValueValueMessage(db, flags, command, value0, value1, value2, value3, value4); - public static Message Create(int db, CommandFlags flags, RedisCommand command, in RedisKey key0, - in RedisKey key1, in RedisValue value0, in RedisValue value1) => + public static Message Create( + int db, + CommandFlags flags, + RedisCommand command, + in RedisKey key0, + in RedisKey key1, + in RedisValue value0, + in RedisValue value1) => new CommandKeyKeyValueValueMessage(db, flags, command, key0, key1, value0, value1); - public static Message Create(int db, CommandFlags flags, RedisCommand command, in RedisKey key0, - in RedisKey key1, in RedisValue value0, in RedisValue value1, in RedisValue value2) => + public static Message Create( + int db, + CommandFlags flags, + RedisCommand command, + in RedisKey key0, + in RedisKey key1, + in RedisValue value0, + in RedisValue value1, + in RedisValue value2) => new CommandKeyKeyValueValueValueMessage(db, flags, command, key0, key1, value0, value1, value2); - public static Message Create(int db, CommandFlags flags, RedisCommand command, in RedisKey key0, - in RedisKey key1, in RedisValue value0, in RedisValue value1, in RedisValue value2, in RedisValue value3) => + public static Message Create( + int db, + CommandFlags flags, + RedisCommand command, + in RedisKey key0, + in RedisKey key1, + in RedisValue value0, + in RedisValue value1, + in RedisValue value2, + in RedisValue value3) => new CommandKeyKeyValueValueValueValueMessage(db, flags, command, key0, key1, value0, value1, value2, value3); - public static Message Create(int db, CommandFlags flags, RedisCommand command, in RedisKey key0, - in RedisKey key1, in RedisValue value0, in RedisValue value1, in RedisValue value2, in RedisValue value3, in RedisValue value4) => + public static Message Create( + int db, + CommandFlags flags, + RedisCommand command, + in RedisKey key0, + in RedisKey key1, + in RedisValue value0, + in RedisValue value1, + in RedisValue value2, + in RedisValue value3, + in RedisValue value4) => new CommandKeyKeyValueValueValueValueValueMessage(db, flags, command, key0, key1, value0, value1, value2, value3, value4); - public static Message Create(int db, CommandFlags flags, RedisCommand command, in RedisKey key0, - in RedisKey key1, in RedisValue value0, in RedisValue value1, in RedisValue value2, in RedisValue value3, in RedisValue value4, in RedisValue value5) => + public static Message Create( + int db, + CommandFlags flags, + RedisCommand command, + in RedisKey key0, + in RedisKey key1, + in RedisValue value0, + in RedisValue value1, + in RedisValue value2, + in RedisValue value3, + in RedisValue value4, + in RedisValue value5) => new CommandKeyKeyValueValueValueValueValueValueMessage(db, flags, command, key0, key1, value0, value1, value2, value3, value4, value5); - public static Message Create(int db, CommandFlags flags, RedisCommand command, in RedisKey key0, - in RedisKey key1, in RedisValue value0, in RedisValue value1, in RedisValue value2, in RedisValue value3, - in RedisValue value4, in RedisValue value5, in RedisValue value6) => + public static Message Create( + int db, + CommandFlags flags, + RedisCommand command, + in RedisKey key0, + in RedisKey key1, + in RedisValue value0, + in RedisValue value1, + in RedisValue value2, + in RedisValue value3, + in RedisValue value4, + in RedisValue value5, + in RedisValue value6) => new CommandKeyKeyValueValueValueValueValueValueValueMessage(db, flags, command, key0, key1, value0, value1, value2, value3, value4, value5, value6); public static Message CreateInSlot(int db, int slot, CommandFlags flags, RedisCommand command, RedisValue[] values) => @@ -357,30 +407,34 @@ public virtual void AppendStormLog(StringBuilder sb) /// (i.e. "why does my standalone server keep saying ERR unknown command 'cluster' ?") /// 2: it allows the initial PING and GET (during connect) to get queued rather /// than be rejected as no-server-available (note that this doesn't apply to - /// handshake messages, as they bypass the queue completely) - /// 3: it disables non-pref logging, as it is usually server-targeted + /// handshake messages, as they bypass the queue completely). + /// 3: it disables non-pref logging, as it is usually server-targeted. /// public void SetInternalCall() => Flags |= InternalCallFlag; /// - /// Gets a string representation of this message: "[{DB}]:{CommandAndKey} ({resultProcessor})" + /// Gets a string representation of this message: "[{DB}]:{CommandAndKey} ({resultProcessor})". /// public override string ToString() => $"[{Db}]:{CommandAndKey} ({resultProcessor?.GetType().Name ?? "(n/a)"})"; /// - /// Gets a string representation of this message without the key: "[{DB}]:{Command} ({resultProcessor})" + /// Gets a string representation of this message without the key: "[{DB}]:{Command} ({resultProcessor})". /// public string ToStringCommandOnly() => $"[{Db}]:{Command} ({resultProcessor?.GetType().Name ?? "(n/a)"})"; public void SetResponseReceived() => performance?.SetResponseReceived(); - bool ICompletable.TryComplete(bool isAsync) { Complete(); return true; } + bool ICompletable.TryComplete(bool isAsync) + { + Complete(); + return true; + } public void Complete() { - //Ensure we can never call Complete on the same resultBox from two threads by grabbing it now + // Ensure we can never call Complete on the same resultBox from two threads by grabbing it now var currBox = Interlocked.Exchange(ref resultBox, null); // set the completion/performance data @@ -452,7 +506,7 @@ internal static Message Create(int db, CommandFlags flags, RedisCommand command, 3 => new CommandKeyKeyValueValueValueMessage(db, flags, command, key0, key1, values[0], values[1], values[2]), 4 => new CommandKeyKeyValueValueValueValueMessage(db, flags, command, key0, key1, values[0], values[1], values[2], values[3]), 5 => new CommandKeyKeyValueValueValueValueValueMessage(db, flags, command, key0, key1, values[0], values[1], values[2], values[3], values[4]), - 6 => new CommandKeyKeyValueValueValueValueValueValueMessage(db, flags, command, key0, key1, values[0], values[1], values[2], values[3],values[4],values[5]), + 6 => new CommandKeyKeyValueValueValueValueValueValueMessage(db, flags, command, key0, key1, values[0], values[1], values[2], values[3], values[4], values[5]), 7 => new CommandKeyKeyValueValueValueValueValueValueValueMessage(db, flags, command, key0, key1, values[0], values[1], values[2], values[3], values[4], values[5], values[6]), _ => new CommandKeyKeyValuesMessage(db, flags, command, key0, key1, values), }; @@ -699,6 +753,7 @@ internal void SetSource(ResultProcessor? resultProcessor, IResultBox? resultBox) /// /// Note order here is reversed to prevent overload resolution errors. /// + /// The type of the result box result. internal void SetSource(IResultBox resultBox, ResultProcessor? resultProcessor) { this.resultBox = resultBox; @@ -1263,8 +1318,14 @@ private sealed class CommandKeyKeyValueValueMessage : CommandKeyBase private readonly RedisValue value0, value1; private readonly RedisKey key1; - public CommandKeyKeyValueValueMessage(int db, CommandFlags flags, RedisCommand command, in RedisKey key0, - in RedisKey key1, in RedisValue value0, in RedisValue value1) : base(db, flags, command, key0) + public CommandKeyKeyValueValueMessage( + int db, + CommandFlags flags, + RedisCommand command, + in RedisKey key0, + in RedisKey key1, + in RedisValue value0, + in RedisValue value1) : base(db, flags, command, key0) { key1.AssertNotNull(); value0.AssertNotNull(); @@ -1291,8 +1352,15 @@ private sealed class CommandKeyKeyValueValueValueMessage : CommandKeyBase private readonly RedisValue value0, value1, value2; private readonly RedisKey key1; - public CommandKeyKeyValueValueValueMessage(int db, CommandFlags flags, RedisCommand command, in RedisKey key0, - in RedisKey key1, in RedisValue value0, in RedisValue value1, in RedisValue value2) : base(db, flags, command, key0) + public CommandKeyKeyValueValueValueMessage( + int db, + CommandFlags flags, + RedisCommand command, + in RedisKey key0, + in RedisKey key1, + in RedisValue value0, + in RedisValue value1, + in RedisValue value2) : base(db, flags, command, key0) { key1.AssertNotNull(); value0.AssertNotNull(); @@ -1322,8 +1390,16 @@ private sealed class CommandKeyKeyValueValueValueValueMessage : CommandKeyBase private readonly RedisValue value0, value1, value2, value3; private readonly RedisKey key1; - public CommandKeyKeyValueValueValueValueMessage(int db, CommandFlags flags, RedisCommand command, in RedisKey key0, - in RedisKey key1, in RedisValue value0, in RedisValue value1, in RedisValue value2, in RedisValue value3) : base(db, flags, command, key0) + public CommandKeyKeyValueValueValueValueMessage( + int db, + CommandFlags flags, + RedisCommand command, + in RedisKey key0, + in RedisKey key1, + in RedisValue value0, + in RedisValue value1, + in RedisValue value2, + in RedisValue value3) : base(db, flags, command, key0) { key1.AssertNotNull(); value0.AssertNotNull(); @@ -1356,8 +1432,17 @@ private sealed class CommandKeyKeyValueValueValueValueValueMessage : CommandKeyB private readonly RedisValue value0, value1, value2, value3, value4; private readonly RedisKey key1; - public CommandKeyKeyValueValueValueValueValueMessage(int db, CommandFlags flags, RedisCommand command, in RedisKey key0, - in RedisKey key1, in RedisValue value0, in RedisValue value1, in RedisValue value2, in RedisValue value3, in RedisValue value4) : base(db, flags, command, key0) + public CommandKeyKeyValueValueValueValueValueMessage( + int db, + CommandFlags flags, + RedisCommand command, + in RedisKey key0, + in RedisKey key1, + in RedisValue value0, + in RedisValue value1, + in RedisValue value2, + in RedisValue value3, + in RedisValue value4) : base(db, flags, command, key0) { key1.AssertNotNull(); value0.AssertNotNull(); @@ -1393,8 +1478,18 @@ private sealed class CommandKeyKeyValueValueValueValueValueValueMessage : Comman private readonly RedisValue value0, value1, value2, value3, value4, value5; private readonly RedisKey key1; - public CommandKeyKeyValueValueValueValueValueValueMessage(int db, CommandFlags flags, RedisCommand command, in RedisKey key0, - in RedisKey key1, in RedisValue value0, in RedisValue value1, in RedisValue value2, in RedisValue value3, in RedisValue value4, in RedisValue value5) : base(db, flags, command, key0) + public CommandKeyKeyValueValueValueValueValueValueMessage( + int db, + CommandFlags flags, + RedisCommand command, + in RedisKey key0, + in RedisKey key1, + in RedisValue value0, + in RedisValue value1, + in RedisValue value2, + in RedisValue value3, + in RedisValue value4, + in RedisValue value5) : base(db, flags, command, key0) { key1.AssertNotNull(); value0.AssertNotNull(); @@ -1433,8 +1528,19 @@ private sealed class CommandKeyKeyValueValueValueValueValueValueValueMessage : C private readonly RedisValue value0, value1, value2, value3, value4, value5, value6; private readonly RedisKey key1; - public CommandKeyKeyValueValueValueValueValueValueValueMessage(int db, CommandFlags flags, RedisCommand command, in RedisKey key0, - in RedisKey key1, in RedisValue value0, in RedisValue value1, in RedisValue value2, in RedisValue value3, in RedisValue value4, in RedisValue value5, in RedisValue value6) : base(db, flags, command, key0) + public CommandKeyKeyValueValueValueValueValueValueValueMessage( + int db, + CommandFlags flags, + RedisCommand command, + in RedisKey key0, + in RedisKey key1, + in RedisValue value0, + in RedisValue value1, + in RedisValue value2, + in RedisValue value3, + in RedisValue value4, + in RedisValue value5, + in RedisValue value6) : base(db, flags, command, key0) { key1.AssertNotNull(); value0.AssertNotNull(); diff --git a/src/StackExchange.Redis/PhysicalBridge.cs b/src/StackExchange.Redis/PhysicalBridge.cs index 7f9ffa32e..0755c939e 100644 --- a/src/StackExchange.Redis/PhysicalBridge.cs +++ b/src/StackExchange.Redis/PhysicalBridge.cs @@ -49,7 +49,7 @@ internal sealed class PhysicalBridge : IDisposable private volatile bool isDisposed; private long nonPreferredEndpointCount; - //private volatile int missedHeartbeats; + // private volatile int missedHeartbeats; private long operationCount, socketCount; private volatile PhysicalConnection? physical; @@ -63,7 +63,7 @@ internal sealed class PhysicalBridge : IDisposable internal long? ConnectionId => physical?.ConnectionId; #if NETCOREAPP - private readonly SemaphoreSlim _singleWriterMutex = new(1,1); + private readonly SemaphoreSlim _singleWriterMutex = new(1, 1); #else private readonly MutexSlim _singleWriterMutex; #endif @@ -98,7 +98,7 @@ public enum State : byte Connecting, ConnectedEstablishing, ConnectedEstablished, - Disconnected + Disconnected, } public Exception? LastException { get; private set; } @@ -123,7 +123,7 @@ public enum State : byte public RedisCommand LastCommand { get; private set; } /// - /// If we have a connection, report the protocol being used + /// If we have a connection, report the protocol being used. /// public RedisProtocol? Protocol => physical?.Protocol; @@ -292,10 +292,12 @@ internal readonly struct BridgeStatus /// Number of messages sent since the last heartbeat was processed. /// public int MessagesSinceLastHeartbeat { get; init; } + /// /// The time this connection was connected at, if it's connected currently. /// public DateTime? ConnectedAt { get; init; } + /// /// Whether the pipe writer is currently active. /// @@ -310,10 +312,12 @@ internal readonly struct BridgeStatus /// The number of messages that are in the backlog queue (waiting to be sent when the connection is healthy again). /// public int BacklogMessagesPending { get; init; } + /// /// The number of messages that are in the backlog queue (waiting to be sent when the connection is healthy again). /// public int BacklogMessagesPendingCounter { get; init; } + /// /// The number of messages ever added to the backlog queue in the life of this connection. /// @@ -392,8 +396,7 @@ internal void KeepAlive(bool forceRun = false) } else if (commandMap.IsAvailable(RedisCommand.UNSUBSCRIBE)) { - msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.UNSUBSCRIBE, - RedisChannel.Literal(Multiplexer.UniqueId)); + msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.UNSUBSCRIBE, RedisChannel.Literal(Multiplexer.UniqueId)); msg.SetSource(ResultProcessor.TrackSubscriptions, null); } break; @@ -478,7 +481,7 @@ internal void OnDisconnected(ConnectionFailureType failureType, PhysicalConnecti oldState = default(State); // only defined when isCurrent = true ConnectedAt = default; - if (isCurrent = (physical == connection)) + if (isCurrent = physical == connection) { Trace("Bridge noting disconnect from active connection" + (isDisposed ? " (disposed)" : "")); oldState = ChangeState(State.Disconnected); @@ -745,8 +748,8 @@ private WriteResult WriteMessageInsideLock(PhysicalConnection physical, Message message.Complete(); return result; } - //The parent message (next) may be returned from GetMessages - //and should not be marked as sent again below + // The parent message (next) may be returned from GetMessages + // and should not be marked as sent again below. messageIsSent = messageIsSent || subCommand == message; } if (!messageIsSent) @@ -840,7 +843,6 @@ private bool TryPushToBacklog(Message message, bool onlyIfExists, bool bypassBac // In the handshake case: send the command directly through. // If we're disconnected *in the middle of a handshake*, we've bombed a brand new socket and failing, // backing off, and retrying next heartbeat is best anyway. - // // Internal calls also shouldn't queue - try immediately. If these aren't errors (most aren't), we // won't alert the user. if (bypassBacklog || message.IsInternalCall) @@ -848,9 +850,9 @@ private bool TryPushToBacklog(Message message, bool onlyIfExists, bool bypassBac return false; } - // Note, for deciding emptiness for whether to push onlyIfExists, and start worker, - // we only need care if WE are able to - // see the queue when its empty. Not whether anyone else sees it as empty. + // Note, for deciding emptiness for whether to push onlyIfExists, and start worker, + // we only need care if WE are able to see the queue when its empty. + // Not whether anyone else sees it as empty. // So strong synchronization is not required. if (onlyIfExists && Volatile.Read(ref _backlogCurrentEnqueued) == 0) { @@ -988,6 +990,7 @@ internal enum BacklogStatus : byte } private volatile BacklogStatus _backlogStatus; + /// /// Process the backlog(s) in play if any. /// This means flushing commands to an available/active connection (if any) or spinning until timeout if not. @@ -1312,7 +1315,8 @@ private async ValueTask WriteMessageTakingWriteLockAsync_Awaited( #else ValueTask pending, #endif - PhysicalConnection physical, Message message) + PhysicalConnection physical, + Message message) { #if NETCOREAPP bool gotLock = false; @@ -1353,6 +1357,7 @@ private async ValueTask WriteMessageTakingWriteLockAsync_Awaited( } } + [SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1519:Braces should not be omitted from multi-line child statement", Justification = "Detector is confused with the #ifdefs here")] private async ValueTask CompleteWriteAndReleaseLockAsync( #if !NETCOREAPP LockToken lockToken, @@ -1503,7 +1508,7 @@ private WriteResult WriteMessageToServerInsideWriteLock(PhysicalConnection conne { throw ExceptionFactory.PrimaryOnly(Multiplexer.RawConfig.IncludeDetailInExceptions, message.Command, message, ServerEndPoint); } - switch(cmd) + switch (cmd) { case RedisCommand.QUIT: connection.RecordQuit(); @@ -1519,7 +1524,7 @@ private WriteResult WriteMessageToServerInsideWriteLock(PhysicalConnection conne { // If we are executing AUTH, it means we are still unauthenticated // Setting READONLY before AUTH always fails but we think it succeeded since - // we run it as Fire and Forget. + // we run it as Fire and Forget. if (cmd != RedisCommand.AUTH && cmd != RedisCommand.HELLO) { var readmode = connection.GetReadModeCommand(isPrimaryOnly); @@ -1555,8 +1560,7 @@ private WriteResult WriteMessageToServerInsideWriteLock(PhysicalConnection conne if (_nextHighIntegrityToken is not 0 && !connection.TransactionActive // validated in the UNWATCH/EXEC/DISCARD - && message.Command is not RedisCommand.AUTH or RedisCommand.HELLO // if auth fails, ECHO may also fail; avoid confusion - ) + && message.Command is not RedisCommand.AUTH or RedisCommand.HELLO) // if auth fails, ECHO may also fail; avoid confusion { // make sure this value exists early to avoid a race condition // if the response comes back super quickly @@ -1607,8 +1611,8 @@ private WriteResult WriteMessageToServerInsideWriteLock(PhysicalConnection conne Trace("Write failed: " + ex.Message); message.Fail(ConnectionFailureType.InternalFailure, ex, null, Multiplexer); message.Complete(); - // This failed without actually writing; we're OK with that... unless there's a transaction + // This failed without actually writing; we're OK with that... unless there's a transaction if (connection?.TransactionActive == true) { // We left it in a broken state - need to kill the connection @@ -1645,7 +1649,7 @@ private uint NextHighIntegrityTokenInsideLock() } /// - /// For testing only + /// For testing only. /// internal void SimulateConnectionFailure(SimulatedFailureType failureType) { diff --git a/src/StackExchange.Redis/PhysicalConnection.cs b/src/StackExchange.Redis/PhysicalConnection.cs index c282121a5..0a07f8ac4 100644 --- a/src/StackExchange.Redis/PhysicalConnection.cs +++ b/src/StackExchange.Redis/PhysicalConnection.cs @@ -1,7 +1,6 @@ -using Pipelines.Sockets.Unofficial; -using Pipelines.Sockets.Unofficial.Arenas; -using System; +using System; using System.Buffers; +using System.Buffers.Binary; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -18,8 +17,9 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Pipelines.Sockets.Unofficial; +using Pipelines.Sockets.Unofficial.Arenas; using static StackExchange.Redis.Message; -using System.Buffers.Binary; namespace StackExchange.Redis { @@ -127,7 +127,8 @@ internal async Task BeginConnectAsync(ILogger? log) { bridge.Multiplexer.RawConfig.BeforeSocketConnect?.Invoke(endpoint, bridge.ConnectionType, _socket); if (tunnel is not null) - { // same functionality as part of a tunnel + { + // same functionality as part of a tunnel await tunnel.BeforeSocketConnectAsync(endpoint, bridge.ConnectionType, _socket, CancellationToken.None).ForAwait(); } } @@ -148,11 +149,13 @@ internal async Task BeginConnectAsync(ILogger? log) args?.Abort(); } else if (args is not null && x.ConnectAsync(args)) - { // asynchronous operation is pending + { + // asynchronous operation is pending timeoutSource = ConfigureTimeout(args, bridge.Multiplexer.RawConfig.ConnectTimeout); } else - { // completed synchronously + { + // completed synchronously args?.Complete(); } @@ -231,16 +234,18 @@ private static CancellationTokenSource ConfigureTimeout(SocketAwaitableEventArgs { var cts = new CancellationTokenSource(); var timeout = Task.Delay(timeoutMilliseconds, cts.Token); - timeout.ContinueWith((_, state) => - { - try + timeout.ContinueWith( + (_, state) => { - var a = (SocketAwaitableEventArgs)state!; - a.Abort(SocketError.TimedOut); - Socket.CancelConnectAsync(a); - } - catch { } - }, args); + try + { + var a = (SocketAwaitableEventArgs)state!; + a.Abort(SocketError.TimedOut); + Socket.CancelConnectAsync(a); + } + catch { } + }, + args); return cts; } @@ -271,7 +276,7 @@ private enum ReadMode : byte internal void SetProtocol(RedisProtocol value) => _protocol = value; - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification = "Trust me yo")] internal void Shutdown() { var ioPipe = Interlocked.Exchange(ref _ioPipe, null); // compare to the critical read @@ -384,8 +389,7 @@ public void RecordConnectionFailed( Exception? innerException = null, [CallerMemberName] string? origin = null, bool isInitialConnect = false, - IDuplexPipe? connectingPipe = null - ) + IDuplexPipe? connectingPipe = null) { bool weAskedForThis = false; Exception? outerException = innerException; @@ -456,7 +460,7 @@ public void RecordConnectionFailed( } var data = new List>(); - void add(string lk, string sk, string? v) + void AddData(string lk, string sk, string? v) { if (lk != null) data.Add(Tuple.Create(lk, v)); if (sk != null) exMessage.Append(", ").Append(sk).Append(": ").Append(v); @@ -473,30 +477,30 @@ void add(string lk, string sk, string? v) data.Add(Tuple.Create("FailureType", failureType.ToString())); data.Add(Tuple.Create("EndPoint", Format.ToString(bridge.ServerEndPoint?.EndPoint))); - add("Origin", "origin", origin); + AddData("Origin", "origin", origin); // add("Input-Buffer", "input-buffer", _ioPipe.Input); - 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"); - if (unansweredWriteTime != 0) add("Unanswered-Write", "unanswered-write", (unchecked(now - unansweredWriteTime) / 1000) + "s ago"); - add("Keep-Alive", "keep-alive", bridge.ServerEndPoint?.WriteEverySeconds + "s"); - add("Previous-Physical-State", "state", oldState.ToString()); - add("Manager", "mgr", bridge.Multiplexer.SocketManager?.GetState()); - if (connStatus.BytesAvailableOnSocket >= 0) add("Inbound-Bytes", "in", connStatus.BytesAvailableOnSocket.ToString()); - if (connStatus.BytesInReadPipe >= 0) add("Inbound-Pipe-Bytes", "in-pipe", connStatus.BytesInReadPipe.ToString()); - if (connStatus.BytesInWritePipe >= 0) add("Outbound-Pipe-Bytes", "out-pipe", connStatus.BytesInWritePipe.ToString()); - - add("Last-Heartbeat", "last-heartbeat", (lastBeat == 0 ? "never" : ((unchecked(now - lastBeat) / 1000) + "s ago")) + (bridge.IsBeating ? " (mid-beat)" : "")); + AddData("Outstanding-Responses", "outstanding", GetSentAwaitingResponseCount().ToString()); + AddData("Last-Read", "last-read", (unchecked(now - lastRead) / 1000) + "s ago"); + AddData("Last-Write", "last-write", (unchecked(now - lastWrite) / 1000) + "s ago"); + if (unansweredWriteTime != 0) AddData("Unanswered-Write", "unanswered-write", (unchecked(now - unansweredWriteTime) / 1000) + "s ago"); + AddData("Keep-Alive", "keep-alive", bridge.ServerEndPoint?.WriteEverySeconds + "s"); + AddData("Previous-Physical-State", "state", oldState.ToString()); + AddData("Manager", "mgr", bridge.Multiplexer.SocketManager?.GetState()); + if (connStatus.BytesAvailableOnSocket >= 0) AddData("Inbound-Bytes", "in", connStatus.BytesAvailableOnSocket.ToString()); + if (connStatus.BytesInReadPipe >= 0) AddData("Inbound-Pipe-Bytes", "in-pipe", connStatus.BytesInReadPipe.ToString()); + if (connStatus.BytesInWritePipe >= 0) AddData("Outbound-Pipe-Bytes", "out-pipe", connStatus.BytesInWritePipe.ToString()); + + AddData("Last-Heartbeat", "last-heartbeat", (lastBeat == 0 ? "never" : ((unchecked(now - lastBeat) / 1000) + "s ago")) + (bridge.IsBeating ? " (mid-beat)" : "")); var mbeat = bridge.Multiplexer.LastHeartbeatSecondsAgo; if (mbeat >= 0) { - add("Last-Multiplexer-Heartbeat", "last-mbeat", mbeat + "s ago"); + AddData("Last-Multiplexer-Heartbeat", "last-mbeat", mbeat + "s ago"); } - add("Last-Global-Heartbeat", "global", ConnectionMultiplexer.LastGlobalHeartbeatSecondsAgo + "s ago"); + AddData("Last-Global-Heartbeat", "global", ConnectionMultiplexer.LastGlobalHeartbeatSecondsAgo + "s ago"); } } - add("Version", "v", Utils.GetLibVersion()); + AddData("Version", "v", Utils.GetLibVersion()); outerException = new RedisConnectionException(failureType, exMessage.ToString(), innerException); @@ -595,7 +599,7 @@ internal static void IdentifyFailureType(Exception? exception, ref ConnectionFai AuthenticationException => ConnectionFailureType.AuthenticationFailure, EndOfStreamException or ObjectDisposedException => ConnectionFailureType.SocketClosed, SocketException or IOException => ConnectionFailureType.SocketFailure, - _ => failureType + _ => failureType, }; } } @@ -768,9 +772,10 @@ internal int OnBridgeHeartbeat() if (msg.ResultBoxIsAsync) { bool haveDeltas = msg.TryGetPhysicalState(out _, out _, out long sentDelta, out var receivedDelta) && sentDelta >= 0 && receivedDelta >= 0; - var timeoutEx = ExceptionFactory.Timeout(multiplexer, haveDeltas + var baseErrorMessage = haveDeltas ? $"Timeout awaiting response (outbound={sentDelta >> 10}KiB, inbound={receivedDelta >> 10}KiB, {elapsed}ms elapsed, timeout is {timeout}ms)" - : $"Timeout awaiting response ({elapsed}ms elapsed, timeout is {timeout}ms)", msg, server); + : $"Timeout awaiting response ({elapsed}ms elapsed, timeout is {timeout}ms)"; + var timeoutEx = ExceptionFactory.Timeout(multiplexer, baseErrorMessage, msg, server); multiplexer.OnMessageFaulted(msg, timeoutEx); msg.SetExceptionAndComplete(timeoutEx, bridge); // tell the message that it is doomed multiplexer.OnAsyncTimeout(); @@ -1101,7 +1106,6 @@ private static void WriteUnifiedSpan(PipeWriter writer, ReadOnlySpan value { // ${len}\r\n = 3 + MaxInt32TextLen // {value}\r\n = 2 + value.Length - const int MaxQuickSpanSize = 512; if (value.Length == 0) { @@ -1162,7 +1166,6 @@ internal void WriteSha1AsHex(byte[] value) { // $40\r\n = 5 // {40 bytes}\r\n = 42 - var span = writer.GetSpan(47); span[0] = (byte)'$'; span[1] = (byte)'4'; @@ -1308,10 +1311,11 @@ private static void WriteUnifiedPrefixedBlob(PipeWriter? maybeNullWriter, byte[] return; // Prevent null refs during disposal } - // ${total-len}\r\n + // ${total-len}\r\n // {prefix}{value}\r\n if (prefix == null || prefix.Length == 0 || value == null) - { // if no prefix, just use the non-prefixed version; + { + // if no prefix, just use the non-prefixed version; // even if prefixed, a null value writes as null, so can use the non-prefixed version WriteUnifiedBlob(writer, value); } @@ -1365,8 +1369,7 @@ private static void WriteUnifiedUInt64(PipeWriter writer, ulong value) } internal static void WriteInteger(PipeWriter writer, long value) { - //note: client should never write integer; only server does this - + // note: client should never write integer; only server does this // :{asc}\r\n = MaxInt64TextLen + 3 var span = writer.GetSpan(3 + Format.MaxInt64TextLen); @@ -1386,18 +1389,22 @@ internal readonly struct ConnectionStatus /// Bytes available on the socket, not yet read into the pipe. /// public long BytesAvailableOnSocket { get; init; } + /// /// Bytes read from the socket, pending in the reader pipe. /// public long BytesInReadPipe { get; init; } + /// /// Bytes in the writer pipe, waiting to be written to the socket. /// public long BytesInWritePipe { get; init; } + /// /// Byte size of the last result we processed. /// public long BytesLastResult { get; init; } + /// /// Byte size on the buffer that isn't processed yet. /// @@ -1407,6 +1414,7 @@ internal readonly struct ConnectionStatus /// The inbound pipe reader status. /// public ReadStatus ReadStatus { get; init; } + /// /// The outbound pipe writer status. /// @@ -1511,7 +1519,8 @@ public ConnectionStatus GetStatus() if (!string.IsNullOrEmpty(pfxPath) && File.Exists(pfxPath)) { - return delegate { return new X509Certificate2(pfxPath, pfxPassword ?? "", flags ?? X509KeyStorageFlags.DefaultKeySet); }; + return (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => + new X509Certificate2(pfxPath, pfxPassword ?? "", flags ?? X509KeyStorageFlags.DefaultKeySet); } } catch (Exception ex) @@ -1535,7 +1544,6 @@ internal async ValueTask ConnectedAsync(Socket? socket, ILogger? log, Sock // the order is important here: // non-TLS: [Socket]<==[SocketConnection:IDuplexPipe] // TLS: [Socket]<==[NetworkStream]<==[SslStream]<==[StreamConnection:IDuplexPipe] - var config = bridge.Multiplexer.RawConfig; var tunnel = config.Tunnel; @@ -1555,10 +1563,12 @@ internal async ValueTask ConnectedAsync(Socket? socket, ILogger? log, Sock } stream ??= new NetworkStream(socket ?? throw new InvalidOperationException("No socket or stream available - possibly a tunnel error")); - var ssl = new SslStream(stream, false, - config.CertificateValidationCallback ?? GetAmbientIssuerCertificateCallback(), - config.CertificateSelectionCallback ?? GetAmbientClientCertificateCallback(), - EncryptionPolicy.RequireEncryption); + var ssl = new SslStream( + innerStream: stream, + leaveInnerStreamOpen: false, + userCertificateValidationCallback: config.CertificateValidationCallback ?? GetAmbientIssuerCertificateCallback(), + userCertificateSelectionCallback: config.CertificateSelectionCallback ?? GetAmbientClientCertificateCallback(), + encryptionPolicy: EncryptionPolicy.RequireEncryption); try { try @@ -1744,7 +1754,6 @@ private void MatchResult(in RawResult result) Volatile.Write(ref _awaitingToken, msg); } - _readStatus = ReadStatus.MatchResultComplete; _activeMessage = null; @@ -1972,30 +1981,6 @@ private int ProcessBuffer(ref ReadOnlySequence buffer) _readStatus = ReadStatus.ProcessBufferComplete; return messageCount; } - //void ISocketCallback.Read() - //{ - // Interlocked.Increment(ref haveReader); - // try - // { - // do - // { - // int space = EnsureSpaceAndComputeBytesToRead(); - // int bytesRead = netStream?.Read(ioBuffer, ioBufferBytes, space) ?? 0; - - // if (!ProcessReadBytes(bytesRead)) return; // EOF - // } while (socketToken.Available != 0); - // Multiplexer.Trace("Buffer exhausted", physicalName); - // // ^^^ note that the socket manager will call us again when there is something to do - // } - // catch (Exception ex) - // { - // RecordConnectionFailed(ConnectionFailureType.InternalFailure, ex); - // } - // finally - // { - // Interlocked.Decrement(ref haveReader); - // } - //} private static RawResult.ResultFlags AsNull(RawResult.ResultFlags flags) => flags & ~RawResult.ResultFlags.NonNull; @@ -2004,18 +1989,25 @@ private static RawResult ReadArray(ResultType resultType, RawResult.ResultFlags var itemCount = ReadLineTerminatedString(ResultType.Integer, flags, ref reader); if (itemCount.HasValue) { - if (!itemCount.TryGetInt64(out long i64)) throw ExceptionFactory.ConnectionFailure(includeDetailInExceptions, ConnectionFailureType.ProtocolFailure, - itemCount.Is('?') ? "Streamed aggregate types not yet implemented" : "Invalid array length", server); + if (!itemCount.TryGetInt64(out long i64)) + { + throw ExceptionFactory.ConnectionFailure( + includeDetailInExceptions, + ConnectionFailureType.ProtocolFailure, + itemCount.Is('?') ? "Streamed aggregate types not yet implemented" : "Invalid array length", + server); + } + int itemCountActual = checked((int)i64); if (itemCountActual < 0) { - //for null response by command like EXEC, RESP array: *-1\r\n + // for null response by command like EXEC, RESP array: *-1\r\n return new RawResult(resultType, items: default, AsNull(flags)); } else if (itemCountActual == 0) { - //for zero array response by command like SCAN, Resp array: *0\r\n + // for zero array response by command like SCAN, Resp array: *0\r\n return new RawResult(resultType, items: default, flags); } @@ -2060,8 +2052,11 @@ private static RawResult ReadBulkString(ResultType type, RawResult.ResultFlags f { if (!prefix.TryGetInt64(out long i64)) { - throw ExceptionFactory.ConnectionFailure(includeDetailInExceptions, ConnectionFailureType.ProtocolFailure, - prefix.Is('?') ? "Streamed strings not yet implemented" : "Invalid bulk string length", server); + throw ExceptionFactory.ConnectionFailure( + includeDetailInExceptions, + ConnectionFailureType.ProtocolFailure, + prefix.Is('?') ? "Streamed strings not yet implemented" : "Invalid bulk string length", + server); } int bodySize = checked((int)i64); if (bodySize < 0) @@ -2128,15 +2123,33 @@ internal enum ReadStatus internal void StartReading() => ReadFromPipe().RedisFireAndForget(); - internal static RawResult TryParseResult(bool isResp3, Arena arena, in ReadOnlySequence buffer, ref BufferReader reader, - bool includeDetilInExceptions, PhysicalConnection? connection, bool allowInlineProtocol = false) - { - return TryParseResult(isResp3 ? (RawResult.ResultFlags.Resp3 | RawResult.ResultFlags.NonNull) : RawResult.ResultFlags.NonNull, - arena, buffer, ref reader, includeDetilInExceptions, connection?.BridgeCouldBeNull?.ServerEndPoint, allowInlineProtocol); - } - - private static RawResult TryParseResult(RawResult.ResultFlags flags, Arena arena, in ReadOnlySequence buffer, ref BufferReader reader, - bool includeDetilInExceptions, ServerEndPoint? server, bool allowInlineProtocol = false) + internal static RawResult TryParseResult( + bool isResp3, + Arena arena, + in ReadOnlySequence buffer, + ref BufferReader reader, + bool includeDetilInExceptions, + PhysicalConnection? connection, + bool allowInlineProtocol = false) + { + return TryParseResult( + isResp3 ? (RawResult.ResultFlags.Resp3 | RawResult.ResultFlags.NonNull) : RawResult.ResultFlags.NonNull, + arena, + buffer, + ref reader, + includeDetilInExceptions, + connection?.BridgeCouldBeNull?.ServerEndPoint, + allowInlineProtocol); + } + + private static RawResult TryParseResult( + RawResult.ResultFlags flags, + Arena arena, + in ReadOnlySequence buffer, + ref BufferReader reader, + bool includeDetilInExceptions, + ServerEndPoint? server, + bool allowInlineProtocol = false) { int prefix; do // this loop is just to allow us to parse (skip) attributes without doing a stack-dive @@ -2198,7 +2211,8 @@ private static RawResult TryParseResult(RawResult.ResultFlags flags, Arena - /// Returns the number of commands captured in this snapshot + /// Returns the number of commands captured in this snapshot. /// public int Count() => _count; /// - /// Returns the number of commands captured in this snapshot that match a condition + /// Returns the number of commands captured in this snapshot that match a condition. /// /// The predicate to match. public int Count(Func predicate) @@ -103,10 +104,11 @@ public int Count(Func predicate) } /// - /// Returns the captured commands as an array + /// Returns the captured commands as an array. /// public IProfiledCommand[] ToArray() - { // exploit the fact that we know the length + { + // exploit the fact that we know the length if (_count == 0) return Array.Empty(); var arr = new IProfiledCommand[_count]; @@ -120,10 +122,11 @@ public IProfiledCommand[] ToArray() } /// - /// Returns the captured commands as a list + /// Returns the captured commands as a list. /// public List ToList() - { // exploit the fact that we know the length + { + // exploit the fact that we know the length var list = new List(_count); ProfiledCommand? cur = _head; while (cur != null) diff --git a/src/StackExchange.Redis/Profiling/ProfilingSession.cs b/src/StackExchange.Redis/Profiling/ProfilingSession.cs index 83f1969bd..f83a49c91 100644 --- a/src/StackExchange.Redis/Profiling/ProfilingSession.cs +++ b/src/StackExchange.Redis/Profiling/ProfilingSession.cs @@ -11,6 +11,7 @@ public sealed class ProfilingSession /// Caller-defined state object. /// public object? UserToken { get; } + /// /// Create a new profiling session, optionally including a caller-defined state object. /// diff --git a/src/StackExchange.Redis/RawResult.cs b/src/StackExchange.Redis/RawResult.cs index 1581c29c9..300503f57 100644 --- a/src/StackExchange.Redis/RawResult.cs +++ b/src/StackExchange.Redis/RawResult.cs @@ -1,8 +1,8 @@ -using Pipelines.Sockets.Unofficial.Arenas; -using System; +using System; using System.Buffers; using System.Runtime.CompilerServices; using System.Text; +using Pipelines.Sockets.Unofficial.Arenas; namespace StackExchange.Redis { @@ -92,7 +92,7 @@ private static void ThrowInvalidType(ResultType resultType) // if null, assume array public ResultType Resp2TypeArray => _resultType == ResultType.Null ? ResultType.Array : _resultType.ToResp2(); - internal bool IsNull => (_flags & ResultFlags.NonNull) == 0; + internal bool IsNull => (_flags & ResultFlags.NonNull) == 0; public bool HasValue => (_flags & ResultFlags.HasValue) != 0; @@ -274,7 +274,7 @@ internal bool StartsWith(byte[] expected) if (rangeToCheck.IsSingleSegment) return rangeToCheck.First.Span.SequenceEqual(expected); int offset = 0; - foreach(var segment in rangeToCheck) + foreach (var segment in rangeToCheck) { var from = segment.Span; var to = new Span(expected, offset, from.Length); @@ -406,12 +406,12 @@ private static GeoPosition AsGeoPosition(in Sequence coords) #else var decoder = Encoding.UTF8.GetDecoder(); int charCount = 0; - foreach(var segment in Payload) + foreach (var segment in Payload) { var span = segment.Span; if (span.IsEmpty) continue; - fixed(byte* bPtr = span) + fixed (byte* bPtr = span) { charCount += decoder.GetCharCount(bPtr, span.Length, false); } @@ -444,9 +444,9 @@ private static GeoPosition AsGeoPosition(in Sequence coords) #endif static string? GetVerbatimString(string? value, out ReadOnlySpan type) { - // the first three bytes provide information about the format of the following string, which - // can be txt for plain text, or mkd for markdown. The fourth byte is always `:` - // Then the real string follows. + // The first three bytes provide information about the format of the following string, which + // can be txt for plain text, or mkd for markdown. The fourth byte is always `:`. + // Then the real string follows. if (value is not null && value.Length >= 4 && value[3] == ':') { diff --git a/src/StackExchange.Redis/RedisBatch.cs b/src/StackExchange.Redis/RedisBatch.cs index 6c9727d0d..0a4c888f2 100644 --- a/src/StackExchange.Redis/RedisBatch.cs +++ b/src/StackExchange.Redis/RedisBatch.cs @@ -8,7 +8,7 @@ internal class RedisBatch : RedisDatabase, IBatch { private List? pending; - public RedisBatch(RedisDatabase wrapped, object? asyncState) : base(wrapped.multiplexer, wrapped.Database, asyncState ?? wrapped.AsyncState) {} + public RedisBatch(RedisDatabase wrapped, object? asyncState) : base(wrapped.multiplexer, wrapped.Database, asyncState ?? wrapped.AsyncState) { } public void Execute() { @@ -109,13 +109,13 @@ internal override Task ExecuteAsync(Message? message, ResultProcessor? return task; } - internal override T ExecuteSync(Message? message, ResultProcessor? processor, ServerEndPoint? server = null, T? defaultValue = default) where T : default => - throw new NotSupportedException("ExecuteSync cannot be used inside a batch"); + internal override T ExecuteSync(Message? message, ResultProcessor? processor, ServerEndPoint? server = null, T? defaultValue = default) where T : default + => throw new NotSupportedException("ExecuteSync cannot be used inside a batch"); private static void FailNoServer(ConnectionMultiplexer muxer, List messages) { if (messages == null) return; - foreach(var msg in messages) + foreach (var msg in messages) { msg.Fail(ConnectionFailureType.UnableToResolvePhysicalConnection, null, "unable to write batch", muxer); msg.Complete(); diff --git a/src/StackExchange.Redis/RedisChannel.cs b/src/StackExchange.Redis/RedisChannel.cs index 5e9446506..561cce21f 100644 --- a/src/StackExchange.Redis/RedisChannel.cs +++ b/src/StackExchange.Redis/RedisChannel.cs @@ -17,13 +17,12 @@ namespace StackExchange.Redis public bool IsNullOrEmpty => Value == null || Value.Length == 0; /// - /// Indicates whether this channel represents a wildcard pattern (see PSUBSCRIBE) + /// Indicates whether this channel represents a wildcard pattern (see PSUBSCRIBE). /// public bool IsPattern => _isPatternBased; internal bool IsNull => Value == null; - /// /// Indicates whether channels should use when no /// is specified; this is enabled by default, but can be disabled to avoid unexpected wildcard scenarios. @@ -36,19 +35,22 @@ public static bool UseImplicitAutoPattern private static PatternMode s_DefaultPatternMode = PatternMode.Auto; /// - /// Creates a new that does not act as a wildcard subscription + /// Creates a new that does not act as a wildcard subscription. /// public static RedisChannel Literal(string value) => new RedisChannel(value, PatternMode.Literal); + /// - /// Creates a new that does not act as a wildcard subscription + /// Creates a new that does not act as a wildcard subscription. /// public static RedisChannel Literal(byte[] value) => new RedisChannel(value, PatternMode.Literal); + /// - /// Creates a new that acts as a wildcard subscription + /// Creates a new that acts as a wildcard subscription. /// public static RedisChannel Pattern(string value) => new RedisChannel(value, PatternMode.Pattern); + /// - /// Creates a new that acts as a wildcard subscription + /// Creates a new that acts as a wildcard subscription. /// public static RedisChannel Pattern(byte[] value) => new RedisChannel(value, PatternMode.Pattern); @@ -162,7 +164,7 @@ private RedisChannel(byte[]? value, bool isPatternBased) RedisChannel rcObj => RedisValue.Equals(Value, rcObj.Value), string sObj => RedisValue.Equals(Value, Encoding.UTF8.GetBytes(sObj)), byte[] bObj => RedisValue.Equals(Value, bObj), - _ => false + _ => false, }; /// @@ -213,14 +215,16 @@ public enum PatternMode /// Will be treated as a pattern if it includes *. /// Auto = 0, + /// /// Never a pattern. /// Literal = 1, + /// /// Always a pattern. /// - Pattern = 2 + Pattern = 2, } /// diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs index 6a0210e6b..288e263d2 100644 --- a/src/StackExchange.Redis/RedisDatabase.cs +++ b/src/StackExchange.Redis/RedisDatabase.cs @@ -1776,7 +1776,7 @@ public RedisValue[] SetPop(RedisKey key, long count, CommandFlags flags = Comman public Task SetPopAsync(RedisKey key, long count, CommandFlags flags = CommandFlags.None) { - if(count == 0) return CompletedTask.FromDefault(Array.Empty(), asyncState); + if (count == 0) return CompletedTask.FromDefault(Array.Empty(), asyncState); var msg = count == 1 ? Message.Create(Database, flags, RedisCommand.SPOP, key) : Message.Create(Database, flags, RedisCommand.SPOP, key, count); @@ -1882,7 +1882,7 @@ public bool SortedSetAdd(RedisKey key, RedisValue member, double score, CommandF SortedSetAdd(key, member, score, SortedSetWhen.Always, flags); public bool SortedSetAdd(RedisKey key, RedisValue member, double score, When when = When.Always, CommandFlags flags = CommandFlags.None) => - SortedSetAdd(key, member, score, SortedSetWhenExtensions.Parse(when), flags); + SortedSetAdd(key, member, score, SortedSetWhenExtensions.Parse(when), flags); public bool SortedSetAdd(RedisKey key, RedisValue member, double score, SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None) { @@ -2331,7 +2331,8 @@ public Task StreamAcknowledgeAsync(RedisKey key, RedisValue groupName, Red public RedisValue StreamAdd(RedisKey key, RedisValue streamField, RedisValue streamValue, RedisValue? messageId = null, int? maxLength = null, bool useApproximateMaxLength = false, CommandFlags flags = CommandFlags.None) { - var msg = GetStreamAddMessage(key, + var msg = GetStreamAddMessage( + key, messageId ?? StreamConstants.AutoGeneratedId, maxLength, useApproximateMaxLength, @@ -2343,7 +2344,8 @@ public RedisValue StreamAdd(RedisKey key, RedisValue streamField, RedisValue str public Task StreamAddAsync(RedisKey key, RedisValue streamField, RedisValue streamValue, RedisValue? messageId = null, int? maxLength = null, bool useApproximateMaxLength = false, CommandFlags flags = CommandFlags.None) { - var msg = GetStreamAddMessage(key, + var msg = GetStreamAddMessage( + key, messageId ?? StreamConstants.AutoGeneratedId, maxLength, useApproximateMaxLength, @@ -2355,7 +2357,8 @@ public Task StreamAddAsync(RedisKey key, RedisValue streamField, Red public RedisValue StreamAdd(RedisKey key, NameValueEntry[] streamPairs, RedisValue? messageId = null, int? maxLength = null, bool useApproximateMaxLength = false, CommandFlags flags = CommandFlags.None) { - var msg = GetStreamAddMessage(key, + var msg = GetStreamAddMessage( + key, messageId ?? StreamConstants.AutoGeneratedId, maxLength, useApproximateMaxLength, @@ -2367,7 +2370,8 @@ public RedisValue StreamAdd(RedisKey key, NameValueEntry[] streamPairs, RedisVal public Task StreamAddAsync(RedisKey key, NameValueEntry[] streamPairs, RedisValue? messageId = null, int? maxLength = null, bool useApproximateMaxLength = false, CommandFlags flags = CommandFlags.None) { - var msg = GetStreamAddMessage(key, + var msg = GetStreamAddMessage( + key, messageId ?? StreamConstants.AutoGeneratedId, maxLength, useApproximateMaxLength, @@ -2403,7 +2407,8 @@ public Task StreamAutoClaimIdsOnlyAsync(RedisKey k public StreamEntry[] StreamClaim(RedisKey key, RedisValue consumerGroup, RedisValue claimingConsumer, long minIdleTimeInMs, RedisValue[] messageIds, CommandFlags flags = CommandFlags.None) { - var msg = GetStreamClaimMessage(key, + var msg = GetStreamClaimMessage( + key, consumerGroup, claimingConsumer, minIdleTimeInMs, @@ -2416,7 +2421,8 @@ public StreamEntry[] StreamClaim(RedisKey key, RedisValue consumerGroup, RedisVa public Task StreamClaimAsync(RedisKey key, RedisValue consumerGroup, RedisValue claimingConsumer, long minIdleTimeInMs, RedisValue[] messageIds, CommandFlags flags = CommandFlags.None) { - var msg = GetStreamClaimMessage(key, + var msg = GetStreamClaimMessage( + key, consumerGroup, claimingConsumer, minIdleTimeInMs, @@ -2429,7 +2435,8 @@ public Task StreamClaimAsync(RedisKey key, RedisValue consumerGro public RedisValue[] StreamClaimIdsOnly(RedisKey key, RedisValue consumerGroup, RedisValue claimingConsumer, long minIdleTimeInMs, RedisValue[] messageIds, CommandFlags flags = CommandFlags.None) { - var msg = GetStreamClaimMessage(key, + var msg = GetStreamClaimMessage( + key, consumerGroup, claimingConsumer, minIdleTimeInMs, @@ -2442,7 +2449,8 @@ public RedisValue[] StreamClaimIdsOnly(RedisKey key, RedisValue consumerGroup, R public Task StreamClaimIdsOnlyAsync(RedisKey key, RedisValue consumerGroup, RedisValue claimingConsumer, long minIdleTimeInMs, RedisValue[] messageIds, CommandFlags flags = CommandFlags.None) { - var msg = GetStreamClaimMessage(key, + var msg = GetStreamClaimMessage( + key, consumerGroup, claimingConsumer, minIdleTimeInMs, @@ -2455,7 +2463,8 @@ public Task StreamClaimIdsOnlyAsync(RedisKey key, RedisValue consu public bool StreamConsumerGroupSetPosition(RedisKey key, RedisValue groupName, RedisValue position, CommandFlags flags = CommandFlags.None) { - var msg = Message.Create(Database, + var msg = Message.Create( + Database, flags, RedisCommand.XGROUP, new RedisValue[] @@ -2463,7 +2472,7 @@ public bool StreamConsumerGroupSetPosition(RedisKey key, RedisValue groupName, R StreamConstants.SetId, key.AsRedisValue(), groupName, - StreamPosition.Resolve(position, RedisCommand.XGROUP) + StreamPosition.Resolve(position, RedisCommand.XGROUP), }); return ExecuteSync(msg, ResultProcessor.Boolean); @@ -2471,7 +2480,8 @@ public bool StreamConsumerGroupSetPosition(RedisKey key, RedisValue groupName, R public Task StreamConsumerGroupSetPositionAsync(RedisKey key, RedisValue groupName, RedisValue position, CommandFlags flags = CommandFlags.None) { - var msg = Message.Create(Database, + var msg = Message.Create( + Database, flags, RedisCommand.XGROUP, new RedisValue[] @@ -2479,7 +2489,7 @@ public Task StreamConsumerGroupSetPositionAsync(RedisKey key, RedisValue g StreamConstants.SetId, key.AsRedisValue(), groupName, - StreamPosition.Resolve(position, RedisCommand.XGROUP) + StreamPosition.Resolve(position, RedisCommand.XGROUP), }); return ExecuteAsync(msg, ResultProcessor.Boolean); @@ -2531,14 +2541,15 @@ public Task StreamCreateConsumerGroupAsync(RedisKey key, RedisValue groupN public StreamConsumerInfo[] StreamConsumerInfo(RedisKey key, RedisValue groupName, CommandFlags flags = CommandFlags.None) { - var msg = Message.Create(Database, + var msg = Message.Create( + Database, flags, RedisCommand.XINFO, new RedisValue[] { StreamConstants.Consumers, key.AsRedisValue(), - groupName + groupName, }); return ExecuteSync(msg, ResultProcessor.StreamConsumerInfo, defaultValue: Array.Empty()); @@ -2546,14 +2557,15 @@ public StreamConsumerInfo[] StreamConsumerInfo(RedisKey key, RedisValue groupNam public Task StreamConsumerInfoAsync(RedisKey key, RedisValue groupName, CommandFlags flags = CommandFlags.None) { - var msg = Message.Create(Database, + var msg = Message.Create( + Database, flags, RedisCommand.XINFO, new RedisValue[] { StreamConstants.Consumers, key.AsRedisValue(), - groupName + groupName, }); return ExecuteAsync(msg, ResultProcessor.StreamConsumerInfo, defaultValue: Array.Empty()); @@ -2597,7 +2609,8 @@ public Task StreamLengthAsync(RedisKey key, CommandFlags flags = CommandFl public long StreamDelete(RedisKey key, RedisValue[] messageIds, CommandFlags flags = CommandFlags.None) { - var msg = Message.Create(Database, + var msg = Message.Create( + Database, flags, RedisCommand.XDEL, key, @@ -2608,7 +2621,8 @@ public long StreamDelete(RedisKey key, RedisValue[] messageIds, CommandFlags fla public Task StreamDeleteAsync(RedisKey key, RedisValue[] messageIds, CommandFlags flags = CommandFlags.None) { - var msg = Message.Create(Database, + var msg = Message.Create( + Database, flags, RedisCommand.XDEL, key, @@ -2619,7 +2633,8 @@ public Task StreamDeleteAsync(RedisKey key, RedisValue[] messageIds, Comma public long StreamDeleteConsumer(RedisKey key, RedisValue groupName, RedisValue consumerName, CommandFlags flags = CommandFlags.None) { - var msg = Message.Create(Database, + var msg = Message.Create( + Database, flags, RedisCommand.XGROUP, new RedisValue[] @@ -2627,7 +2642,7 @@ public long StreamDeleteConsumer(RedisKey key, RedisValue groupName, RedisValue StreamConstants.DeleteConsumer, key.AsRedisValue(), groupName, - consumerName + consumerName, }); return ExecuteSync(msg, ResultProcessor.Int64); @@ -2635,7 +2650,8 @@ public long StreamDeleteConsumer(RedisKey key, RedisValue groupName, RedisValue public Task StreamDeleteConsumerAsync(RedisKey key, RedisValue groupName, RedisValue consumerName, CommandFlags flags = CommandFlags.None) { - var msg = Message.Create(Database, + var msg = Message.Create( + Database, flags, RedisCommand.XGROUP, new RedisValue[] @@ -2643,7 +2659,7 @@ public Task StreamDeleteConsumerAsync(RedisKey key, RedisValue groupName, StreamConstants.DeleteConsumer, key.AsRedisValue(), groupName, - consumerName + consumerName, }); return ExecuteAsync(msg, ResultProcessor.Int64); @@ -2651,14 +2667,15 @@ public Task StreamDeleteConsumerAsync(RedisKey key, RedisValue groupName, public bool StreamDeleteConsumerGroup(RedisKey key, RedisValue groupName, CommandFlags flags = CommandFlags.None) { - var msg = Message.Create(Database, + var msg = Message.Create( + Database, flags, RedisCommand.XGROUP, new RedisValue[] { StreamConstants.Destroy, key.AsRedisValue(), - groupName + groupName, }); return ExecuteSync(msg, ResultProcessor.Boolean); @@ -2666,14 +2683,15 @@ public bool StreamDeleteConsumerGroup(RedisKey key, RedisValue groupName, Comman public Task StreamDeleteConsumerGroupAsync(RedisKey key, RedisValue groupName, CommandFlags flags = CommandFlags.None) { - var msg = Message.Create(Database, + var msg = Message.Create( + Database, flags, RedisCommand.XGROUP, new RedisValue[] { StreamConstants.Destroy, key.AsRedisValue(), - groupName + groupName, }); return ExecuteAsync(msg, ResultProcessor.Boolean); @@ -2693,7 +2711,8 @@ public Task StreamPendingAsync(RedisKey key, RedisValue group public StreamPendingMessageInfo[] StreamPendingMessages(RedisKey key, RedisValue groupName, int count, RedisValue consumerName, RedisValue? minId = null, RedisValue? maxId = null, CommandFlags flags = CommandFlags.None) { - var msg = GetStreamPendingMessagesMessage(key, + var msg = GetStreamPendingMessagesMessage( + key, groupName, minId, maxId, @@ -2706,7 +2725,8 @@ public StreamPendingMessageInfo[] StreamPendingMessages(RedisKey key, RedisValue public Task StreamPendingMessagesAsync(RedisKey key, RedisValue groupName, int count, RedisValue consumerName, RedisValue? minId = null, RedisValue? maxId = null, CommandFlags flags = CommandFlags.None) { - var msg = GetStreamPendingMessagesMessage(key, + var msg = GetStreamPendingMessagesMessage( + key, groupName, minId, maxId, @@ -2719,7 +2739,8 @@ public Task StreamPendingMessagesAsync(RedisKey key, public StreamEntry[] StreamRange(RedisKey key, RedisValue? minId = null, RedisValue? maxId = null, int? count = null, Order messageOrder = Order.Ascending, CommandFlags flags = CommandFlags.None) { - var msg = GetStreamRangeMessage(key, + var msg = GetStreamRangeMessage( + key, minId, maxId, count, @@ -2731,7 +2752,8 @@ public StreamEntry[] StreamRange(RedisKey key, RedisValue? minId = null, RedisVa public Task StreamRangeAsync(RedisKey key, RedisValue? minId = null, RedisValue? maxId = null, int? count = null, Order messageOrder = Order.Ascending, CommandFlags flags = CommandFlags.None) { - var msg = GetStreamRangeMessage(key, + var msg = GetStreamRangeMessage( + key, minId, maxId, count, @@ -2743,7 +2765,8 @@ public Task StreamRangeAsync(RedisKey key, RedisValue? minId = nu public StreamEntry[] StreamRead(RedisKey key, RedisValue position, int? count = null, CommandFlags flags = CommandFlags.None) { - var msg = GetSingleStreamReadMessage(key, + var msg = GetSingleStreamReadMessage( + key, StreamPosition.Resolve(position, RedisCommand.XREAD), count, flags); @@ -2753,7 +2776,8 @@ public StreamEntry[] StreamRead(RedisKey key, RedisValue position, int? count = public Task StreamReadAsync(RedisKey key, RedisValue position, int? count = null, CommandFlags flags = CommandFlags.None) { - var msg = GetSingleStreamReadMessage(key, + var msg = GetSingleStreamReadMessage( + key, StreamPosition.Resolve(position, RedisCommand.XREAD), count, flags); @@ -2775,7 +2799,8 @@ public Task StreamReadAsync(StreamPosition[] streamPositions, int public StreamEntry[] StreamReadGroup(RedisKey key, RedisValue groupName, RedisValue consumerName, RedisValue? position, int? count, CommandFlags flags) { - return StreamReadGroup(key, + return StreamReadGroup( + key, groupName, consumerName, position, @@ -2788,7 +2813,8 @@ public StreamEntry[] StreamReadGroup(RedisKey key, RedisValue groupName, RedisVa { var actualPosition = position ?? StreamPosition.NewMessages; - var msg = GetStreamReadGroupMessage(key, + var msg = GetStreamReadGroupMessage( + key, groupName, consumerName, StreamPosition.Resolve(actualPosition, RedisCommand.XREADGROUP), @@ -2801,7 +2827,8 @@ public StreamEntry[] StreamReadGroup(RedisKey key, RedisValue groupName, RedisVa public Task StreamReadGroupAsync(RedisKey key, RedisValue groupName, RedisValue consumerName, RedisValue? position, int? count, CommandFlags flags) { - return StreamReadGroupAsync(key, + return StreamReadGroupAsync( + key, groupName, consumerName, position, @@ -2814,7 +2841,8 @@ public Task StreamReadGroupAsync(RedisKey key, RedisValue groupNa { var actualPosition = position ?? StreamPosition.NewMessages; - var msg = GetStreamReadGroupMessage(key, + var msg = GetStreamReadGroupMessage( + key, groupName, consumerName, StreamPosition.Resolve(actualPosition, RedisCommand.XREADGROUP), @@ -2827,7 +2855,8 @@ public Task StreamReadGroupAsync(RedisKey key, RedisValue groupNa public RedisStream[] StreamReadGroup(StreamPosition[] streamPositions, RedisValue groupName, RedisValue consumerName, int? countPerStream, CommandFlags flags) { - return StreamReadGroup(streamPositions, + return StreamReadGroup( + streamPositions, groupName, consumerName, countPerStream, @@ -2837,7 +2866,8 @@ public RedisStream[] StreamReadGroup(StreamPosition[] streamPositions, RedisValu public RedisStream[] StreamReadGroup(StreamPosition[] streamPositions, RedisValue groupName, RedisValue consumerName, int? countPerStream = null, bool noAck = false, CommandFlags flags = CommandFlags.None) { - var msg = GetMultiStreamReadGroupMessage(streamPositions, + var msg = GetMultiStreamReadGroupMessage( + streamPositions, groupName, consumerName, countPerStream, @@ -2849,7 +2879,8 @@ public RedisStream[] StreamReadGroup(StreamPosition[] streamPositions, RedisValu public Task StreamReadGroupAsync(StreamPosition[] streamPositions, RedisValue groupName, RedisValue consumerName, int? countPerStream, CommandFlags flags) { - return StreamReadGroupAsync(streamPositions, + return StreamReadGroupAsync( + streamPositions, groupName, consumerName, countPerStream, @@ -2859,7 +2890,8 @@ public Task StreamReadGroupAsync(StreamPosition[] streamPositions public Task StreamReadGroupAsync(StreamPosition[] streamPositions, RedisValue groupName, RedisValue consumerName, int? countPerStream = null, bool noAck = false, CommandFlags flags = CommandFlags.None) { - var msg = GetMultiStreamReadGroupMessage(streamPositions, + var msg = GetMultiStreamReadGroupMessage( + streamPositions, groupName, consumerName, countPerStream, @@ -3274,9 +3306,9 @@ private Message GetCopyMessage(in RedisKey sourceKey, RedisKey destinationKey, i { < -1 => throw new ArgumentOutOfRangeException(nameof(destinationDatabase)), -1 when replace => Message.Create(Database, flags, RedisCommand.COPY, sourceKey, destinationKey, RedisLiterals.REPLACE), - -1 => Message.Create(Database, flags, RedisCommand.COPY, sourceKey, destinationKey), - _ when replace => Message.Create(Database, flags, RedisCommand.COPY, sourceKey, destinationKey, RedisLiterals.DB, destinationDatabase, RedisLiterals.REPLACE), - _ => Message.Create(Database, flags, RedisCommand.COPY, sourceKey, destinationKey, RedisLiterals.DB, destinationDatabase), + -1 => Message.Create(Database, flags, RedisCommand.COPY, sourceKey, destinationKey), + _ when replace => Message.Create(Database, flags, RedisCommand.COPY, sourceKey, destinationKey, RedisLiterals.DB, destinationDatabase, RedisLiterals.REPLACE), + _ => Message.Create(Database, flags, RedisCommand.COPY, sourceKey, destinationKey, RedisLiterals.DB, destinationDatabase), }; private Message GetExpiryMessage(in RedisKey key, CommandFlags flags, TimeSpan? expiry, ExpireWhen when, out ServerEndPoint? server) @@ -3287,7 +3319,7 @@ private Message GetExpiryMessage(in RedisKey key, CommandFlags flags, TimeSpan? return when switch { ExpireWhen.Always => Message.Create(Database, flags, RedisCommand.PERSIST, key), - _ => throw new ArgumentException("PERSIST cannot be used with when.") + _ => throw new ArgumentException("PERSIST cannot be used with when."), }; } @@ -3303,7 +3335,7 @@ private Message GetExpiryMessage(in RedisKey key, CommandFlags flags, DateTime? return when switch { ExpireWhen.Always => Message.Create(Database, flags, RedisCommand.PERSIST, key), - _ => throw new ArgumentException("PERSIST cannot be used with when.") + _ => throw new ArgumentException("PERSIST cannot be used with when."), }; } @@ -3311,7 +3343,8 @@ private Message GetExpiryMessage(in RedisKey key, CommandFlags flags, DateTime? return GetExpiryMessage(key, RedisCommand.PEXPIREAT, RedisCommand.EXPIREAT, milliseconds, when, flags, out server); } - private Message GetExpiryMessage(in RedisKey key, + private Message GetExpiryMessage( + in RedisKey key, RedisCommand millisecondsCommand, RedisCommand secondsCommand, long milliseconds, @@ -3328,7 +3361,7 @@ private Message GetExpiryMessage(in RedisKey key, return when switch { ExpireWhen.Always => Message.Create(Database, flags, millisecondsCommand, key, milliseconds), - _ => Message.Create(Database, flags, millisecondsCommand, key, milliseconds, when.ToLiteral()) + _ => Message.Create(Database, flags, millisecondsCommand, key, milliseconds, when.ToLiteral()), }; } server = null; @@ -3338,7 +3371,7 @@ private Message GetExpiryMessage(in RedisKey key, return when switch { ExpireWhen.Always => Message.Create(Database, flags, secondsCommand, key, seconds), - _ => Message.Create(Database, flags, secondsCommand, key, seconds, when.ToLiteral()) + _ => Message.Create(Database, flags, secondsCommand, key, seconds, when.ToLiteral()), }; } @@ -3405,12 +3438,23 @@ private Message GetSortedSetMultiPopMessage(RedisKey[] keys, Order order, long c { case 0: return null; case 1: - return Message.Create(Database, flags, RedisCommand.HMSET, key, - hashFields[0].name, hashFields[0].value); + return Message.Create( + Database, + flags, + RedisCommand.HMSET, + key, + hashFields[0].name, + hashFields[0].value); case 2: - return Message.Create(Database, flags, RedisCommand.HMSET, key, - hashFields[0].name, hashFields[0].value, - hashFields[1].name, hashFields[1].value); + return Message.Create( + Database, + flags, + RedisCommand.HMSET, + key, + hashFields[0].name, + hashFields[0].value, + hashFields[1].name, + hashFields[1].value); default: var arr = new RedisValue[hashFields.Length * 2]; int offset = 0; @@ -3461,7 +3505,8 @@ private static RedisValue GetLexRange(RedisValue value, Exclude exclude, bool is } private Message GetMultiStreamReadGroupMessage(StreamPosition[] streamPositions, RedisValue groupName, RedisValue consumerName, int? countPerStream, bool noAck, CommandFlags flags) => - new MultiStreamReadGroupCommandMessage(Database, + new MultiStreamReadGroupCommandMessage( + Database, flags, streamPositions, groupName, @@ -3502,11 +3547,10 @@ public MultiStreamReadGroupCommandMessage(int db, CommandFlags flags, StreamPosi this.countPerStream = countPerStream; this.noAck = noAck; - argCount = 4 // Room for GROUP groupName consumerName & STREAMS - + (streamPositions.Length * 2) // Enough room for the stream keys and associated IDs. - + (countPerStream.HasValue ? 2 : 0) // Room for "COUNT num" or 0 if countPerStream is null. - + (noAck ? 1 : 0); // Allow for the NOACK subcommand. - + argCount = 4 // Room for GROUP groupName consumerName & STREAMS + + (streamPositions.Length * 2) // Enough room for the stream keys and associated IDs. + + (countPerStream.HasValue ? 2 : 0) // Room for "COUNT num" or 0 if countPerStream is null. + + (noAck ? 1 : 0); // Allow for the NOACK subcommand. } public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy) @@ -3578,9 +3622,9 @@ public MultiStreamReadCommandMessage(int db, CommandFlags flags, StreamPosition[ this.streamPositions = streamPositions; this.countPerStream = countPerStream; - argCount = 1 // Streams keyword. - + (countPerStream.HasValue ? 2 : 0) // Room for "COUNT num" or 0 if countPerStream is null. - + (streamPositions.Length * 2); // Room for the stream names and the ID after which to begin reading. + argCount = 1 // Streams keyword. + + (countPerStream.HasValue ? 2 : 0) // Room for "COUNT num" or 0 if countPerStream is null. + + (streamPositions.Length * 2); // Room for the stream names and the ID after which to begin reading. } public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy) @@ -3658,21 +3702,26 @@ private Message GetSetIntersectionLengthMessage(RedisKey[] keys, long limit = 0, private Message GetSortedSetAddMessage(RedisKey key, RedisValue member, double score, SortedSetWhen when, bool change, CommandFlags flags) { - RedisValue[] arr = new RedisValue[2 + when.CountBits() + (change? 1:0)]; + RedisValue[] arr = new RedisValue[2 + when.CountBits() + (change ? 1 : 0)]; int index = 0; - if ((when & SortedSetWhen.NotExists) != 0) { + if ((when & SortedSetWhen.NotExists) != 0) + { arr[index++] = RedisLiterals.NX; } - if ((when & SortedSetWhen.Exists) != 0) { + if ((when & SortedSetWhen.Exists) != 0) + { arr[index++] = RedisLiterals.XX; } - if ((when & SortedSetWhen.GreaterThan) != 0) { + if ((when & SortedSetWhen.GreaterThan) != 0) + { arr[index++] = RedisLiterals.GT; } - if ((when & SortedSetWhen.LessThan) != 0) { + if ((when & SortedSetWhen.LessThan) != 0) + { arr[index++] = RedisLiterals.LT; } - if (change) { + if (change) + { arr[index++] = RedisLiterals.CH; } arr[index++] = score; @@ -3689,21 +3738,26 @@ private Message GetSortedSetAddMessage(RedisKey key, RedisValue member, double s case 1: return GetSortedSetAddMessage(key, values[0].element, values[0].score, when, change, flags); default: - RedisValue[] arr = new RedisValue[(values.Length * 2) + when.CountBits() + (change? 1:0)]; + RedisValue[] arr = new RedisValue[(values.Length * 2) + when.CountBits() + (change ? 1 : 0)]; int index = 0; - if ((when & SortedSetWhen.NotExists) != 0) { + if ((when & SortedSetWhen.NotExists) != 0) + { arr[index++] = RedisLiterals.NX; } - if ((when & SortedSetWhen.Exists) != 0) { + if ((when & SortedSetWhen.Exists) != 0) + { arr[index++] = RedisLiterals.XX; } - if ((when & SortedSetWhen.GreaterThan) != 0) { + if ((when & SortedSetWhen.GreaterThan) != 0) + { arr[index++] = RedisLiterals.GT; } - if ((when & SortedSetWhen.LessThan) != 0) { + if ((when & SortedSetWhen.LessThan) != 0) + { arr[index++] = RedisLiterals.LT; } - if (change) { + if (change) + { arr[index++] = RedisLiterals.CH; } @@ -3723,21 +3777,20 @@ private Message GetSortMessage(RedisKey destination, RedisKey key, long skip, lo ? RedisCommand.SORT_RO : RedisCommand.SORT; - //if SORT_RO is not available, we cannot issue the command to a read-only replica + // If SORT_RO is not available, we cannot issue the command to a read-only replica if (command == RedisCommand.SORT) { server = null; } - // most common cases; no "get", no "by", no "destination", no "skip", no "take" if (destination.IsNull && skip == 0 && take == -1 && by.IsNull && (get == null || get.Length == 0)) { return order switch { - Order.Ascending when sortType == SortType.Numeric => Message.Create(Database, flags, command, key), - Order.Ascending when sortType == SortType.Alphabetic => Message.Create(Database, flags, command, key, RedisLiterals.ALPHA), - Order.Descending when sortType == SortType.Numeric => Message.Create(Database, flags, command, key, RedisLiterals.DESC), + Order.Ascending when sortType == SortType.Numeric => Message.Create(Database, flags, command, key), + Order.Ascending when sortType == SortType.Alphabetic => Message.Create(Database, flags, command, key, RedisLiterals.ALPHA), + Order.Descending when sortType == SortType.Numeric => Message.Create(Database, flags, command, key, RedisLiterals.DESC), Order.Descending when sortType == SortType.Alphabetic => Message.Create(Database, flags, command, key, RedisLiterals.DESC, RedisLiterals.ALPHA), Order.Ascending or Order.Descending => throw new ArgumentOutOfRangeException(nameof(sortType)), _ => throw new ArgumentOutOfRangeException(nameof(order)), @@ -3751,7 +3804,8 @@ private Message GetSortMessage(RedisKey destination, RedisKey key, long skip, lo values.Add(RedisLiterals.BY); values.Add(by); } - if (skip != 0 || take != -1)// these are our defaults that mean "everything"; anything else needs to be sent explicitly + // these are our defaults that mean "everything"; anything else needs to be sent explicitly + if (skip != 0 || take != -1) { values.Add(RedisLiterals.LIMIT); values.Add(skip); @@ -3950,8 +4004,13 @@ private Message GetSortedSetRangeByScoreMessage(RedisKey key, double start, doub private Message GetSortedSetRemoveRangeByScoreMessage(RedisKey key, double start, double stop, Exclude exclude, CommandFlags flags) { - return Message.Create(Database, flags, RedisCommand.ZREMRANGEBYSCORE, key, - GetRange(start, exclude, true), GetRange(stop, exclude, false)); + return Message.Create( + Database, + flags, + RedisCommand.ZREMRANGEBYSCORE, + key, + GetRange(start, exclude, true), + GetRange(stop, exclude, false)); } private Message GetStreamAcknowledgeMessage(RedisKey key, RedisValue groupName, RedisValue messageId, CommandFlags flags) @@ -3959,7 +4018,7 @@ private Message GetStreamAcknowledgeMessage(RedisKey key, RedisValue groupName, var values = new RedisValue[] { groupName, - messageId + messageId, }; return Message.Create(Database, flags, RedisCommand.XACK, key, values); @@ -4035,9 +4094,9 @@ private Message GetStreamAddMessage(RedisKey key, RedisValue entryId, int? maxLe var includeMaxLen = maxLength.HasValue ? 2 : 0; var includeApproxLen = maxLength.HasValue && useApproximateMaxLength ? 1 : 0; - var totalLength = (streamPairs.Length * 2) // Room for the name/value pairs - + 1 // The stream entry ID - + includeMaxLen // 2 or 0 (MAXLEN keyword & the count) + var totalLength = (streamPairs.Length * 2) // Room for the name/value pairs + + 1 // The stream entry ID + + includeMaxLen // 2 or 0 (MAXLEN keyword & the count) + includeApproxLen; // 1 or 0 var values = new RedisValue[totalLength]; @@ -4136,14 +4195,15 @@ private Message GetStreamCreateConsumerGroupMessage(RedisKey key, RedisValue gro values[4] = StreamConstants.MkStream; } - return Message.Create(Database, + return Message.Create( + Database, flags, RedisCommand.XGROUP, values); } /// - /// Gets a message for + /// Gets a message for . /// /// private Message GetStreamPendingMessagesMessage(RedisKey key, RedisValue groupName, RedisValue? minId, RedisValue? maxId, int count, RedisValue consumerName, CommandFlags flags) @@ -4157,7 +4217,6 @@ private Message GetStreamPendingMessagesMessage(RedisKey key, RedisValue groupNa // 2) "Bob" // 3) (integer)74170458 // 4) (integer)1 - if (count <= 0) { throw new ArgumentOutOfRangeException(nameof(count), "count must be greater than 0."); @@ -4175,7 +4234,8 @@ private Message GetStreamPendingMessagesMessage(RedisKey key, RedisValue groupNa values[4] = consumerName; } - return Message.Create(Database, + return Message.Create( + Database, flags, RedisCommand.XPENDING, key, @@ -4194,8 +4254,8 @@ private Message GetStreamRangeMessage(RedisKey key, RedisValue? minId, RedisValu var values = new RedisValue[2 + (count.HasValue ? 2 : 0)]; - values[0] = (messageOrder == Order.Ascending ? actualMin : actualMax); - values[1] = (messageOrder == Order.Ascending ? actualMax : actualMin); + values[0] = messageOrder == Order.Ascending ? actualMin : actualMax; + values[1] = messageOrder == Order.Ascending ? actualMax : actualMin; if (count.HasValue) { @@ -4203,7 +4263,8 @@ private Message GetStreamRangeMessage(RedisKey key, RedisValue? minId, RedisValu values[3] = count.Value; } - return Message.Create(Database, + return Message.Create( + Database, flags, messageOrder == Order.Ascending ? RedisCommand.XRANGE : RedisCommand.XREVRANGE, key, @@ -4242,7 +4303,8 @@ public SingleStreamReadGroupCommandMessage(int db, CommandFlags flags, RedisKey argCount = 6 + (count.HasValue ? 2 : 0) + (noAck ? 1 : 0); } - protected override void WriteImpl(PhysicalConnection physical) { + protected override void WriteImpl(PhysicalConnection physical) + { physical.WriteHeader(Command, argCount); physical.WriteBulkString(StreamConstants.Group); physical.WriteBulkString(groupName); @@ -4309,7 +4371,6 @@ protected override void WriteImpl(PhysicalConnection physical) public override int ArgCount => argCount; } - private Message GetStreamTrimMessage(RedisKey key, int maxLength, bool useApproximateMaxLength, CommandFlags flags) { if (maxLength < 0) @@ -4331,7 +4392,8 @@ private Message GetStreamTrimMessage(RedisKey key, int maxLength, bool useApprox values[1] = maxLength; } - return Message.Create(Database, + return Message.Create( + Database, flags, RedisCommand.XTRIM, key, @@ -4365,7 +4427,8 @@ private Message GetStringBitOperationMessage(Bitwise operation, RedisKey destina int slot = serverSelectionStrategy.HashSlot(destination); slot = serverSelectionStrategy.CombineSlot(slot, first); if (second.IsNull || operation == Bitwise.Not) - { // unary + { + // unary return Message.CreateInSlot(Database, slot, flags, RedisCommand.BITOP, new[] { op, destination.AsRedisValue(), first.AsRedisValue() }); } // binary @@ -4376,7 +4439,7 @@ private Message GetStringBitOperationMessage(Bitwise operation, RedisKey destina private Message GetStringGetExMessage(in RedisKey key, TimeSpan? expiry, CommandFlags flags = CommandFlags.None) => expiry switch { null => Message.Create(Database, flags, RedisCommand.GETEX, key, RedisLiterals.PERSIST), - _ => Message.Create(Database, flags, RedisCommand.GETEX, key, RedisLiterals.PX, (long)expiry.Value.TotalMilliseconds) + _ => Message.Create(Database, flags, RedisCommand.GETEX, key, RedisLiterals.PX, (long)expiry.Value.TotalMilliseconds), }; private Message GetStringGetExMessage(in RedisKey key, DateTime expiry, CommandFlags flags = CommandFlags.None) => expiry == DateTime.MaxValue @@ -4438,12 +4501,12 @@ private Message GetStringSetMessage( // no expiry return when switch { - When.Always when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value), - When.Always when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.KEEPTTL), + When.Always when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value), + When.Always when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.KEEPTTL), When.NotExists when !keepTtl => Message.Create(Database, flags, RedisCommand.SETNX, key, value), - When.NotExists when keepTtl => Message.Create(Database, flags, RedisCommand.SETNX, key, value, RedisLiterals.KEEPTTL), - When.Exists when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX), - When.Exists when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX, RedisLiterals.KEEPTTL), + When.NotExists when keepTtl => Message.Create(Database, flags, RedisCommand.SETNX, key, value, RedisLiterals.KEEPTTL), + When.Exists when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX), + When.Exists when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX, RedisLiterals.KEEPTTL), _ => throw new ArgumentOutOfRangeException(nameof(when)), }; } @@ -4455,8 +4518,8 @@ private Message GetStringSetMessage( long seconds = milliseconds / 1000; return when switch { - When.Always => Message.Create(Database, flags, RedisCommand.SETEX, key, seconds, value), - When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.XX), + When.Always => Message.Create(Database, flags, RedisCommand.SETEX, key, seconds, value), + When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.XX), When.NotExists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.NX), _ => throw new ArgumentOutOfRangeException(nameof(when)), }; @@ -4464,8 +4527,8 @@ private Message GetStringSetMessage( return when switch { - When.Always => Message.Create(Database, flags, RedisCommand.PSETEX, key, milliseconds, value), - When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.XX), + When.Always => Message.Create(Database, flags, RedisCommand.PSETEX, key, milliseconds, value), + When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.XX), When.NotExists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.NX), _ => throw new ArgumentOutOfRangeException(nameof(when)), }; @@ -4487,12 +4550,12 @@ private Message GetStringSetAndGetMessage( // no expiry return when switch { - When.Always when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.GET), - When.Always when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.GET, RedisLiterals.KEEPTTL), - When.Exists when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX, RedisLiterals.GET), - When.Exists when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX, RedisLiterals.GET, RedisLiterals.KEEPTTL), + When.Always when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.GET), + When.Always when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.GET, RedisLiterals.KEEPTTL), + When.Exists when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX, RedisLiterals.GET), + When.Exists when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX, RedisLiterals.GET, RedisLiterals.KEEPTTL), When.NotExists when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.NX, RedisLiterals.GET), - When.NotExists when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.NX, RedisLiterals.GET, RedisLiterals.KEEPTTL), + When.NotExists when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.NX, RedisLiterals.GET, RedisLiterals.KEEPTTL), _ => throw new ArgumentOutOfRangeException(nameof(when)), }; } @@ -4504,8 +4567,8 @@ private Message GetStringSetAndGetMessage( long seconds = milliseconds / 1000; return when switch { - When.Always => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.GET), - When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.XX, RedisLiterals.GET), + When.Always => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.GET), + When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.XX, RedisLiterals.GET), When.NotExists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.NX, RedisLiterals.GET), _ => throw new ArgumentOutOfRangeException(nameof(when)), }; @@ -4513,8 +4576,8 @@ private Message GetStringSetAndGetMessage( return when switch { - When.Always => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.GET), - When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.XX, RedisLiterals.GET), + When.Always => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.GET), + When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.XX, RedisLiterals.GET), When.NotExists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.NX, RedisLiterals.GET), _ => throw new ArgumentOutOfRangeException(nameof(when)), }; @@ -4525,10 +4588,10 @@ private Message GetStringSetAndGetMessage( 0 => ((flags & CommandFlags.FireAndForget) != 0) ? null : Message.Create(Database, flags, RedisCommand.INCRBY, key, value), - 1 => Message.Create(Database, flags, RedisCommand.INCR, key), - -1 => Message.Create(Database, flags, RedisCommand.DECR, key), + 1 => Message.Create(Database, flags, RedisCommand.INCR, key), + -1 => Message.Create(Database, flags, RedisCommand.DECR, key), > 0 => Message.Create(Database, flags, RedisCommand.INCRBY, key, value), - _ => Message.Create(Database, flags, RedisCommand.DECRBY, key, -value), + _ => Message.Create(Database, flags, RedisCommand.DECRBY, key, -value), }; private static RedisCommand SetOperationCommand(SetOperation operation, bool store) => operation switch @@ -4587,8 +4650,15 @@ private static void ReverseLimits(Order order, ref Exclude exclude, ref RedisVal } } } - public RedisValue[] SortedSetRangeByValue(RedisKey key, RedisValue min = default, RedisValue max = default, - Exclude exclude = Exclude.None, Order order = Order.Ascending, long skip = 0, long take = -1, CommandFlags flags = CommandFlags.None) + public RedisValue[] SortedSetRangeByValue( + RedisKey key, + RedisValue min = default, + RedisValue max = default, + Exclude exclude = Exclude.None, + Order order = Order.Ascending, + long skip = 0, + long take = -1, + CommandFlags flags = CommandFlags.None) { ReverseLimits(order, ref exclude, ref min, ref max); var msg = GetLexMessage(order == Order.Ascending ? RedisCommand.ZRANGEBYLEX : RedisCommand.ZREVRANGEBYLEX, key, min, max, exclude, skip, take, flags); @@ -4610,8 +4680,15 @@ public Task SortedSetLengthByValueAsync(RedisKey key, RedisValue min, Redi public Task SortedSetRangeByValueAsync(RedisKey key, RedisValue min, RedisValue max, Exclude exclude, long skip, long take, CommandFlags flags) => SortedSetRangeByValueAsync(key, min, max, exclude, Order.Ascending, skip, take, flags); - public Task SortedSetRangeByValueAsync(RedisKey key, RedisValue min = default, RedisValue max = default, - Exclude exclude = Exclude.None, Order order = Order.Ascending, long skip = 0, long take = -1, CommandFlags flags = CommandFlags.None) + public Task SortedSetRangeByValueAsync( + RedisKey key, + RedisValue min = default, + RedisValue max = default, + Exclude exclude = Exclude.None, + Order order = Order.Ascending, + long skip = 0, + long take = -1, + CommandFlags flags = CommandFlags.None) { ReverseLimits(order, ref exclude, ref min, ref max); var msg = GetLexMessage(order == Order.Ascending ? RedisCommand.ZRANGEBYLEX : RedisCommand.ZREVRANGEBYLEX, key, min, max, exclude, skip, take, flags); @@ -4630,8 +4707,17 @@ internal class ScanEnumerable : CursorEnumerable private readonly RedisValue pattern; private readonly RedisCommand command; - public ScanEnumerable(RedisDatabase database, ServerEndPoint? server, RedisKey key, in RedisValue pattern, int pageSize, in RedisValue cursor, int pageOffset, CommandFlags flags, - RedisCommand command, ResultProcessor processor) + public ScanEnumerable( + RedisDatabase database, + ServerEndPoint? server, + RedisKey key, + in RedisValue pattern, + int pageSize, + in RedisValue cursor, + int pageOffset, + CommandFlags flags, + RedisCommand command, + ResultProcessor processor) : base(database, server, database.Database, pageSize, cursor, pageOffset, flags) { this.key = key; @@ -4752,7 +4838,7 @@ protected override void WriteImpl(PhysicalConnection physical) physical.Write(channel); } else - { // recognises well-known types + { // recognises well-known types var val = RedisValue.TryParse(arg, out var valid); if (!valid) throw new InvalidCastException($"Unable to parse value: '{arg}'"); physical.WriteBulkString(val); @@ -4922,7 +5008,7 @@ private static Message CreateSortedSetRangeStoreMessage( { Order.Ascending => Message.Create(db, flags, RedisCommand.ZRANGESTORE, destinationKey, sourceKey, start, stop), Order.Descending => Message.Create(db, flags, RedisCommand.ZRANGESTORE, destinationKey, sourceKey, start, stop, RedisLiterals.REV), - _ => throw new ArgumentOutOfRangeException(nameof(order)) + _ => throw new ArgumentOutOfRangeException(nameof(order)), }; } @@ -4930,14 +5016,14 @@ private static Message CreateSortedSetRangeStoreMessage( { Exclude.Both or Exclude.Start => $"({start}", _ when sortedSetOrder == SortedSetOrder.ByLex => $"[{start}", - _ => start + _ => start, }; RedisValue formattedStop = exclude switch { Exclude.Both or Exclude.Stop => $"({stop}", _ when sortedSetOrder == SortedSetOrder.ByLex => $"[{stop}", - _ => stop + _ => stop, }; return order switch @@ -4950,7 +5036,7 @@ private static Message CreateSortedSetRangeStoreMessage( Message.Create(db, flags, RedisCommand.ZRANGESTORE, destinationKey, sourceKey, formattedStart, formattedStop, sortedSetOrder.GetLiteral(), RedisLiterals.REV, RedisLiterals.LIMIT, skip, take), Order.Descending => Message.Create(db, flags, RedisCommand.ZRANGESTORE, destinationKey, sourceKey, formattedStart, formattedStop, sortedSetOrder.GetLiteral(), RedisLiterals.REV), - _ => throw new ArgumentOutOfRangeException(nameof(order)) + _ => throw new ArgumentOutOfRangeException(nameof(order)), }; } diff --git a/src/StackExchange.Redis/RedisErrorEventArgs.cs b/src/StackExchange.Redis/RedisErrorEventArgs.cs index bfe114a7c..2213baf1c 100644 --- a/src/StackExchange.Redis/RedisErrorEventArgs.cs +++ b/src/StackExchange.Redis/RedisErrorEventArgs.cs @@ -12,8 +12,10 @@ public class RedisErrorEventArgs : EventArgs, ICompletable private readonly EventHandler? handler; private readonly object sender; internal RedisErrorEventArgs( - EventHandler? handler, object sender, - EndPoint endpoint, string message) + EventHandler? handler, + object sender, + EndPoint endpoint, + string message) { this.handler = handler; this.sender = sender; @@ -28,7 +30,7 @@ internal RedisErrorEventArgs( /// Redis endpoint. /// Error message. public RedisErrorEventArgs(object sender, EndPoint endpoint, string message) - : this (null, sender, endpoint, message) + : this(null, sender, endpoint, message) { } diff --git a/src/StackExchange.Redis/RedisFeatures.cs b/src/StackExchange.Redis/RedisFeatures.cs index 19c5233e1..e81043010 100644 --- a/src/StackExchange.Redis/RedisFeatures.cs +++ b/src/StackExchange.Redis/RedisFeatures.cs @@ -11,6 +11,8 @@ namespace StackExchange.Redis /// public readonly struct RedisFeatures : IEquatable { +#pragma warning disable SA1310 // Field names should not contain underscore +#pragma warning disable SA1311 // Static readonly fields should begin with upper-case letter internal static readonly Version v2_0_0 = new Version(2, 0, 0), v2_1_0 = new Version(2, 1, 0), v2_1_1 = new Version(2, 1, 1), @@ -42,6 +44,8 @@ namespace StackExchange.Redis v7_0_0_rc1 = new Version(6, 9, 240), // 7.0 RC1 is version 6.9.240 v7_2_0_rc1 = new Version(7, 1, 240), // 7.2 RC1 is version 7.1.240 v7_4_0_rc1 = new Version(7, 3, 240); // 7.4 RC1 is version 7.3.240 +#pragma warning restore SA1310 // Field names should not contain underscore +#pragma warning restore SA1311 // Static readonly fields should begin with upper-case letter private readonly Version version; @@ -54,6 +58,8 @@ public RedisFeatures(Version version) this.version = version ?? throw new ArgumentNullException(nameof(version)); } +#pragma warning disable SA1629 // Documentation should end with a period + /// /// Are BITOP and BITCOUNT available? /// @@ -264,14 +270,15 @@ public RedisFeatures(Version version) /// public bool PushMultiple => Version.IsAtLeast(v4_0_0); - /// /// Is the RESP3 protocol available? /// public bool Resp3 => Version.IsAtLeast(v6_0_0); +#pragma warning restore 1629 // Documentation text should end with a period. + /// - /// The Redis version of the server + /// The Redis version of the server. /// public Version Version => version ?? v2_0_0; @@ -339,7 +346,6 @@ internal static class VersionExtensions { // normalize two version parts and smash them together into a long; if either part is -ve, // zero is used instead; this gives us consistent ordering following "long" rules - private static long ComposeMajorMinor(Version version) // always specified => (((long)version.Major) << 32) | (long)version.Minor; diff --git a/src/StackExchange.Redis/RedisKey.cs b/src/StackExchange.Redis/RedisKey.cs index 28378d116..9bfc041b1 100644 --- a/src/StackExchange.Redis/RedisKey.cs +++ b/src/StackExchange.Redis/RedisKey.cs @@ -7,7 +7,7 @@ namespace StackExchange.Redis { /// - /// Represents a key that can be stored in redis + /// Represents a key that can be stored in redis. /// public readonly struct RedisKey : IEquatable { @@ -239,6 +239,7 @@ public static implicit operator RedisKey(string? key) if (key == null) return default; return new RedisKey(null, key); } + /// /// Create a from a . /// @@ -253,7 +254,7 @@ public static implicit operator RedisKey(byte[]? key) /// Obtain the as a . /// /// The key to get a byte array for. - public static implicit operator byte[]? (RedisKey key) + public static implicit operator byte[]?(RedisKey key) { if (key.IsNull) return null; if (key.TryGetSimpleBuffer(out var arr)) return arr; @@ -270,7 +271,7 @@ public static implicit operator RedisKey(byte[]? key) /// Obtain the key as a . /// /// The key to get a string for. - public static implicit operator string? (RedisKey key) + public static implicit operator string?(RedisKey key) { if (key.KeyPrefix is null) { @@ -413,9 +414,11 @@ internal int CopyTo(Span destination) unsafe { fixed (byte* bPtr = destination) - fixed (char* cPtr = s) { - written += Encoding.UTF8.GetBytes(cPtr, s.Length, bPtr, destination.Length); + fixed (char* cPtr = s) + { + written += Encoding.UTF8.GetBytes(cPtr, s.Length, bPtr, destination.Length); + } } } #endif diff --git a/src/StackExchange.Redis/RedisLiterals.cs b/src/StackExchange.Redis/RedisLiterals.cs index 11d2ba016..b77649402 100644 --- a/src/StackExchange.Redis/RedisLiterals.cs +++ b/src/StackExchange.Redis/RedisLiterals.cs @@ -2,6 +2,8 @@ namespace StackExchange.Redis { +#pragma warning disable SA1310 // Field names should not contain underscore +#pragma warning disable SA1311 // Static readonly fields should begin with upper-case letter internal static class CommonReplies { public static readonly CommandBytes @@ -153,14 +155,14 @@ public static readonly RedisValue REPLICAS = "REPLICAS", SLAVES = "SLAVES", GETMASTERADDRBYNAME = "GET-MASTER-ADDR-BY-NAME", - // RESET = "RESET", + // RESET = "RESET", FAILOVER = "FAILOVER", SENTINELS = "SENTINELS", // Sentinel Literals as of 2.8.4 MONITOR = "MONITOR", REMOVE = "REMOVE", - // SET = "SET", + // SET = "SET", // replication states connect = "connect", @@ -215,4 +217,6 @@ public static readonly RedisValue _ => throw new ArgumentOutOfRangeException(nameof(operation)), }; } +#pragma warning restore SA1310 // Field names should not contain underscore +#pragma warning restore SA1311 // Static readonly fields should begin with upper-case letter } diff --git a/src/StackExchange.Redis/RedisProtocol.cs b/src/StackExchange.Redis/RedisProtocol.cs index 8c1c9b869..077671bd6 100644 --- a/src/StackExchange.Redis/RedisProtocol.cs +++ b/src/StackExchange.Redis/RedisProtocol.cs @@ -11,11 +11,12 @@ public enum RedisProtocol // "hey, we've added RESP 3.1; oops, we've added RESP 3.1.1" /// - /// The protocol used by all redis server versions since 1.2, as defined by https://github.com/redis/redis-specifications/blob/master/protocol/RESP2.md + /// The protocol used by all redis server versions since 1.2, as defined by https://github.com/redis/redis-specifications/blob/master/protocol/RESP2.md. /// Resp2 = 2_00_00, // major__minor__revision + /// - /// Opt-in variant introduced in server version 6, as defined by https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md + /// Opt-in variant introduced in server version 6, as defined by https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md. /// Resp3 = 3_00_00, // major__minor__revision } diff --git a/src/StackExchange.Redis/RedisResult.cs b/src/StackExchange.Redis/RedisResult.cs index bf094f8af..4a1644c36 100644 --- a/src/StackExchange.Redis/RedisResult.cs +++ b/src/StackExchange.Redis/RedisResult.cs @@ -23,9 +23,9 @@ public RedisResult() : this(default) { } /// Create a new RedisResult representing a single value. /// /// The to create a result from. - /// The type of result being represented + /// The type of result being represented. /// new . - [SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads", Justification = "")] + [SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads", Justification = "Legacy compat.")] public static RedisResult Create(RedisValue value, ResultType? resultType = null) => new SingleRedisResult(value, resultType); /// @@ -95,10 +95,10 @@ public static RedisResult Create(RedisResult[] values, ResultType resultType) public sealed override string ToString() => ToString(out _) ?? ""; /// - /// Gets the string content as per , but also obtains the declared type from verbatim strings (for example LATENCY DOCTOR) + /// Gets the string content as per , but also obtains the declared type from verbatim strings (for example LATENCY DOCTOR). /// /// The type of the returned string. - /// The content + /// The content. public abstract string? ToString(out string? type); /// @@ -189,119 +189,142 @@ internal static bool TryCreate(PhysicalConnection? connection, in RawResult resu /// /// The result to convert to a . public static explicit operator string?(RedisResult? result) => result?.AsString(); + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator byte[]?(RedisResult? result) => result?.AsByteArray(); + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator double(RedisResult result) => result.AsDouble(); + /// /// Interprets the result as an . /// /// The result to convert to a . public static explicit operator long(RedisResult result) => result.AsInt64(); + /// /// Interprets the result as an . /// /// The result to convert to a . [CLSCompliant(false)] public static explicit operator ulong(RedisResult result) => result.AsUInt64(); + /// /// Interprets the result as an . /// /// The result to convert to a . public static explicit operator int(RedisResult result) => result.AsInt32(); + /// - /// Interprets the result as a + /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator bool(RedisResult result) => result.AsBoolean(); + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator RedisValue(RedisResult? result) => result?.AsRedisValue() ?? RedisValue.Null; + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator RedisKey(RedisResult? result) => result?.AsRedisKey() ?? default; + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator double?(RedisResult? result) => result?.AsNullableDouble(); + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator long?(RedisResult? result) => result?.AsNullableInt64(); + /// /// Interprets the result as a . /// /// The result to convert to a . [CLSCompliant(false)] public static explicit operator ulong?(RedisResult? result) => result?.AsNullableUInt64(); + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator int?(RedisResult? result) => result?.AsNullableInt32(); + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator bool?(RedisResult? result) => result?.AsNullableBoolean(); + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator string?[]?(RedisResult? result) => result?.AsStringArray(); + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator byte[]?[]?(RedisResult? result) => result?.AsByteArrayArray(); + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator double[]?(RedisResult? result) => result?.AsDoubleArray(); + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator long[]?(RedisResult? result) => result?.AsInt64Array(); + /// /// Interprets the result as a . /// /// The result to convert to a . [CLSCompliant(false)] public static explicit operator ulong[]?(RedisResult? result) => result?.AsUInt64Array(); + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator int[]?(RedisResult? result) => result?.AsInt32Array(); + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator bool[]?(RedisResult? result) => result?.AsBooleanArray(); + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator RedisValue[]?(RedisResult? result) => result?.AsRedisValueArray(); + /// /// Interprets the result as a . /// /// The result to convert to a . public static explicit operator RedisKey[]?(RedisResult? result) => result?.AsRedisKeyArray(); + /// /// Interprets the result as a . /// @@ -579,7 +602,8 @@ public SingleRedisResult(RedisValue value, ResultType? resultType) : base(value. type = null; string? s = _value; if (Resp3Type == ResultType.VerbatimString && s is not null && s.Length >= 4 && s[3] == ':') - { // remove the prefix + { + // remove the prefix type = s.Substring(0, 3); s = s.Substring(4); } @@ -652,7 +676,11 @@ decimal IConvertible.ToDecimal(IFormatProvider? provider) ThrowNotSupported(); return default; } - DateTime IConvertible.ToDateTime(IFormatProvider? provider) { ThrowNotSupported(); return default; } + DateTime IConvertible.ToDateTime(IFormatProvider? provider) + { + ThrowNotSupported(); + return default; + } string IConvertible.ToString(IFormatProvider? provider) => AsString()!; object IConvertible.ToType(Type conversionType, IFormatProvider? provider) { diff --git a/src/StackExchange.Redis/RedisServer.cs b/src/StackExchange.Redis/RedisServer.cs index 1f7791dd2..8810e1e2b 100644 --- a/src/StackExchange.Redis/RedisServer.cs +++ b/src/StackExchange.Redis/RedisServer.cs @@ -224,24 +224,22 @@ private Message GetCommandListMessage(RedisValue? moduleName = null, RedisValue? { return Message.Create(-1, flags, RedisCommand.COMMAND, RedisLiterals.LIST); } - else if (moduleName != null && category == null && pattern == null) { return Message.Create(-1, flags, RedisCommand.COMMAND, MakeArray(RedisLiterals.LIST, RedisLiterals.FILTERBY, RedisLiterals.MODULE, (RedisValue)moduleName)); } - else if (moduleName == null && category != null && pattern == null) { return Message.Create(-1, flags, RedisCommand.COMMAND, MakeArray(RedisLiterals.LIST, RedisLiterals.FILTERBY, RedisLiterals.ACLCAT, (RedisValue)category)); } - else if (moduleName == null && category == null && pattern != null) { return Message.Create(-1, flags, RedisCommand.COMMAND, MakeArray(RedisLiterals.LIST, RedisLiterals.FILTERBY, RedisLiterals.PATTERN, (RedisValue)pattern)); } - else + { throw new ArgumentException("More then one filter is not allowed"); + } } private RedisValue[] AddValueToArray(RedisValue val, RedisValue[] arr) @@ -253,7 +251,7 @@ private RedisValue[] AddValueToArray(RedisValue val, RedisValue[] arr) return result; } - private RedisValue[] MakeArray(params RedisValue[] redisValues) { return redisValues; } + private RedisValue[] MakeArray(params RedisValue[] redisValues) => redisValues; public long DatabaseSize(int database = -1, CommandFlags flags = CommandFlags.None) { @@ -1048,7 +1046,7 @@ public Task ExecuteAsync(string command, ICollection args, } /// - /// For testing only + /// For testing only. /// internal void SimulateConnectionFailure(SimulatedFailureType failureType) => server.SimulateConnectionFailure(failureType); diff --git a/src/StackExchange.Redis/RedisSubscriber.cs b/src/StackExchange.Redis/RedisSubscriber.cs index cb4940e41..92c96ad6c 100644 --- a/src/StackExchange.Redis/RedisSubscriber.cs +++ b/src/StackExchange.Redis/RedisSubscriber.cs @@ -148,7 +148,7 @@ internal long EnsureSubscriptions(CommandFlags flags = CommandFlags.None) internal enum SubscriptionAction { Subscribe, - Unsubscribe + Unsubscribe, } /// @@ -396,7 +396,6 @@ internal bool EnsureSubscribedToServer(Subscription sub, RedisChannel channel, C if (sub.IsConnected) { return true; } // TODO: Cleanup old hangers here? - sub.SetCurrentServer(null); // we're not appropriately connected, so blank it out for eligible reconnection var message = sub.GetMessage(channel, SubscriptionAction.Subscribe, flags, internalCall); var selected = multiplexer.SelectServer(message); @@ -428,7 +427,6 @@ public Task EnsureSubscribedToServerAsync(Subscription sub, RedisChannel c if (sub.IsConnected) { return CompletedTask.Default(null); } // TODO: Cleanup old hangers here? - sub.SetCurrentServer(null); // we're not appropriately connected, so blank it out for eligible reconnection var message = sub.GetMessage(channel, SubscriptionAction.Subscribe, flags, internalCall); var selected = multiplexer.SelectServer(message); diff --git a/src/StackExchange.Redis/RedisTransaction.cs b/src/StackExchange.Redis/RedisTransaction.cs index 7f0d1a7ec..04d7293ac 100644 --- a/src/StackExchange.Redis/RedisTransaction.cs +++ b/src/StackExchange.Redis/RedisTransaction.cs @@ -219,6 +219,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes private class TransactionMessage : Message, IMultiMessage { private readonly ConditionResult[] conditions; + public QueuedMessage[] InnerOperations { get; } public TransactionMessage(int db, CommandFlags flags, List? conditions, List? operations) @@ -233,7 +234,7 @@ internal override void SetExceptionAndComplete(Exception exception, PhysicalBrid var inner = InnerOperations; if (inner != null) { - for(int i = 0; i < inner.Length;i++) + for (int i = 0; i < inner.Length; i++) { inner[i]?.Wrapped?.SetExceptionAndComplete(exception, bridge); } @@ -358,7 +359,8 @@ public IEnumerable GetMessages(PhysicalConnection connection) foreach (var op in InnerOperations) { if (explicitCheckForQueued) - { // need to have locked them before sending them + { + // need to have locked them before sending them // to guarantee that we see the pulse IResultBox? thisBox = op.ResultBox; if (thisBox != null) @@ -498,11 +500,11 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes SetResult(message, false); return true; } - //EXEC returned with a NULL + // EXEC returned with a NULL if (!tran.IsAborted && result.IsNull) { connection.Trace("Server aborted due to failed EXEC"); - //cancel the commands in the transaction and mark them as complete with the completion manager + // cancel the commands in the transaction and mark them as complete with the completion manager foreach (var op in wrapped) { var inner = op.Wrapped; @@ -536,7 +538,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes muxer?.OnTransactionLog($"Processing {arr.Length} wrapped messages"); int i = 0; - foreach(ref RawResult item in arr) + foreach (ref RawResult item in arr) { var inner = wrapped[i++].Wrapped; muxer?.OnTransactionLog($"> got {item} for {inner.CommandAndKey}"); diff --git a/src/StackExchange.Redis/RedisValue.cs b/src/StackExchange.Redis/RedisValue.cs index a0b045cf4..0eb1a5812 100644 --- a/src/StackExchange.Redis/RedisValue.cs +++ b/src/StackExchange.Redis/RedisValue.cs @@ -30,7 +30,8 @@ private RedisValue(long overlappedValue64, ReadOnlyMemory memory, object? } internal RedisValue(object obj, long overlappedBits) - { // this creates a bodged RedisValue which should **never** + { + // this creates a bodged RedisValue which should **never** // be seen directly; the contents are ... unexpected _overlappedBits64 = overlappedBits; _objectOrSentinel = obj; @@ -53,7 +54,7 @@ public RedisValue(string value) : this(0, default, value) { } private static readonly object Sentinel_Double = new(); /// - /// Obtain this value as an object - to be used alongside Unbox + /// Obtain this value as an object - to be used alongside Unbox. /// public object? Box() { @@ -244,7 +245,7 @@ private static int GetHashCode(RedisValue x) StorageType.Null => -1, StorageType.Double => x.OverlappedValueDouble.GetHashCode(), StorageType.Int64 or StorageType.UInt64 => x._overlappedBits64.GetHashCode(), - StorageType.Raw => ((string)x!).GetHashCode(),// to match equality + StorageType.Raw => ((string)x!).GetHashCode(), // to match equality _ => x._objectOrSentinel!.GetHashCode(), }; } @@ -291,13 +292,13 @@ internal static unsafe int GetHashCode(ReadOnlySpan span) for (int i = 0; i < span64.Length; i++) { var val = span64[i]; - int valHash = (((int)val) ^ ((int)(val >> 32))); - acc = (((acc << 5) + acc) ^ valHash); + int valHash = ((int)val) ^ ((int)(val >> 32)); + acc = ((acc << 5) + acc) ^ valHash; } int spare = len % 8, offset = len - spare; while (spare-- != 0) { - acc = (((acc << 5) + acc) ^ span[offset++]); + acc = ((acc << 5) + acc) ^ span[offset++]; } return acc; } @@ -310,7 +311,12 @@ internal void AssertNotNull() internal enum StorageType { - Null, Int64, UInt64, Double, Raw, String, + Null, + Int64, + UInt64, + Double, + Raw, + String, } internal StorageType Type @@ -330,7 +336,7 @@ internal StorageType Type } /// - /// Get the size of this value in bytes + /// Get the size of this value in bytes. /// public long Length() => Type switch { @@ -527,6 +533,7 @@ public static implicit operator RedisValue(ReadOnlyMemory value) if (value.Length == 0) return EmptyString; return new RedisValue(0, value, Sentinel_Raw); } + /// /// Creates a new from a . /// @@ -594,9 +601,9 @@ public static explicit operator long(RedisValue value) value = value.Simplify(); return value.Type switch { - StorageType.Null => 0,// in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr") + StorageType.Null => 0, // in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr") StorageType.Int64 => value.OverlappedValueInt64, - StorageType.UInt64 => checked((long)value.OverlappedValueUInt64),// this will throw since unsigned is always 64-bit + StorageType.UInt64 => checked((long)value.OverlappedValueUInt64), // this will throw since unsigned is always 64-bit _ => throw new InvalidCastException($"Unable to cast from {value.Type} to long: '{value}'"), }; } @@ -611,7 +618,7 @@ public static explicit operator uint(RedisValue value) value = value.Simplify(); return value.Type switch { - StorageType.Null => 0,// in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr") + StorageType.Null => 0, // in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr") StorageType.Int64 => checked((uint)value.OverlappedValueInt64), StorageType.UInt64 => checked((uint)value.OverlappedValueUInt64), _ => throw new InvalidCastException($"Unable to cast from {value.Type} to uint: '{value}'"), @@ -628,8 +635,8 @@ public static explicit operator ulong(RedisValue value) value = value.Simplify(); return value.Type switch { - StorageType.Null => 0,// in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr") - StorageType.Int64 => checked((ulong)value.OverlappedValueInt64),// throw if negative + StorageType.Null => 0, // in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr") + StorageType.Int64 => checked((ulong)value.OverlappedValueInt64), // throw if negative StorageType.UInt64 => value.OverlappedValueUInt64, _ => throw new InvalidCastException($"Unable to cast from {value.Type} to ulong: '{value}'"), }; @@ -644,7 +651,7 @@ public static explicit operator double(RedisValue value) value = value.Simplify(); return value.Type switch { - StorageType.Null => 0,// in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr") + StorageType.Null => 0, // in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr") StorageType.Int64 => value.OverlappedValueInt64, StorageType.UInt64 => value.OverlappedValueUInt64, StorageType.Double => value.OverlappedValueDouble, @@ -661,7 +668,7 @@ public static explicit operator decimal(RedisValue value) value = value.Simplify(); return value.Type switch { - StorageType.Null => 0,// in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr") + StorageType.Null => 0, // in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr") StorageType.Int64 => value.OverlappedValueInt64, StorageType.UInt64 => value.OverlappedValueUInt64, StorageType.Double => (decimal)value.OverlappedValueDouble, @@ -678,7 +685,7 @@ public static explicit operator float(RedisValue value) value = value.Simplify(); return value.Type switch { - StorageType.Null => 0,// in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr") + StorageType.Null => 0, // in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr") StorageType.Int64 => value.OverlappedValueInt64, StorageType.UInt64 => value.OverlappedValueUInt64, StorageType.Double => (float)value.OverlappedValueDouble, @@ -908,7 +915,7 @@ object IConvertible.ToType(Type conversionType, IFormatProvider? provider) /// but more importantly b: because it can change values - for example, if they start /// with "123.000", it should **stay** as "123.000", not become 123L; this could be /// a hash key or similar - we don't want to break it; RedisConnection uses - /// the storage type, not the "does it look like a long?" - for this reason + /// the storage type, not the "does it look like a long?" - for this reason. /// internal RedisValue Simplify() { @@ -965,8 +972,15 @@ public bool TryParse(out long val) return Format.TryParseInt64(_memory.Span, out val); case StorageType.Double: var d = OverlappedValueDouble; - try { val = (long)d; } - catch { val = default; return false; } + try + { + val = (long)d; + } + catch + { + val = default; + return false; + } return val == d; case StorageType.Null: // in redis-land 0 approx. equal null; so roll with it @@ -1083,8 +1097,8 @@ public bool StartsWith(RedisValue value) switch (thisType) { case StorageType.String: - var sThis = ((string)_objectOrSentinel!); - var sOther = ((string)value._objectOrSentinel!); + var sThis = (string)_objectOrSentinel!; + var sOther = (string)value._objectOrSentinel!; return sThis.StartsWith(sOther, StringComparison.Ordinal); case StorageType.Raw: rawThis = _memory; diff --git a/src/StackExchange.Redis/ResultBox.cs b/src/StackExchange.Redis/ResultBox.cs index c61221018..20b76ba15 100644 --- a/src/StackExchange.Redis/ResultBox.cs +++ b/src/StackExchange.Redis/ResultBox.cs @@ -102,7 +102,7 @@ private TaskResultBox(object? asyncState, TaskCreationOptions creationOptions) : void IResultBox.SetResult(T value) => _value = value; - T? IResultBox.GetResult(out Exception? ex, bool _) + T? IResultBox.GetResult(out Exception? ex, bool unused) { ex = _exception; return _value; @@ -145,9 +145,10 @@ public static IResultBox Create(out TaskCompletionSource source, object? a // how it is being used in those 2 different ways; also, the *fact* that they // are the same underlying object is an implementation detail that the rest of // the code doesn't need to know about - var obj = new TaskResultBox(asyncState, ConnectionMultiplexer.PreventThreadTheft - ? TaskCreationOptions.None // if we don't trust the TPL/sync-context, avoid a double QUWI dispatch - : TaskCreationOptions.RunContinuationsAsynchronously); + var obj = new TaskResultBox( + asyncState, + // if we don't trust the TPL/sync-context, avoid a double QUWI dispatch + ConnectionMultiplexer.PreventThreadTheft ? TaskCreationOptions.None : TaskCreationOptions.RunContinuationsAsynchronously); source = obj; return obj; } diff --git a/src/StackExchange.Redis/ResultProcessor.cs b/src/StackExchange.Redis/ResultProcessor.cs index 95dc4bd87..894e6f5f9 100644 --- a/src/StackExchange.Redis/ResultProcessor.cs +++ b/src/StackExchange.Redis/ResultProcessor.cs @@ -1,6 +1,4 @@ -using Microsoft.Extensions.Logging; -using Pipelines.Sockets.Unofficial.Arenas; -using System; +using System; using System.Buffers; using System.Collections.Generic; using System.Diagnostics; @@ -10,6 +8,8 @@ using System.Net; using System.Text; using System.Text.RegularExpressions; +using Microsoft.Extensions.Logging; +using Pipelines.Sockets.Unofficial.Arenas; namespace StackExchange.Redis { @@ -402,7 +402,8 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes return false; } else - { // don't check the actual reply; there are multiple ways of constructing + { + // don't check the actual reply; there are multiple ways of constructing // a timing message, and we don't actually care about what approach was used TimeSpan duration; if (message is TimerMessage timingMessage) @@ -465,7 +466,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes var newServer = message.Command switch { RedisCommand.SUBSCRIBE or RedisCommand.PSUBSCRIBE => connection.BridgeCouldBeNull?.ServerEndPoint, - _ => null + _ => null, }; Subscription?.SetCurrentServer(newServer); return true; @@ -485,8 +486,16 @@ public static bool TryGet(in RawResult result, out bool value) case ResultType.Integer: case ResultType.SimpleString: case ResultType.BulkString: - if (result.IsEqual(CommonReplies.one)) { value = true; return true; } - else if (result.IsEqual(CommonReplies.zero)) { value = false; return true; } + if (result.IsEqual(CommonReplies.one)) + { + value = true; + return true; + } + else if (result.IsEqual(CommonReplies.zero)) + { + value = false; + return true; + } break; } value = false; @@ -651,7 +660,6 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes } } - internal sealed class HashEntryArrayProcessor : ValuePairInterleavedProcessorBase { protected override HashEntry Parse(in RawResult first, in RawResult second, object? state) => @@ -900,7 +908,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes if (message?.Command == RedisCommand.CONFIG) { var iter = result.GetItems().GetEnumerator(); - while(iter.MoveNext()) + while (iter.MoveNext()) { ref RawResult key = ref iter.Current; if (!iter.MoveNext()) break; @@ -1137,9 +1145,13 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes case ResultType.BulkString: string nodes = result.GetString()!; try - { ClusterNodesProcessor.Parse(connection, nodes); } + { + ClusterNodesProcessor.Parse(connection, nodes); + } catch - { /* tralalalala */} + { + /* tralalalala */ + } SetResult(message, nodes); return true; } @@ -1217,7 +1229,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes // -1 means no expiry and -2 means key does not exist < 0 => null, _ when isMilliseconds => RedisBase.UnixEpoch.AddMilliseconds(duration), - _ => RedisBase.UnixEpoch.AddSeconds(duration) + _ => RedisBase.UnixEpoch.AddSeconds(duration), }; SetResult(message, expiry); return true; @@ -1275,7 +1287,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes SetResult(message, true); return true; } - if(message.Command == RedisCommand.AUTH) connection?.BridgeCouldBeNull?.Multiplexer?.SetAuthSuspect(new RedisException("Unknown AUTH exception")); + if (message.Command == RedisCommand.AUTH) connection?.BridgeCouldBeNull?.Multiplexer?.SetAuthSuspect(new RedisException("Unknown AUTH exception")); return false; } } @@ -1716,7 +1728,7 @@ The geohash integer. /// /// Parser for the https://redis.io/commands/lcs/ format with the and arguments. /// - /// + /// /// Example response: /// 1) "matches" /// 2) 1) 1) 1) (integer) 4 @@ -1726,7 +1738,8 @@ The geohash integer. /// 3) (integer) 4 /// 3) "len" /// 4) (integer) 6 - /// + /// ... + /// private sealed class LongestCommonSubsequenceProcessor : ResultProcessor { protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) @@ -2087,15 +2100,16 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes } else { - streams = result.GetItems().ToArray((in RawResult item, in MultiStreamProcessor obj) => - { - var details = item.GetItems(); + streams = result.GetItems().ToArray( + (in RawResult item, in MultiStreamProcessor obj) => + { + var details = item.GetItems(); - // details[0] = Name of the Stream - // details[1] = Multibulk Array of Stream Entries - return new RedisStream(key: details[0].AsRedisKey(), - entries: obj.ParseRedisStreamEntries(details[1])!); - }, this); + // details[0] = Name of the Stream + // details[1] = Multibulk Array of Stream Entries + return new RedisStream(key: details[0].AsRedisKey(), entries: obj.ParseRedisStreamEntries(details[1])!); + }, + this); } SetResult(message, streams); @@ -2191,7 +2205,6 @@ protected override StreamConsumerInfo ParseItem(in RawResult result) // 4) (integer)1 // 5) idle // 6) (integer)83841983 - var arr = result.GetItems(); string? name = default; int pendingMessageCount = default; @@ -2235,7 +2248,8 @@ internal static bool TryRead(Sequence pairs, in CommandBytes key, ref internal static bool TryRead(Sequence pairs, in CommandBytes key, ref int value) { long tmp = default; - if(TryRead(pairs, key, ref tmp)) { + if (TryRead(pairs, key, ref tmp)) + { value = checked((int)tmp); return true; } @@ -2289,7 +2303,6 @@ protected override StreamGroupInfo ParseItem(in RawResult result) // 10) (integer)1 // 11) "lag" // 12) (integer)1 - var arr = result.GetItems(); string? name = default, lastDeliveredId = default; int consumerCount = default, pendingMessageCount = default; @@ -2361,13 +2374,13 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes var lastGeneratedId = Redis.RedisValue.Null; StreamEntry firstEntry = StreamEntry.Null, lastEntry = StreamEntry.Null; var iter = arr.GetEnumerator(); - for(int i = 0; i < max; i++) + for (int i = 0; i < max; i++) { ref RawResult key = ref iter.GetNext(), value = ref iter.GetNext(); if (key.Payload.Length > CommandBytes.MaxLength) continue; var keyBytes = new CommandBytes(key.Payload); - if(keyBytes.Equals(CommonReplies.length)) + if (keyBytes.Equals(CommonReplies.length)) { if (!value.TryGetInt64(out length)) return false; } @@ -2424,7 +2437,6 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes // 2) "2" // 5) 1) 1) "Joe" // 2) "8" - if (result.Resp2TypeArray != ResultType.Array) { return false; @@ -2453,12 +2465,11 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes }); } - var pendingInfo = new StreamPendingInfo(pendingMessageCount: (int)arr[0].AsRedisValue(), + var pendingInfo = new StreamPendingInfo( + pendingMessageCount: (int)arr[0].AsRedisValue(), lowestId: arr[1].AsRedisValue(), highestId: arr[2].AsRedisValue(), consumers: consumers ?? Array.Empty()); - // ^^^^^ - // Should we bother allocating an empty array only to prevent the need for a null check? SetResult(message, pendingInfo); return true; @@ -2478,7 +2489,8 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes { var details = item.GetItems().GetEnumerator(); - return new StreamPendingMessageInfo(messageId: details.GetNext().AsRedisValue(), + return new StreamPendingMessageInfo( + messageId: details.GetNext().AsRedisValue(), consumerName: details.GetNext().AsRedisValue(), idleTimeInMs: (long)details.GetNext().AsRedisValue(), deliveryCount: (int)details.GetNext().AsRedisValue()); @@ -2500,6 +2512,7 @@ protected override NameValueEntry Parse(in RawResult first, in RawResult second, /// /// Handles stream responses. For formats, see . /// + /// The type of the stream result. internal abstract class StreamProcessorBase : ResultProcessor { protected static StreamEntry ParseRedisStreamEntry(in RawResult item) @@ -2513,7 +2526,8 @@ protected static StreamEntry ParseRedisStreamEntry(in RawResult item) // [1] = Multibulk array of the name/value pairs of the stream entry's data var entryDetails = item.GetItems(); - return new StreamEntry(id: entryDetails[0].AsRedisValue(), + return new StreamEntry( + id: entryDetails[0].AsRedisValue(), values: ParseStreamEntryValues(entryDetails[1])); } protected internal StreamEntry[] ParseRedisStreamEntries(in RawResult result) => @@ -2535,7 +2549,6 @@ protected static NameValueEntry[] ParseStreamEntryValues(in RawResult result) // 2) "9999" // 3) "temperature" // 4) "18.2" - if (result.Resp2TypeArray != ResultType.Array || result.IsNull) { return Array.Empty(); @@ -2686,7 +2699,8 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes } else { - connection.RecordConnectionFailed(ConnectionFailureType.ProtocolFailure, + connection.RecordConnectionFailed( + ConnectionFailureType.ProtocolFailure, new InvalidOperationException($"unexpected tracer reply to {message.Command}: {result.ToString()}")); return false; } @@ -2819,7 +2833,8 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes { throw new ArgumentOutOfRangeException(nameof(rawInnerArray), $"Error processing {message.CommandAndKey}, could not decode array '{rawInnerArray}'"); } - }, innerProcessor)!; + }, + innerProcessor)!; SetResult(message, returnArray); return true; @@ -2845,7 +2860,7 @@ internal abstract class ArrayResultProcessor : ResultProcessor { protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) { - switch(result.Resp2TypeArray) + switch (result.Resp2TypeArray) { case ResultType.Array: var items = result.GetItems(); diff --git a/src/StackExchange.Redis/ScriptParameterMapper.cs b/src/StackExchange.Redis/ScriptParameterMapper.cs index 9960d87b7..10dccd5ff 100644 --- a/src/StackExchange.Redis/ScriptParameterMapper.cs +++ b/src/StackExchange.Redis/ScriptParameterMapper.cs @@ -154,7 +154,7 @@ public static LuaScript PrepareScript(string script) typeof(bool?), typeof(RedisKey), - typeof(RedisValue) + typeof(RedisValue), }; /// @@ -252,20 +252,18 @@ public static bool IsValidParameterHash(Type t, LuaScript script, out string? mi else { var needsKeyPrefix = Expression.Property(keyPrefix, nameof(Nullable.HasValue)); - var keyPrefixValueArr = new[] { Expression.Call(keyPrefix, - nameof(Nullable.GetValueOrDefault), null, null) }; - var prepend = typeof(RedisKey).GetMethod(nameof(RedisKey.Prepend), - BindingFlags.Public | BindingFlags.Instance)!; - asRedisValue = typeof(RedisKey).GetMethod(nameof(RedisKey.AsRedisValue), - BindingFlags.NonPublic | BindingFlags.Instance)!; + var keyPrefixValueArr = new[] + { + Expression.Call(keyPrefix, nameof(Nullable.GetValueOrDefault), null, null), + }; + var prepend = typeof(RedisKey).GetMethod(nameof(RedisKey.Prepend), BindingFlags.Public | BindingFlags.Instance)!; + asRedisValue = typeof(RedisKey).GetMethod(nameof(RedisKey.AsRedisValue), BindingFlags.NonPublic | BindingFlags.Instance)!; keysResultArr = new Expression[keys.Count]; for (int i = 0; i < keysResultArr.Length; i++) { var member = GetMember(objTyped, keys[i]); - keysResultArr[i] = Expression.Condition(needsKeyPrefix, - Expression.Call(member, prepend, keyPrefixValueArr), - member); + keysResultArr[i] = Expression.Condition(needsKeyPrefix, Expression.Call(member, prepend, keyPrefixValueArr), member); } keysResult = Expression.NewArrayInit(typeof(RedisKey), keysResultArr); } @@ -294,8 +292,7 @@ public static bool IsValidParameterHash(Type t, LuaScript script, out string? mi } var body = Expression.Lambda>( - Expression.New(ScriptParameters.Cons, keysResult, valuesResult), - objUntyped, keyPrefix); + Expression.New(ScriptParameters.Cons, keysResult, valuesResult), objUntyped, keyPrefix); return body.Compile(); } } diff --git a/src/StackExchange.Redis/ServerCounters.cs b/src/StackExchange.Redis/ServerCounters.cs index f6d96c6a6..b661f27d7 100644 --- a/src/StackExchange.Redis/ServerCounters.cs +++ b/src/StackExchange.Redis/ServerCounters.cs @@ -46,7 +46,7 @@ public ServerCounters(EndPoint? endpoint) public long TotalOutstanding => Interactive.TotalOutstanding + Subscription.TotalOutstanding + Other.TotalOutstanding; /// - /// See Object.ToString(); + /// See . /// public override string ToString() { diff --git a/src/StackExchange.Redis/ServerEndPoint.cs b/src/StackExchange.Redis/ServerEndPoint.cs index 2cbe36920..8b099afd2 100644 --- a/src/StackExchange.Redis/ServerEndPoint.cs +++ b/src/StackExchange.Redis/ServerEndPoint.cs @@ -1,5 +1,4 @@ -using Microsoft.Extensions.Logging; -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -9,6 +8,7 @@ using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using static StackExchange.Redis.PhysicalBridge; namespace StackExchange.Redis @@ -84,7 +84,7 @@ public ServerEndPoint(ConnectionMultiplexer multiplexer, EndPoint endpoint) /// This is memoized because it's accessed on hot paths inside the write lock. /// public bool SupportsDatabases => - supportsDatabases ??= (serverType == ServerType.Standalone && Multiplexer.CommandMap.IsAvailable(RedisCommand.SELECT)); + supportsDatabases ??= serverType == ServerType.Standalone && Multiplexer.CommandMap.IsAvailable(RedisCommand.SELECT); public int Databases { @@ -105,7 +105,7 @@ public bool KnowOrAssumeResp3() } public bool SupportsSubscriptions => Multiplexer.CommandMap.IsAvailable(RedisCommand.SUBSCRIBE); - public bool SupportsPrimaryWrites => supportsPrimaryWrites ??= (!IsReplica || !ReplicaReadOnly || AllowReplicaWrites); + public bool SupportsPrimaryWrites => supportsPrimaryWrites ??= !IsReplica || !ReplicaReadOnly || AllowReplicaWrites; private readonly List> _pendingConnectionMonitors = new List>(); @@ -157,7 +157,7 @@ internal Exception? LastException var subEx = subscription?.LastException; var subExData = subEx?.Data; - //check if subscription endpoint has a better last exception + // check if subscription endpoint has a better last exception if (subExData != null && subExData.Contains("Redis-FailureType") && subExData["Redis-FailureType"]?.ToString() != nameof(ConnectionFailureType.UnableToConnect)) { return subEx; @@ -208,7 +208,7 @@ public Version Version } /// - /// If we have a connection (interactive), report the protocol being used + /// If we have a connection (interactive), report the protocol being used. /// public RedisProtocol? Protocol => interactive?.Protocol; @@ -254,7 +254,6 @@ public void Dispose() // Subscription commands go to a specific bridge - so we need to set that up. // There are other commands we need to send to the right connection (e.g. subscriber PING with an explicit SetForSubscriptionBridge call), // but these always go subscriber. - switch (message.Command) { case RedisCommand.SUBSCRIBE: @@ -464,8 +463,9 @@ internal async Task AutoConfigureAsync(PhysicalConnection? connection, ILogger? } private int _nextReplicaOffset; + /// - /// Used to round-robin between multiple replicas + /// Used to round-robin between multiple replicas. /// internal uint NextReplicaOffset() => (uint)Interlocked.Increment(ref _nextReplicaOffset); @@ -533,7 +533,8 @@ internal BridgeStatus GetBridgeStatus(ConnectionType connectionType) return GetBridge(connectionType, false)?.GetStatus() ?? BridgeStatus.Zero; } catch (Exception ex) - { // only needs to be best efforts + { + // only needs to be best efforts System.Diagnostics.Debug.WriteLine(ex.Message); } @@ -872,6 +873,7 @@ internal string Summary() /// /// Write the message directly to the pipe or fail...will not queue. /// + /// The type of the result processor. internal ValueTask WriteDirectOrQueueFireAndForgetAsync(PhysicalConnection? connection, Message message, ResultProcessor processor) { static async ValueTask Awaited(ValueTask l_result) => await l_result.ForAwait(); @@ -966,7 +968,6 @@ private async Task HandshakeAsync(PhysicalConnection connection, ILogger? log) // that's fine and doesn't cause a problem; if we wanted we could probably just discard (`_ =`) // the various tasks and just `return connection.FlushAsync();` - however, since handshake is low // volume, we can afford to optimize for a good stack-trace rather than avoiding state machines. - ResultProcessor? autoConfig = null; if (Multiplexer.RawConfig.TryResp3()) // note this includes an availability check on HELLO { @@ -1020,8 +1021,7 @@ private async Task HandshakeAsync(PhysicalConnection connection, ILogger? log) var libName = Multiplexer.GetFullLibraryName(); if (!string.IsNullOrWhiteSpace(libName)) { - msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.CLIENT, - RedisLiterals.SETINFO, RedisLiterals.lib_name, libName); + msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.CLIENT, RedisLiterals.SETINFO, RedisLiterals.lib_name, libName); msg.SetInternalCall(); await WriteDirectOrQueueFireAndForgetAsync(connection, msg, ResultProcessor.DemandOK).ForAwait(); } @@ -1029,8 +1029,7 @@ private async Task HandshakeAsync(PhysicalConnection connection, ILogger? log) var version = ClientInfoSanitize(Utils.GetLibVersion()); if (!string.IsNullOrWhiteSpace(version)) { - msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.CLIENT, - RedisLiterals.SETINFO, RedisLiterals.lib_ver, version); + msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.CLIENT, RedisLiterals.SETINFO, RedisLiterals.lib_ver, version); msg.SetInternalCall(); await WriteDirectOrQueueFireAndForgetAsync(connection, msg, ResultProcessor.DemandOK).ForAwait(); } @@ -1086,7 +1085,7 @@ private void SetConfig(ref T field, T value, [CallerMemberName] string? calle } } internal static string ClientInfoSanitize(string? value) - => string.IsNullOrWhiteSpace(value) ? "" : nameSanitizer.Replace(value!.Trim(), "-"); + => string.IsNullOrWhiteSpace(value) ? "" : nameSanitizer.Replace(value!.Trim(), "-"); private void ClearMemoized() { @@ -1095,7 +1094,7 @@ private void ClearMemoized() } /// - /// For testing only + /// For testing only. /// internal void SimulateConnectionFailure(SimulatedFailureType failureType) { diff --git a/src/StackExchange.Redis/ServerSelectionStrategy.cs b/src/StackExchange.Redis/ServerSelectionStrategy.cs index 4a32da0d4..44241d373 100644 --- a/src/StackExchange.Redis/ServerSelectionStrategy.cs +++ b/src/StackExchange.Redis/ServerSelectionStrategy.cs @@ -10,40 +10,40 @@ internal sealed class ServerSelectionStrategy { public const int NoSlot = -1, MultipleSlots = -2; private const int RedisClusterSlotCount = 16384; - private static readonly ushort[] s_crc16tab = new ushort[] + private static readonly ushort[] Crc16tab = new ushort[] { - 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, - 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, - 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, - 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, - 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, - 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, - 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, - 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, - 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, - 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, - 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, - 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, - 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, - 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, - 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, - 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, - 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, - 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, - 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, - 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, - 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, - 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, - 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, - 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, - 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, - 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, - 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, - 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, - 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, - 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, - 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, - 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, }; private readonly ConnectionMultiplexer multiplexer; @@ -103,7 +103,7 @@ public int HashSlot(in RedisChannel channel) /// Gets the hashslot for a given byte sequence. /// /// - /// HASH_SLOT = CRC16(key) mod 16384 + /// HASH_SLOT = CRC16(key) mod 16384. /// private static unsafe int GetClusterSlot(ReadOnlySpan blob) { @@ -111,7 +111,7 @@ private static unsafe int GetClusterSlot(ReadOnlySpan blob) { fixed (byte* ptr = blob) { - fixed (ushort* crc16tab = s_crc16tab) + fixed (ushort* crc16tab = ServerSelectionStrategy.Crc16tab) { int offset = 0, count = blob.Length, start, end; if ((start = IndexOf(ptr, (byte)'{', 0, count - 1)) >= 0 @@ -288,7 +288,8 @@ private static unsafe int IndexOf(byte* ptr, byte value, int start, int end) if (!cursor.IsReplica && cursor.IsSelectable(command)) return cursor; cursor = cursor.Primary; - } while (cursor != null && --max != 0); + } + while (cursor != null && --max != 0); return null; } @@ -330,8 +331,7 @@ private ServerEndPoint[] MapForMutation() if (slot == NoSlot || (arr = map) == null) return Any(command, flags, allowDisconnected); ServerEndPoint endpoint = arr[slot]; - ServerEndPoint? testing; - // but: ^^^ is the PRIMARY slots; if we want a replica, we need to do some thinking + ServerEndPoint? testing; // but: ^^^ is the PRIMARY slots; if we want a replica, we need to do some thinking if (endpoint != null) { diff --git a/src/StackExchange.Redis/SkipLocalsInit.cs b/src/StackExchange.Redis/SkipLocalsInit.cs index 66f84567e..353b00142 100644 --- a/src/StackExchange.Redis/SkipLocalsInit.cs +++ b/src/StackExchange.Redis/SkipLocalsInit.cs @@ -9,6 +9,6 @@ namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)] - internal sealed class SkipLocalsInitAttribute : Attribute {} + internal sealed class SkipLocalsInitAttribute : Attribute { } } #endif diff --git a/src/StackExchange.Redis/SocketManager.cs b/src/StackExchange.Redis/SocketManager.cs index a0c755834..146e576ff 100644 --- a/src/StackExchange.Redis/SocketManager.cs +++ b/src/StackExchange.Redis/SocketManager.cs @@ -41,7 +41,7 @@ public SocketManager(string name, bool useHighPrioritySocketThreads) /// the number of dedicated workers for this . /// Whether this should use high priority sockets. public SocketManager(string name, int workerCount, bool useHighPrioritySocketThreads) - : this(name, workerCount, UseHighPrioritySocketThreads(useHighPrioritySocketThreads)) {} + : this(name, workerCount, UseHighPrioritySocketThreads(useHighPrioritySocketThreads)) { } private static SocketManagerOptions UseHighPrioritySocketThreads(bool value) => value ? SocketManagerOptions.UseHighPrioritySocketThreads : SocketManagerOptions.None; @@ -56,12 +56,14 @@ public enum SocketManagerOptions /// No additional options. /// None = 0, + /// /// Whether the should use high priority sockets. /// UseHighPrioritySocketThreads = 1 << 0, + /// - /// Use the regular thread-pool for all scheduling + /// Use the regular thread-pool for all scheduling. /// UseThreadPool = 1 << 1, } @@ -70,8 +72,8 @@ public enum SocketManagerOptions /// Creates a new (optionally named) instance. /// /// The name for this . - /// the number of dedicated workers for this . - /// + /// The number of dedicated workers for this . + /// Options to use when creating the socket manager. public SocketManager(string? name = null, int workerCount = 0, SocketManagerOptions options = SocketManagerOptions.None) { if (name.IsNullOrWhiteSpace()) name = GetType().Name; @@ -85,17 +87,18 @@ public SocketManager(string? name = null, int workerCount = 0, SocketManagerOpti var defaultPipeOptions = PipeOptions.Default; - long Send_PauseWriterThreshold = Math.Max( - 512 * 1024,// send: let's give it up to 0.5MiB + long send_PauseWriterThreshold = Math.Max( + 512 * 1024, // send: let's give it up to 0.5MiB defaultPipeOptions.PauseWriterThreshold); // or the default, whichever is bigger - long Send_ResumeWriterThreshold = Math.Max( - Send_PauseWriterThreshold / 2, + long send_ResumeWriterThreshold = Math.Max( + send_PauseWriterThreshold / 2, defaultPipeOptions.ResumeWriterThreshold); Scheduler = PipeScheduler.ThreadPool; if (!useThreadPool) { - Scheduler = new DedicatedThreadPoolPipeScheduler(name + ":IO", + Scheduler = new DedicatedThreadPoolPipeScheduler( + name: name + ":IO", workerCount: workerCount, priority: useHighPrioritySocketThreads ? ThreadPriority.AboveNormal : ThreadPriority.Normal); } @@ -103,8 +106,8 @@ public SocketManager(string? name = null, int workerCount = 0, SocketManagerOpti pool: defaultPipeOptions.Pool, readerScheduler: Scheduler, writerScheduler: Scheduler, - pauseWriterThreshold: Send_PauseWriterThreshold, - resumeWriterThreshold: Send_ResumeWriterThreshold, + pauseWriterThreshold: send_PauseWriterThreshold, + resumeWriterThreshold: send_ResumeWriterThreshold, minimumSegmentSize: Math.Max(defaultPipeOptions.MinimumSegmentSize, MINIMUM_SEGMENT_SIZE), useSynchronizationContext: false); ReceivePipeOptions = new PipeOptions( @@ -220,7 +223,7 @@ internal static Socket CreateSocket(EndPoint endpoint) ? new Socket(SocketType.Stream, protocolType) : new Socket(addressFamily, SocketType.Stream, protocolType); SocketConnection.SetRecommendedClientOptions(socket); - //socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, false); + // socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, false); return socket; } diff --git a/src/StackExchange.Redis/StreamConstants.cs b/src/StackExchange.Redis/StreamConstants.cs index 409653c72..74650e010 100644 --- a/src/StackExchange.Redis/StreamConstants.cs +++ b/src/StackExchange.Redis/StreamConstants.cs @@ -1,5 +1,4 @@ - -namespace StackExchange.Redis +namespace StackExchange.Redis { /// /// Constants representing values used in Redis Stream commands. diff --git a/src/StackExchange.Redis/TaskExtensions.cs b/src/StackExchange.Redis/TaskExtensions.cs index 0a70cfc09..081a691ec 100644 --- a/src/StackExchange.Redis/TaskExtensions.cs +++ b/src/StackExchange.Redis/TaskExtensions.cs @@ -40,7 +40,7 @@ internal static Task ObserveErrors(this Task task) /// Licensed to the .NET Foundation under one or more agreements. /// The .NET Foundation licenses this file to you under the MIT license. /// - /// Inspired from + /// Inspired from . internal static async Task TimeoutAfter(this Task task, int timeoutMs) { var cts = new CancellationTokenSource(); diff --git a/tests/BasicTest/Program.cs b/tests/BasicTest/Program.cs index 5c8ef687c..faff1b7d7 100644 --- a/tests/BasicTest/Program.cs +++ b/tests/BasicTest/Program.cs @@ -21,7 +21,7 @@ internal class CustomConfig : ManualConfig { protected virtual Job Configure(Job j) => j.WithGcMode(new GcMode { Force = true }) - //.With(InProcessToolchain.Instance) + // .With(InProcessToolchain.Instance) ; public CustomConfig() @@ -41,9 +41,7 @@ protected override Job Configure(Job j) .WithWarmupCount(1) .WithIterationCount(5); } - /// - /// The tests - /// + [Config(typeof(CustomConfig))] public class RedisBenchmarks : IDisposable { @@ -51,14 +49,10 @@ public class RedisBenchmarks : IDisposable private ConnectionMultiplexer connection; private IDatabase db; - /// - /// Create - /// [GlobalSetup] public void Setup() { // Pipelines.Sockets.Unofficial.SocketConnection.AssertDependencies(); - var options = ConfigurationOptions.Parse("127.0.0.1:6379"); connection = ConnectionMultiplexer.Connect(options); db = connection.GetDatabase(3); @@ -88,10 +82,9 @@ void IDisposable.Dispose() private const int COUNT = 50; /// - /// Run INCRBY lots of times + /// Run INCRBY lots of times. /// // [Benchmark(Description = "INCRBY/s", OperationsPerInvoke = COUNT)] - public int ExecuteIncrBy() { var rand = new Random(12345); @@ -110,7 +103,7 @@ public int ExecuteIncrBy() } /// - /// Run INCRBY lots of times + /// Run INCRBY lots of times. /// // [Benchmark(Description = "INCRBY/a", OperationsPerInvoke = COUNT)] public async Task ExecuteIncrByAsync() @@ -131,7 +124,7 @@ public async Task ExecuteIncrByAsync() } /// - /// Run GEORADIUS lots of times + /// Run GEORADIUS lots of times. /// // [Benchmark(Description = "GEORADIUS/s", OperationsPerInvoke = COUNT)] public int ExecuteGeoRadius() @@ -139,15 +132,14 @@ public int ExecuteGeoRadius() int total = 0; for (int i = 0; i < COUNT; i++) { - var results = db.GeoRadius(GeoKey, 15, 37, 200, GeoUnit.Kilometers, - options: GeoRadiusOptions.WithCoordinates | GeoRadiusOptions.WithDistance | GeoRadiusOptions.WithGeoHash); + var results = db.GeoRadius(GeoKey, 15, 37, 200, GeoUnit.Kilometers, options: GeoRadiusOptions.WithCoordinates | GeoRadiusOptions.WithDistance | GeoRadiusOptions.WithGeoHash); total += results.Length; } return total; } /// - /// Run GEORADIUS lots of times + /// Run GEORADIUS lots of times. /// // [Benchmark(Description = "GEORADIUS/a", OperationsPerInvoke = COUNT)] public async Task ExecuteGeoRadiusAsync() @@ -155,15 +147,14 @@ public async Task ExecuteGeoRadiusAsync() int total = 0; for (int i = 0; i < COUNT; i++) { - var results = await db.GeoRadiusAsync(GeoKey, 15, 37, 200, GeoUnit.Kilometers, - options: GeoRadiusOptions.WithCoordinates | GeoRadiusOptions.WithDistance | GeoRadiusOptions.WithGeoHash).ConfigureAwait(false); + var results = await db.GeoRadiusAsync(GeoKey, 15, 37, 200, GeoUnit.Kilometers, options: GeoRadiusOptions.WithCoordinates | GeoRadiusOptions.WithDistance | GeoRadiusOptions.WithGeoHash).ConfigureAwait(false); total += results.Length; } return total; } /// - /// Run StringSet lots of times + /// Run StringSet lots of times. /// [Benchmark(Description = "StringSet/s", OperationsPerInvoke = COUNT)] public void StringSet() @@ -175,7 +166,7 @@ public void StringSet() } /// - /// Run StringGet lots of times + /// Run StringGet lots of times. /// [Benchmark(Description = "StringGet/s", OperationsPerInvoke = COUNT)] public void StringGet() @@ -187,7 +178,7 @@ public void StringGet() } /// - /// Run HashGetAll lots of times + /// Run HashGetAll lots of times. /// [Benchmark(Description = "HashGetAll F+F/s", OperationsPerInvoke = COUNT)] public void HashGetAll_FAF() @@ -200,7 +191,7 @@ public void HashGetAll_FAF() } /// - /// Run HashGetAll lots of times + /// Run HashGetAll lots of times. /// [Benchmark(Description = "HashGetAll F+F/a", OperationsPerInvoke = COUNT)] diff --git a/tests/ConsoleTest/Program.cs b/tests/ConsoleTest/Program.cs index 39e00701e..98d96f259 100644 --- a/tests/ConsoleTest/Program.cs +++ b/tests/ConsoleTest/Program.cs @@ -1,6 +1,6 @@ -using StackExchange.Redis; -using System.Diagnostics; +using System.Diagnostics; using System.Reflection; +using StackExchange.Redis; Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); @@ -11,7 +11,7 @@ Console.WriteLine($"{nameof(options.HighIntegrity)}: {options.HighIntegrity}"); #endif -//options.SocketManager = SocketManager.ThreadPool; +// options.SocketManager = SocketManager.ThreadPool; Console.WriteLine("Connecting..."); var connection = ConnectionMultiplexer.Connect(options); Console.WriteLine("Connected"); @@ -118,8 +118,8 @@ static async Task MassInsertAsync(ConnectionMultiplexer connection) matchErrors += await ValidateAsync(outstanding); Console.WriteLine(i); } - } + matchErrors += await ValidateAsync(outstanding); Console.WriteLine($"Match errors: {matchErrors}"); @@ -141,7 +141,6 @@ static async Task ValidateAsync(List<(Task, Task, string)> outs } } - static void ParallelTasks(ConnectionMultiplexer connection) { static void ParallelRun(int taskId, ConnectionMultiplexer connection) @@ -164,14 +163,14 @@ static void ParallelRun(int taskId, ConnectionMultiplexer connection) } var taskList = new List(); - for (int i = 0; i < 10; i++) - { - var i1 = i; - var task = new Task(() => ParallelRun(i1, connection)); - task.Start(); - taskList.Add(task); - } - Task.WaitAll(taskList.ToArray()); + for (int i = 0; i < 10; i++) + { + var i1 = i; + var task = new Task(() => ParallelRun(i1, connection)); + task.Start(); + taskList.Add(task); + } + Task.WaitAll(taskList.ToArray()); } static void MassPublish(ConnectionMultiplexer connection) @@ -182,8 +181,8 @@ static void MassPublish(ConnectionMultiplexer connection) static string GetLibVersion() { - var assembly = typeof(ConnectionMultiplexer).Assembly; - return (Attribute.GetCustomAttribute(assembly, typeof(AssemblyFileVersionAttribute)) as AssemblyFileVersionAttribute)?.Version - ?? assembly.GetName().Version?.ToString() - ?? "Unknown"; + var assembly = typeof(ConnectionMultiplexer).Assembly; + return (Attribute.GetCustomAttribute(assembly, typeof(AssemblyFileVersionAttribute)) as AssemblyFileVersionAttribute)?.Version + ?? assembly.GetName().Version?.ToString() + ?? "Unknown"; } diff --git a/tests/StackExchange.Redis.Tests/AbortOnConnectFailTests.cs b/tests/StackExchange.Redis.Tests/AbortOnConnectFailTests.cs index cfb96a547..2920a51d3 100644 --- a/tests/StackExchange.Redis.Tests/AbortOnConnectFailTests.cs +++ b/tests/StackExchange.Redis.Tests/AbortOnConnectFailTests.cs @@ -1,6 +1,6 @@ -using StackExchange.Redis.Tests.Helpers; -using System; +using System; using System.Threading.Tasks; +using StackExchange.Redis.Tests.Helpers; using Xunit; using Xunit.Abstractions; @@ -8,7 +8,7 @@ namespace StackExchange.Redis.Tests; public class AbortOnConnectFailTests : TestBase { - public AbortOnConnectFailTests(ITestOutputHelper output) : base (output) { } + public AbortOnConnectFailTests(ITestOutputHelper output) : base(output) { } [Fact] public void NeverEverConnectedNoBacklogThrowsConnectionNotAvailableSync() diff --git a/tests/StackExchange.Redis.Tests/AdhocTests.cs b/tests/StackExchange.Redis.Tests/AdhocTests.cs index 50ceb88c4..38ae5639a 100644 --- a/tests/StackExchange.Redis.Tests/AdhocTests.cs +++ b/tests/StackExchange.Redis.Tests/AdhocTests.cs @@ -6,7 +6,7 @@ namespace StackExchange.Redis.Tests; [Collection(SharedConnectionFixture.Key)] public class AdhocTests : TestBase { - public AdhocTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base (output, fixture) { } + public AdhocTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } [Fact] public void TestAdhocCommandsAPI() @@ -20,7 +20,7 @@ public void TestAdhocCommandsAPI() RedisKey key = Me(); // note: if command renames are configured in - // the API, they will still work automatically + // the API, they will still work automatically db.Execute("del", key); db.Execute("set", key, "12"); db.Execute("incrby", key, 4); diff --git a/tests/StackExchange.Redis.Tests/AggressiveTests.cs b/tests/StackExchange.Redis.Tests/AggressiveTests.cs index 375e2da3d..73d06c4c7 100644 --- a/tests/StackExchange.Redis.Tests/AggressiveTests.cs +++ b/tests/StackExchange.Redis.Tests/AggressiveTests.cs @@ -81,11 +81,11 @@ public void RunCompetingBatchesOnSameMuxer() Thread x = new Thread(state => BatchRunPings((IDatabase)state!)) { - Name = nameof(BatchRunPings) + Name = nameof(BatchRunPings), }; Thread y = new Thread(state => BatchRunIntegers((IDatabase)state!)) { - Name = nameof(BatchRunIntegers) + Name = nameof(BatchRunIntegers), }; x.Start(db); @@ -102,7 +102,7 @@ private void BatchRunIntegers(IDatabase db) db.KeyDelete(key); db.StringSet(key, 1); Task[] tasks = new Task[InnerCount]; - for(int i = 0; i < IterationCount; i++) + for (int i = 0; i < IterationCount; i++) { var batch = db.CreateBatch(); for (int j = 0; j < tasks.Length; j++) @@ -161,7 +161,7 @@ private async Task BatchRunIntegersAsync(IDatabase db) tasks[j] = batch.StringIncrementAsync(key); } batch.Execute(); - for(int j = tasks.Length - 1; j >= 0;j--) + for (int j = tasks.Length - 1; j >= 0; j--) { await tasks[j]; } @@ -197,11 +197,11 @@ public void RunCompetingTransactionsOnSameMuxer() Thread x = new Thread(state => TranRunPings((IDatabase)state!)) { - Name = nameof(BatchRunPings) + Name = nameof(BatchRunPings), }; Thread y = new Thread(state => TranRunIntegers((IDatabase)state!)) { - Name = nameof(BatchRunIntegers) + Name = nameof(BatchRunIntegers), }; x.Start(db); diff --git a/tests/StackExchange.Redis.Tests/BacklogTests.cs b/tests/StackExchange.Redis.Tests/BacklogTests.cs index d1c853577..b81c86b8a 100644 --- a/tests/StackExchange.Redis.Tests/BacklogTests.cs +++ b/tests/StackExchange.Redis.Tests/BacklogTests.cs @@ -7,7 +7,7 @@ namespace StackExchange.Redis.Tests; public class BacklogTests : TestBase { - public BacklogTests(ITestOutputHelper output) : base (output) { } + public BacklogTests(ITestOutputHelper output) : base(output) { } protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort + "," + TestConfig.Current.ReplicaServerAndPort; @@ -149,7 +149,6 @@ public async Task QueuesAndFlushesAfterReconnectingAsync() var lastPing = db.PingAsync(); // TODO: Add specific server call - var disconnectedStats = server.GetBridgeStatus(ConnectionType.Interactive); Assert.False(conn.IsConnected); Assert.True(disconnectedStats.BacklogMessagesPending >= 3, $"Expected {nameof(disconnectedStats.BacklogMessagesPending)} > 3, got {disconnectedStats.BacklogMessagesPending}"); @@ -238,10 +237,10 @@ public async Task QueuesAndFlushesAfterReconnecting() Log("Test: Disconnected pings"); Task[] pings = new Task[3]; - pings[0] = RunBlockingSynchronousWithExtraThreadAsync(() => disconnectedPings(1)); - pings[1] = RunBlockingSynchronousWithExtraThreadAsync(() => disconnectedPings(2)); - pings[2] = RunBlockingSynchronousWithExtraThreadAsync(() => disconnectedPings(3)); - void disconnectedPings(int id) + pings[0] = RunBlockingSynchronousWithExtraThreadAsync(() => DisconnectedPings(1)); + pings[1] = RunBlockingSynchronousWithExtraThreadAsync(() => DisconnectedPings(2)); + pings[2] = RunBlockingSynchronousWithExtraThreadAsync(() => DisconnectedPings(3)); + void DisconnectedPings(int id) { // No need to delay, we're going to try a disconnected connection immediately so it'll fail... Log($"Pinging (disconnected - {id})"); @@ -278,9 +277,9 @@ void disconnectedPings(int id) Assert.Equal(0, reconnectedStats.BacklogMessagesPending); Log("Test: Pinging again..."); - pings[0] = RunBlockingSynchronousWithExtraThreadAsync(() => disconnectedPings(4)); - pings[1] = RunBlockingSynchronousWithExtraThreadAsync(() => disconnectedPings(5)); - pings[2] = RunBlockingSynchronousWithExtraThreadAsync(() => disconnectedPings(6)); + pings[0] = RunBlockingSynchronousWithExtraThreadAsync(() => DisconnectedPings(4)); + pings[1] = RunBlockingSynchronousWithExtraThreadAsync(() => DisconnectedPings(5)); + pings[2] = RunBlockingSynchronousWithExtraThreadAsync(() => DisconnectedPings(6)); Log("Test: Last Ping queued"); // We should see none queued diff --git a/tests/StackExchange.Redis.Tests/BitTests.cs b/tests/StackExchange.Redis.Tests/BitTests.cs index 1a870f37e..c6b12c02b 100644 --- a/tests/StackExchange.Redis.Tests/BitTests.cs +++ b/tests/StackExchange.Redis.Tests/BitTests.cs @@ -7,7 +7,7 @@ namespace StackExchange.Redis.Tests; [Collection(SharedConnectionFixture.Key)] public class BitTests : TestBase { - public BitTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base (output, fixture) { } + public BitTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } [Fact] public void BasicOps() diff --git a/tests/StackExchange.Redis.Tests/BoxUnboxTests.cs b/tests/StackExchange.Redis.Tests/BoxUnboxTests.cs index 123a33a88..1ffb972a2 100644 --- a/tests/StackExchange.Redis.Tests/BoxUnboxTests.cs +++ b/tests/StackExchange.Redis.Tests/BoxUnboxTests.cs @@ -52,7 +52,7 @@ private static void AssertEqualGiveOrTakeNaN(RedisValue expected, RedisValue act private static readonly byte[] s_abc = Encoding.UTF8.GetBytes("abc"); public static IEnumerable RoundTripValues - => new [] + => new[] { new object[] { RedisValue.Null }, new object[] { RedisValue.EmptyString }, @@ -94,7 +94,7 @@ public static IEnumerable RoundTripValues }; public static IEnumerable UnboxValues - => new [] + => new[] { new object?[] { null, RedisValue.Null }, new object[] { "", RedisValue.EmptyString }, @@ -125,7 +125,7 @@ public static IEnumerable UnboxValues new object[] { double.NegativeInfinity, (RedisValue)double.NegativeInfinity }, new object[] { double.NaN, (RedisValue)double.NaN }, new object[] { true, (RedisValue)true }, - new object[] { false, (RedisValue)false}, + new object[] { false, (RedisValue)false }, new object[] { "abc", (RedisValue)"abc" }, new object[] { s_abc, (RedisValue)s_abc }, new object[] { new Memory(s_abc), (RedisValue)s_abc }, @@ -135,7 +135,7 @@ public static IEnumerable UnboxValues public static IEnumerable InternedValues() { - for(int i = -20; i <= 40; i++) + for (int i = -20; i <= 40; i++) { bool expectInterned = i >= -1 & i <= 20; yield return new object[] { (RedisValue)i, expectInterned }; @@ -146,13 +146,13 @@ public static IEnumerable InternedValues() yield return new object[] { (RedisValue)float.NegativeInfinity, true }; yield return new object[] { (RedisValue)(-0.5F), false }; - yield return new object[] { (RedisValue)(0.5F), false }; + yield return new object[] { (RedisValue)0.5F, false }; yield return new object[] { (RedisValue)float.PositiveInfinity, true }; yield return new object[] { (RedisValue)float.NaN, true }; yield return new object[] { (RedisValue)double.NegativeInfinity, true }; yield return new object[] { (RedisValue)(-0.5D), false }; - yield return new object[] { (RedisValue)(0.5D), false }; + yield return new object[] { (RedisValue)0.5D, false }; yield return new object[] { (RedisValue)double.PositiveInfinity, true }; yield return new object[] { (RedisValue)double.NaN, true }; diff --git a/tests/StackExchange.Redis.Tests/ClientKillTests.cs b/tests/StackExchange.Redis.Tests/ClientKillTests.cs index 34f00c6bc..eaf91e073 100644 --- a/tests/StackExchange.Redis.Tests/ClientKillTests.cs +++ b/tests/StackExchange.Redis.Tests/ClientKillTests.cs @@ -52,14 +52,14 @@ public void TestClientKillMessageWithAllArguments() ClientType type = ClientType.Normal; string userName = "user1"; EndPoint endpoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1234); - EndPoint serverEndpoint = new IPEndPoint(IPAddress.Parse("198.0.0.1"), 6379); ; + EndPoint serverEndpoint = new IPEndPoint(IPAddress.Parse("198.0.0.1"), 6379); bool skipMe = true; long maxAge = 102; var filter = new ClientKillFilter().WithId(id).WithClientType(type).WithUsername(userName).WithEndpoint(endpoint).WithServerEndpoint(serverEndpoint).WithSkipMe(skipMe).WithMaxAgeInSeconds(maxAge); List expected = new List() { - "KILL", "ID", "101", "TYPE", "normal", "USERNAME", "user1", "ADDR", "127.0.0.1:1234", "LADDR", "198.0.0.1:6379", "SKIPME", "yes", "MAXAGE", "102" + "KILL", "ID", "101", "TYPE", "normal", "USERNAME", "user1", "ADDR", "127.0.0.1:1234", "LADDR", "198.0.0.1:6379", "SKIPME", "yes", "MAXAGE", "102", }; Assert.Equal(expected, filter.ToList(true)); } diff --git a/tests/StackExchange.Redis.Tests/ClusterTests.cs b/tests/StackExchange.Redis.Tests/ClusterTests.cs index 535b4a91a..fcab7bb14 100644 --- a/tests/StackExchange.Redis.Tests/ClusterTests.cs +++ b/tests/StackExchange.Redis.Tests/ClusterTests.cs @@ -219,7 +219,8 @@ public void TransactionWithMultiServerKeys() do { y = Guid.NewGuid().ToString(); - } while (--abort > 0 && config.GetBySlot(y) == xNode); + } + while (--abort > 0 && config.GetBySlot(y) == xNode); if (abort == 0) Skip.Inconclusive("failed to find a different node to use"); var yNode = config.GetBySlot(y); Assert.NotNull(yNode); @@ -243,13 +244,13 @@ public void TransactionWithMultiServerKeys() // the rest no longer applies while we are following single-slot rules //// check that everything was aborted - //Assert.False(success, "tran aborted"); - //Assert.True(setX.IsCanceled, "set x cancelled"); - //Assert.True(setY.IsCanceled, "set y cancelled"); - //var existsX = cluster.KeyExistsAsync(x); - //var existsY = cluster.KeyExistsAsync(y); - //Assert.False(cluster.Wait(existsX), "x exists"); - //Assert.False(cluster.Wait(existsY), "y exists"); + // Assert.False(success, "tran aborted"); + // Assert.True(setX.IsCanceled, "set x cancelled"); + // Assert.True(setY.IsCanceled, "set y cancelled"); + // var existsX = cluster.KeyExistsAsync(x); + // var existsY = cluster.KeyExistsAsync(y); + // Assert.False(cluster.Wait(existsX), "x exists"); + // Assert.False(cluster.Wait(existsY), "y exists"); }); Assert.Equal("Multi-key operations must involve a single slot; keys can use 'hash tags' to help this, i.e. '{/users/12345}/account' and '{/users/12345}/contacts' will always be in the same slot", ex.Message); } @@ -274,7 +275,8 @@ public void TransactionWithSameServerKeys() do { y = Guid.NewGuid().ToString(); - } while (--abort > 0 && config.GetBySlot(y) != xNode); + } + while (--abort > 0 && config.GetBySlot(y) != xNode); if (abort == 0) Skip.Inconclusive("failed to find a key with the same node to use"); var yNode = config.GetBySlot(y); Assert.NotNull(xNode); @@ -299,13 +301,13 @@ public void TransactionWithSameServerKeys() // the rest no longer applies while we are following single-slot rules //// check that everything was aborted - //Assert.True(success, "tran aborted"); - //Assert.False(setX.IsCanceled, "set x cancelled"); - //Assert.False(setY.IsCanceled, "set y cancelled"); - //var existsX = cluster.KeyExistsAsync(x); - //var existsY = cluster.KeyExistsAsync(y); - //Assert.True(cluster.Wait(existsX), "x exists"); - //Assert.True(cluster.Wait(existsY), "y exists"); + // Assert.True(success, "tran aborted"); + // Assert.False(setX.IsCanceled, "set x cancelled"); + // Assert.False(setY.IsCanceled, "set y cancelled"); + // var existsX = cluster.KeyExistsAsync(x); + // var existsY = cluster.KeyExistsAsync(y); + // Assert.True(cluster.Wait(existsX), "x exists"); + // Assert.True(cluster.Wait(existsY), "y exists"); }); Assert.Equal("Multi-key operations must involve a single slot; keys can use 'hash tags' to help this, i.e. '{/users/12345}/account' and '{/users/12345}/contacts' will always be in the same slot", ex.Message); } @@ -358,7 +360,7 @@ public void TransactionWithSameSlotKeys() } [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "xUnit1004:Test methods should not be skipped", Justification = "Because.")] - [Theory (Skip = "FlushAllDatabases")] + [Theory(Skip = "FlushAllDatabases")] [InlineData(null, 10)] [InlineData(null, 100)] [InlineData("abc", 10)] @@ -624,7 +626,6 @@ public void GroupedQueriesWork() // note it doesn't matter that the data doesn't exist for this; // the point here is that the entire thing *won't work* otherwise, // as per above test - var keys = InventKeys(); using var conn = Create(); @@ -650,7 +651,7 @@ public void GroupedQueriesWork() [Fact] public void MovedProfiling() { - var Key = Me(); + var key = Me(); const string Value = "redirected-value"; var profiler = new ProfilingTests.PerThreadProfiler(); @@ -663,24 +664,24 @@ public void MovedProfiling() var servers = endpoints.Select(e => conn.GetServer(e)); var db = conn.GetDatabase(); - db.KeyDelete(Key); - db.StringSet(Key, Value); + db.KeyDelete(key); + db.StringSet(key, Value); var config = servers.First().ClusterConfiguration; Assert.NotNull(config); - //int slot = conn.HashSlot(Key); - var rightPrimaryNode = config.GetBySlot(Key); + // int slot = conn.HashSlot(Key); + var rightPrimaryNode = config.GetBySlot(key); Assert.NotNull(rightPrimaryNode); Assert.NotNull(rightPrimaryNode.EndPoint); - string? a = (string?)conn.GetServer(rightPrimaryNode.EndPoint).Execute("GET", Key); + string? a = (string?)conn.GetServer(rightPrimaryNode.EndPoint).Execute("GET", key); Assert.Equal(Value, a); // right primary var wrongPrimaryNode = config.Nodes.FirstOrDefault(x => !x.IsReplica && x.NodeId != rightPrimaryNode.NodeId); Assert.NotNull(wrongPrimaryNode); Assert.NotNull(wrongPrimaryNode.EndPoint); - string? b = (string?)conn.GetServer(wrongPrimaryNode.EndPoint).Execute("GET", Key); + string? b = (string?)conn.GetServer(wrongPrimaryNode.EndPoint).Execute("GET", key); Assert.Equal(Value, b); // wrong primary, allow redirect var msgs = profiler.GetSession().FinishProfiling().ToList(); diff --git a/tests/StackExchange.Redis.Tests/CommandTimeoutTests.cs b/tests/StackExchange.Redis.Tests/CommandTimeoutTests.cs index 671345f9f..13125d722 100644 --- a/tests/StackExchange.Redis.Tests/CommandTimeoutTests.cs +++ b/tests/StackExchange.Redis.Tests/CommandTimeoutTests.cs @@ -8,7 +8,7 @@ namespace StackExchange.Redis.Tests; [Collection(NonParallelCollection.Name)] public class CommandTimeoutTests : TestBase { - public CommandTimeoutTests(ITestOutputHelper output) : base (output) { } + public CommandTimeoutTests(ITestOutputHelper output) : base(output) { } [FactLongRunning] public async Task DefaultHeartbeatTimeout() diff --git a/tests/StackExchange.Redis.Tests/ConfigTests.cs b/tests/StackExchange.Redis.Tests/ConfigTests.cs index f93eb176f..2a4b2bc75 100644 --- a/tests/StackExchange.Redis.Tests/ConfigTests.cs +++ b/tests/StackExchange.Redis.Tests/ConfigTests.cs @@ -1,6 +1,4 @@ -using Microsoft.Extensions.Logging.Abstractions; -using StackExchange.Redis.Configuration; -using System; +using System; using System.Globalization; using System.IO; using System.IO.Pipelines; @@ -13,6 +11,8 @@ using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging.Abstractions; +using StackExchange.Redis.Configuration; using Xunit; using Xunit.Abstractions; @@ -24,38 +24,69 @@ public class ConfigTests : TestBase { public ConfigTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - public Version DefaultVersion = new (3, 0, 0); - public Version DefaultAzureVersion = new (4, 0, 0); + public Version DefaultVersion = new(3, 0, 0); + public Version DefaultAzureVersion = new(4, 0, 0); [Fact] public void ExpectedFields() { // if this test fails, check that you've updated ConfigurationOptions.Clone(), then: fix the test! // this is a simple but pragmatic "have you considered?" check - - var fields = Array.ConvertAll(typeof(ConfigurationOptions).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance), + var fields = Array.ConvertAll( + typeof(ConfigurationOptions).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance), x => Regex.Replace(x.Name, """^<(\w+)>k__BackingField$""", "$1")); Array.Sort(fields); - Assert.Equal(new[] { - "abortOnConnectFail", "allowAdmin", "asyncTimeout", "backlogPolicy", "BeforeSocketConnect", - "CertificateSelection", "CertificateValidation", "ChannelPrefix", - "checkCertificateRevocation", "ClientName", "commandMap", - "configChannel", "configCheckSeconds", "connectRetry", - "connectTimeout", "DefaultDatabase", "defaultOptions", - "defaultVersion", "EndPoints", "heartbeatConsistencyChecks", - "heartbeatInterval", "highIntegrity", "includeDetailInExceptions", "includePerformanceCountersInExceptions", - "keepAlive", "LibraryName", "loggerFactory", - "password", "Protocol", "proxy", - "reconnectRetryPolicy", "resolveDns", "responseTimeout", - "ServiceName", "setClientLibrary", "SocketManager", - "ssl", -#if !NETFRAMEWORK - "SslClientAuthenticationOptions", -#endif - "sslHost", "SslProtocols", - "syncTimeout", "tieBreaker", "Tunnel", - "user" - }, fields); + Assert.Equal( + new[] + { + "abortOnConnectFail", + "allowAdmin", + "asyncTimeout", + "backlogPolicy", + "BeforeSocketConnect", + "CertificateSelection", + "CertificateValidation", + "ChannelPrefix", + "checkCertificateRevocation", + "ClientName", + "commandMap", + "configChannel", + "configCheckSeconds", + "connectRetry", + "connectTimeout", + "DefaultDatabase", + "defaultOptions", + "defaultVersion", + "EndPoints", + "heartbeatConsistencyChecks", + "heartbeatInterval", + "highIntegrity", + "includeDetailInExceptions", + "includePerformanceCountersInExceptions", + "keepAlive", + "LibraryName", + "loggerFactory", + "password", + "Protocol", + "proxy", + "reconnectRetryPolicy", + "resolveDns", + "responseTimeout", + "ServiceName", + "setClientLibrary", + "SocketManager", + "ssl", + #if !NETFRAMEWORK + "SslClientAuthenticationOptions", + #endif + "sslHost", + "SslProtocols", + "syncTimeout", + "tieBreaker", + "Tunnel", + "user", + }, + fields); } [Fact] @@ -208,9 +239,9 @@ public void TalkToNonsenseServer() AbortOnConnectFail = false, EndPoints = { - { "127.0.0.1:1234" } + { "127.0.0.1:1234" }, }, - ConnectTimeout = 200 + ConnectTimeout = 200, }; var log = new StringWriter(); using (var conn = ConnectionMultiplexer.Connect(config, log)) @@ -544,7 +575,7 @@ public void ThreadPoolManagerIsDetected() var config = new ConfigurationOptions { EndPoints = { { IPAddress.Loopback, 6379 } }, - SocketManager = SocketManager.ThreadPool + SocketManager = SocketManager.ThreadPool, }; using var conn = ConnectionMultiplexer.Connect(config); @@ -779,6 +810,5 @@ public void CheckHighIntegrity(bool? assigned, bool expected, string cs) var parsed = ConfigurationOptions.Parse(cs); Assert.Equal(expected, options.HighIntegrity); - } } diff --git a/tests/StackExchange.Redis.Tests/ConnectByIPTests.cs b/tests/StackExchange.Redis.Tests/ConnectByIPTests.cs index b79f2e07d..24fc8d44d 100644 --- a/tests/StackExchange.Redis.Tests/ConnectByIPTests.cs +++ b/tests/StackExchange.Redis.Tests/ConnectByIPTests.cs @@ -9,7 +9,7 @@ namespace StackExchange.Redis.Tests; public class ConnectByIPTests : TestBase { - public ConnectByIPTests(ITestOutputHelper output) : base (output) { } + public ConnectByIPTests(ITestOutputHelper output) : base(output) { } [Fact] public void ParseEndpoints() @@ -18,7 +18,7 @@ public void ParseEndpoints() { { "127.0.0.1", 1000 }, { "::1", 1001 }, - { "localhost", 1002 } + { "localhost", 1002 }, }; Assert.Equal(AddressFamily.InterNetwork, eps[0].AddressFamily); @@ -35,7 +35,7 @@ public void IPv4Connection() { var config = new ConfigurationOptions { - EndPoints = { { TestConfig.Current.IPv4Server, TestConfig.Current.IPv4Port } } + EndPoints = { { TestConfig.Current.IPv4Server, TestConfig.Current.IPv4Port } }, }; using var conn = ConnectionMultiplexer.Connect(config); @@ -49,7 +49,7 @@ public void IPv6Connection() { var config = new ConfigurationOptions { - EndPoints = { { TestConfig.Current.IPv6Server, TestConfig.Current.IPv6Port } } + EndPoints = { { TestConfig.Current.IPv6Server, TestConfig.Current.IPv6Port } }, }; using var conn = ConnectionMultiplexer.Connect(config); @@ -65,7 +65,7 @@ public void ConnectByVariousEndpoints(EndPoint ep, AddressFamily expectedFamily) Assert.Equal(expectedFamily, ep.AddressFamily); var config = new ConfigurationOptions { - EndPoints = { ep } + EndPoints = { ep }, }; if (ep.AddressFamily != AddressFamily.InterNetworkV6) // I don't have IPv6 servers { diff --git a/tests/StackExchange.Redis.Tests/ConnectCustomConfigTests.cs b/tests/StackExchange.Redis.Tests/ConnectCustomConfigTests.cs index f0f189372..460f6f6b6 100644 --- a/tests/StackExchange.Redis.Tests/ConnectCustomConfigTests.cs +++ b/tests/StackExchange.Redis.Tests/ConnectCustomConfigTests.cs @@ -7,7 +7,7 @@ namespace StackExchange.Redis.Tests; public class ConnectCustomConfigTests : TestBase { - public ConnectCustomConfigTests(ITestOutputHelper output) : base (output) { } + public ConnectCustomConfigTests(ITestOutputHelper output) : base(output) { } // So we're triggering tiebreakers here protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort + "," + TestConfig.Current.ReplicaServerAndPort; diff --git a/tests/StackExchange.Redis.Tests/ConnectFailTimeoutTests.cs b/tests/StackExchange.Redis.Tests/ConnectFailTimeoutTests.cs index 2b4b5a29f..58d9795bb 100644 --- a/tests/StackExchange.Redis.Tests/ConnectFailTimeoutTests.cs +++ b/tests/StackExchange.Redis.Tests/ConnectFailTimeoutTests.cs @@ -7,7 +7,7 @@ namespace StackExchange.Redis.Tests; public class ConnectFailTimeoutTests : TestBase { - public ConnectFailTimeoutTests(ITestOutputHelper output) : base (output) { } + public ConnectFailTimeoutTests(ITestOutputHelper output) : base(output) { } [Fact] public async Task NoticesConnectFail() @@ -17,8 +17,9 @@ public async Task NoticesConnectFail() var server = conn.GetServer(conn.GetEndPoints()[0]); - await RunBlockingSynchronousWithExtraThreadAsync(innerScenario).ForAwait(); - void innerScenario() + await RunBlockingSynchronousWithExtraThreadAsync(InnerScenario).ForAwait(); + + void InnerScenario() { conn.ConnectionFailed += (s, a) => Log("Disconnected: " + EndPointCollection.ToString(a.EndPoint)); diff --git a/tests/StackExchange.Redis.Tests/ConnectToUnexistingHostTests.cs b/tests/StackExchange.Redis.Tests/ConnectToUnexistingHostTests.cs index a8bfe69b0..d8a942a28 100644 --- a/tests/StackExchange.Redis.Tests/ConnectToUnexistingHostTests.cs +++ b/tests/StackExchange.Redis.Tests/ConnectToUnexistingHostTests.cs @@ -9,7 +9,7 @@ namespace StackExchange.Redis.Tests; public class ConnectToUnexistingHostTests : TestBase { - public ConnectToUnexistingHostTests(ITestOutputHelper output) : base (output) { } + public ConnectToUnexistingHostTests(ITestOutputHelper output) : base(output) { } [Fact] public async Task FailsWithinTimeout() @@ -21,7 +21,7 @@ public async Task FailsWithinTimeout() var config = new ConfigurationOptions { EndPoints = { { "invalid", 1234 } }, - ConnectTimeout = timeout + ConnectTimeout = timeout, }; using (ConnectionMultiplexer.Connect(config, Writer)) @@ -43,8 +43,8 @@ public async Task FailsWithinTimeout() [Fact] public async Task CanNotOpenNonsenseConnection_IP() { - await RunBlockingSynchronousWithExtraThreadAsync(innerScenario).ForAwait(); - void innerScenario() + await RunBlockingSynchronousWithExtraThreadAsync(InnerScenario).ForAwait(); + void InnerScenario() { var ex = Assert.Throws(() => { @@ -67,8 +67,8 @@ public async Task CanNotOpenNonsenseConnection_DNS() [Fact] public async Task CreateDisconnectedNonsenseConnection_IP() { - await RunBlockingSynchronousWithExtraThreadAsync(innerScenario).ForAwait(); - void innerScenario() + await RunBlockingSynchronousWithExtraThreadAsync(InnerScenario).ForAwait(); + void InnerScenario() { using (var conn = ConnectionMultiplexer.Connect(TestConfig.Current.PrimaryServer + ":6500,abortConnect=false,connectTimeout=1000,connectRetry=0", Writer)) { @@ -81,8 +81,8 @@ void innerScenario() [Fact] public async Task CreateDisconnectedNonsenseConnection_DNS() { - await RunBlockingSynchronousWithExtraThreadAsync(innerScenario).ForAwait(); - void innerScenario() + await RunBlockingSynchronousWithExtraThreadAsync(InnerScenario).ForAwait(); + void InnerScenario() { using (var conn = ConnectionMultiplexer.Connect($"doesnot.exist.ds.{Guid.NewGuid():N}.com:6500,abortConnect=false,connectTimeout=1000,connectRetry=0", Writer)) { diff --git a/tests/StackExchange.Redis.Tests/ConnectingFailDetectionTests.cs b/tests/StackExchange.Redis.Tests/ConnectingFailDetectionTests.cs index 7ed717eab..db8d1dd1a 100644 --- a/tests/StackExchange.Redis.Tests/ConnectingFailDetectionTests.cs +++ b/tests/StackExchange.Redis.Tests/ConnectingFailDetectionTests.cs @@ -8,7 +8,7 @@ namespace StackExchange.Redis.Tests; public class ConnectingFailDetectionTests : TestBase { - public ConnectingFailDetectionTests(ITestOutputHelper output) : base (output) { } + public ConnectingFailDetectionTests(ITestOutputHelper output) : base(output) { } protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort + "," + TestConfig.Current.ReplicaServerAndPort; diff --git a/tests/StackExchange.Redis.Tests/ConnectionFailedErrorsTests.cs b/tests/StackExchange.Redis.Tests/ConnectionFailedErrorsTests.cs index 68bc8dc6e..df3802118 100644 --- a/tests/StackExchange.Redis.Tests/ConnectionFailedErrorsTests.cs +++ b/tests/StackExchange.Redis.Tests/ConnectionFailedErrorsTests.cs @@ -10,7 +10,7 @@ namespace StackExchange.Redis.Tests; public class ConnectionFailedErrorsTests : TestBase { - public ConnectionFailedErrorsTests(ITestOutputHelper output) : base (output) { } + public ConnectionFailedErrorsTests(ITestOutputHelper output) : base(output) { } [Theory] [InlineData(true)] @@ -29,14 +29,15 @@ public async Task SSLCertificateValidationError(bool isCertValidationSucceeded) using var conn = ConnectionMultiplexer.Connect(options); - await RunBlockingSynchronousWithExtraThreadAsync(innerScenario).ForAwait(); - void innerScenario() + await RunBlockingSynchronousWithExtraThreadAsync(InnerScenario).ForAwait(); + + void InnerScenario() { conn.ConnectionFailed += (sender, e) => Assert.Equal(ConnectionFailureType.AuthenticationFailure, e.FailureType); if (!isCertValidationSucceeded) { - //validate that in this case it throws an certificatevalidation exception + // Validate that in this case it throws an certificatevalidation exception var outer = Assert.Throws(() => conn.GetDatabase().Ping()); Assert.Equal(ConnectionFailureType.UnableToResolvePhysicalConnection, outer.FailureType); @@ -72,13 +73,13 @@ public async Task AuthenticationFailureError() using var conn = ConnectionMultiplexer.Connect(options); - await RunBlockingSynchronousWithExtraThreadAsync(innerScenario).ForAwait(); - void innerScenario() + await RunBlockingSynchronousWithExtraThreadAsync(InnerScenario).ForAwait(); + void InnerScenario() { conn.ConnectionFailed += (sender, e) => { if (e.FailureType == ConnectionFailureType.SocketFailure) Skip.Inconclusive("socket fail"); // this is OK too - Assert.Equal(ConnectionFailureType.AuthenticationFailure, e.FailureType); + Assert.Equal(ConnectionFailureType.AuthenticationFailure, e.FailureType); }; var ex = Assert.Throws(() => conn.GetDatabase().Ping()); @@ -90,15 +91,15 @@ void innerScenario() Assert.Equal("Error: NOAUTH Authentication required. Verify if the Redis password provided is correct.", rde.InnerException.Message); } - //wait for a second for connectionfailed event to fire + // Wait for a second for connectionfailed event to fire await Task.Delay(1000).ForAwait(); } [Fact] public async Task SocketFailureError() { - await RunBlockingSynchronousWithExtraThreadAsync(innerScenario).ForAwait(); - void innerScenario() + await RunBlockingSynchronousWithExtraThreadAsync(InnerScenario).ForAwait(); + void InnerScenario() { var options = new ConfigurationOptions(); options.EndPoints.Add($"{Guid.NewGuid():N}.redis.cache.windows.net"); @@ -144,8 +145,8 @@ void innerScenario() [Fact] public async Task AbortOnConnectFailFalseConnectTimeoutError() { - await RunBlockingSynchronousWithExtraThreadAsync(innerScenario).ForAwait(); - void innerScenario() + await RunBlockingSynchronousWithExtraThreadAsync(InnerScenario).ForAwait(); + void InnerScenario() { Skip.IfNoConfig(nameof(TestConfig.Config.AzureCacheServer), TestConfig.Current.AzureCacheServer); Skip.IfNoConfig(nameof(TestConfig.Config.AzureCachePassword), TestConfig.Current.AzureCachePassword); diff --git a/tests/StackExchange.Redis.Tests/ConnectionReconnectRetryPolicyTests.cs b/tests/StackExchange.Redis.Tests/ConnectionReconnectRetryPolicyTests.cs index 2ce71f2f7..07e90dabc 100644 --- a/tests/StackExchange.Redis.Tests/ConnectionReconnectRetryPolicyTests.cs +++ b/tests/StackExchange.Redis.Tests/ConnectionReconnectRetryPolicyTests.cs @@ -6,7 +6,7 @@ namespace StackExchange.Redis.Tests; public class TransientErrorTests : TestBase { - public TransientErrorTests(ITestOutputHelper output) : base (output) { } + public TransientErrorTests(ITestOutputHelper output) : base(output) { } [Fact] public void TestExponentialRetry() diff --git a/tests/StackExchange.Redis.Tests/CopyTests.cs b/tests/StackExchange.Redis.Tests/CopyTests.cs index 20a43d1df..b40f00c02 100644 --- a/tests/StackExchange.Redis.Tests/CopyTests.cs +++ b/tests/StackExchange.Redis.Tests/CopyTests.cs @@ -8,7 +8,7 @@ namespace StackExchange.Redis.Tests; [Collection(SharedConnectionFixture.Key)] public class CopyTests : TestBase { - public CopyTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base (output, fixture) { } + public CopyTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } [Fact] public async Task Basic() diff --git a/tests/StackExchange.Redis.Tests/ExceptionFactoryTests.cs b/tests/StackExchange.Redis.Tests/ExceptionFactoryTests.cs index 1922c3edf..2edee05c6 100644 --- a/tests/StackExchange.Redis.Tests/ExceptionFactoryTests.cs +++ b/tests/StackExchange.Redis.Tests/ExceptionFactoryTests.cs @@ -6,7 +6,7 @@ namespace StackExchange.Redis.Tests; public class ExceptionFactoryTests : TestBase { - public ExceptionFactoryTests(ITestOutputHelper output) : base (output) { } + public ExceptionFactoryTests(ITestOutputHelper output) : base(output) { } [Fact] public void NullLastException() @@ -163,7 +163,7 @@ public void NoConnectionException(bool abortOnConnect, int connCount, int comple BacklogPolicy = BacklogPolicy.FailFast, ConnectTimeout = 1000, SyncTimeout = 500, - KeepAlive = 5000 + KeepAlive = 5000, }; ConnectionMultiplexer conn; diff --git a/tests/StackExchange.Redis.Tests/ExpiryTests.cs b/tests/StackExchange.Redis.Tests/ExpiryTests.cs index d69ab53d5..3d11442e6 100644 --- a/tests/StackExchange.Redis.Tests/ExpiryTests.cs +++ b/tests/StackExchange.Redis.Tests/ExpiryTests.cs @@ -8,9 +8,9 @@ namespace StackExchange.Redis.Tests; [Collection(SharedConnectionFixture.Key)] public class ExpiryTests : TestBase { - public ExpiryTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base (output, fixture) { } + public ExpiryTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - private static string[]? GetMap(bool disablePTimes) => disablePTimes ? (new[] { "pexpire", "pexpireat", "pttl" }) : null; + private static string[]? GetMap(bool disablePTimes) => disablePTimes ? new[] { "pexpire", "pexpireat", "pttl" } : null; [Theory] [InlineData(true)] diff --git a/tests/StackExchange.Redis.Tests/FSharpCompatTests.cs b/tests/StackExchange.Redis.Tests/FSharpCompatTests.cs index 7539c1198..7b39d36b9 100644 --- a/tests/StackExchange.Redis.Tests/FSharpCompatTests.cs +++ b/tests/StackExchange.Redis.Tests/FSharpCompatTests.cs @@ -5,8 +5,9 @@ namespace StackExchange.Redis.Tests; public class FSharpCompatTests : TestBase { - public FSharpCompatTests(ITestOutputHelper output) : base (output) { } + public FSharpCompatTests(ITestOutputHelper output) : base(output) { } +#pragma warning disable SA1129 // Do not use default value type constructor [Fact] public void RedisKeyConstructor() { @@ -22,4 +23,5 @@ public void RedisValueConstructor() Assert.Equal((RedisValue)"MyKey", new RedisValue("MyKey")); Assert.Equal((RedisValue)"MyKey2", new RedisValue("MyKey2", 0)); } +#pragma warning restore SA1129 // Do not use default value type constructor } diff --git a/tests/StackExchange.Redis.Tests/FailoverTests.cs b/tests/StackExchange.Redis.Tests/FailoverTests.cs index 2449e6a4b..e40d12a14 100644 --- a/tests/StackExchange.Redis.Tests/FailoverTests.cs +++ b/tests/StackExchange.Redis.Tests/FailoverTests.cs @@ -47,7 +47,7 @@ private static ConfigurationOptions GetPrimaryReplicaConfig() { { TestConfig.Current.FailoverPrimaryServer, TestConfig.Current.FailoverPrimaryPort }, { TestConfig.Current.FailoverReplicaServer, TestConfig.Current.FailoverReplicaPort }, - } + }, }; } @@ -136,8 +136,8 @@ public async Task DereplicateGoesToPrimary() bool isUnanimous = log.Contains("tie-break is unanimous at " + TestConfig.Current.FailoverPrimaryServerAndPort); if (!isUnanimous) Skip.Inconclusive("this is timing sensitive; unable to verify this time"); } - // k, so we know everyone loves 6379; is that what we get? + // k, so we know everyone loves 6379; is that what we get? var db = conn.GetDatabase(); RedisKey key = Me(); diff --git a/tests/StackExchange.Redis.Tests/FloatingPointTests.cs b/tests/StackExchange.Redis.Tests/FloatingPointTests.cs index 6a7158fe3..71bab0386 100644 --- a/tests/StackExchange.Redis.Tests/FloatingPointTests.cs +++ b/tests/StackExchange.Redis.Tests/FloatingPointTests.cs @@ -8,7 +8,7 @@ namespace StackExchange.Redis.Tests; [Collection(SharedConnectionFixture.Key)] public class FloatingPointTests : TestBase { - public FloatingPointTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base (output, fixture) { } + public FloatingPointTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } private static bool Within(double x, double y, double delta) => Math.Abs(x - y) <= delta; @@ -22,16 +22,17 @@ public void IncrDecrFloatingPoint() db.KeyDelete(key, CommandFlags.FireAndForget); double[] incr = { - 12.134, - -14561.0000002, - 125.3421, - -2.49892498 - }, decr = - { - 99.312, - 12, - -35 - }; + 12.134, + -14561.0000002, + 125.3421, + -2.49892498, + }, + decr = + { + 99.312, + 12, + -35, + }; double sum = 0; foreach (var value in incr) { @@ -58,16 +59,17 @@ public async Task IncrDecrFloatingPointAsync() db.KeyDelete(key, CommandFlags.FireAndForget); double[] incr = { - 12.134, - -14561.0000002, - 125.3421, - -2.49892498 - }, decr = - { - 99.312, - 12, - -35 - }; + 12.134, + -14561.0000002, + 125.3421, + -2.49892498, + }, + decr = + { + 99.312, + 12, + -35, + }; double sum = 0; foreach (var value in incr) { @@ -95,16 +97,17 @@ public void HashIncrDecrFloatingPoint() db.KeyDelete(key, CommandFlags.FireAndForget); double[] incr = { - 12.134, - -14561.0000002, - 125.3421, - -2.49892498 - }, decr = - { - 99.312, - 12, - -35 - }; + 12.134, + -14561.0000002, + 125.3421, + -2.49892498, + }, + decr = + { + 99.312, + 12, + -35, + }; double sum = 0; foreach (var value in incr) { @@ -132,16 +135,17 @@ public async Task HashIncrDecrFloatingPointAsync() db.KeyDelete(key, CommandFlags.FireAndForget); double[] incr = { - 12.134, - -14561.0000002, - 125.3421, - -2.49892498 - }, decr = - { - 99.312, - 12, - -35 - }; + 12.134, + -14561.0000002, + 125.3421, + -2.49892498, + }, + decr = + { + 99.312, + 12, + -35, + }; double sum = 0; foreach (var value in incr) { diff --git a/tests/StackExchange.Redis.Tests/FormatTests.cs b/tests/StackExchange.Redis.Tests/FormatTests.cs index bb2f18740..8b3c152ed 100644 --- a/tests/StackExchange.Redis.Tests/FormatTests.cs +++ b/tests/StackExchange.Redis.Tests/FormatTests.cs @@ -81,7 +81,6 @@ public void ClientFlagsFormatting(ClientFlags value, string expected) public void ReplicationChangeOptionsFormatting(ReplicationChangeOptions value, string expected) => Assert.Equal(expected, value.ToString()); - [Theory] [InlineData(0, "0")] [InlineData(1, "1")] diff --git a/tests/StackExchange.Redis.Tests/GarbageCollectionTests.cs b/tests/StackExchange.Redis.Tests/GarbageCollectionTests.cs index 42a132835..8a263c553 100644 --- a/tests/StackExchange.Redis.Tests/GarbageCollectionTests.cs +++ b/tests/StackExchange.Redis.Tests/GarbageCollectionTests.cs @@ -35,9 +35,9 @@ public async Task MuxerIsCollected() ForceGC(); -//#if DEBUG // this counter only exists in debug +// #if DEBUG // this counter only exists in debug // int before = ConnectionMultiplexer.CollectedWithoutDispose; -//#endif +// #endif var wr = new WeakReference(conn); conn = null; @@ -48,10 +48,10 @@ public async Task MuxerIsCollected() // should be collectable Assert.Null(wr.Target); -//#if DEBUG // this counter only exists in debug +// #if DEBUG // this counter only exists in debug // int after = ConnectionMultiplexer.CollectedWithoutDispose; // Assert.Equal(before + 1, after); -//#endif +// #endif } [Fact] @@ -64,15 +64,17 @@ public async Task UnrootedBackloggedAsyncTaskIsCompletedOnTimeout() Task? completedTestTask = null; _ = Task.Run(async () => { - using var conn = await ConnectionMultiplexer.ConnectAsync(new ConfigurationOptions() - { - BacklogPolicy = BacklogPolicy.Default, - AbortOnConnectFail = false, - ConnectTimeout = 50, - SyncTimeout = 1000, - AllowAdmin = true, - EndPoints = { GetConfiguration() }, - }, Writer); + using var conn = await ConnectionMultiplexer.ConnectAsync( + new ConfigurationOptions() + { + BacklogPolicy = BacklogPolicy.Default, + AbortOnConnectFail = false, + ConnectTimeout = 50, + SyncTimeout = 1000, + AllowAdmin = true, + EndPoints = { GetConfiguration() }, + }, + Writer); var db = conn.GetDatabase(); // Disconnect and don't allow re-connection diff --git a/tests/StackExchange.Redis.Tests/GeoTests.cs b/tests/StackExchange.Redis.Tests/GeoTests.cs index f1be0bad1..84fa30386 100644 --- a/tests/StackExchange.Redis.Tests/GeoTests.cs +++ b/tests/StackExchange.Redis.Tests/GeoTests.cs @@ -1,7 +1,7 @@ -using Xunit; -using System; -using Xunit.Abstractions; +using System; using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; namespace StackExchange.Redis.Tests; @@ -9,14 +9,15 @@ namespace StackExchange.Redis.Tests; [Collection(SharedConnectionFixture.Key)] public class GeoTests : TestBase { - public GeoTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base (output, fixture) { } + public GeoTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } private static readonly GeoEntry - palermo = new GeoEntry(13.361389, 38.115556, "Palermo"), - catania = new GeoEntry(15.087269, 37.502669, "Catania"), - agrigento = new GeoEntry(13.5765, 37.311, "Agrigento"), - cefalù = new GeoEntry(14.0188, 38.0084, "Cefalù"); - private static readonly GeoEntry[] all = { palermo, catania, agrigento, cefalù }; + Palermo = new GeoEntry(13.361389, 38.115556, "Palermo"), + Catania = new GeoEntry(15.087269, 37.502669, "Catania"), + Agrigento = new GeoEntry(13.5765, 37.311, "Agrigento"), + Cefalù = new GeoEntry(14.0188, 38.0084, "Cefalù"); + + private static readonly GeoEntry[] All = { Palermo, Catania, Agrigento, Cefalù }; [Fact] public void GeoAdd() @@ -28,20 +29,20 @@ public void GeoAdd() db.KeyDelete(key, CommandFlags.FireAndForget); // add while not there - Assert.True(db.GeoAdd(key, cefalù.Longitude, cefalù.Latitude, cefalù.Member)); - Assert.Equal(2, db.GeoAdd(key, new[] { palermo, catania })); - Assert.True(db.GeoAdd(key, agrigento)); + Assert.True(db.GeoAdd(key, Cefalù.Longitude, Cefalù.Latitude, Cefalù.Member)); + Assert.Equal(2, db.GeoAdd(key, new[] { Palermo, Catania })); + Assert.True(db.GeoAdd(key, Agrigento)); // now add again - Assert.False(db.GeoAdd(key, cefalù.Longitude, cefalù.Latitude, cefalù.Member)); - Assert.Equal(0, db.GeoAdd(key, new[] { palermo, catania })); - Assert.False(db.GeoAdd(key, agrigento)); + Assert.False(db.GeoAdd(key, Cefalù.Longitude, Cefalù.Latitude, Cefalù.Member)); + Assert.Equal(0, db.GeoAdd(key, new[] { Palermo, Catania })); + Assert.False(db.GeoAdd(key, Agrigento)); // Validate - var pos = db.GeoPosition(key, palermo.Member); + var pos = db.GeoPosition(key, Palermo.Member); Assert.NotNull(pos); - Assert.Equal(palermo.Longitude, pos!.Value.Longitude, 5); - Assert.Equal(palermo.Latitude, pos!.Value.Latitude, 5); + Assert.Equal(Palermo.Longitude, pos!.Value.Longitude, 5); + Assert.Equal(Palermo.Latitude, pos!.Value.Latitude, 5); } [Fact] @@ -52,7 +53,7 @@ public void GetDistance() var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - db.GeoAdd(key, all, CommandFlags.FireAndForget); + db.GeoAdd(key, All, CommandFlags.FireAndForget); var val = db.GeoDistance(key, "Palermo", "Catania", GeoUnit.Meters); Assert.True(val.HasValue); Assert.Equal(166274.1516, val); @@ -69,9 +70,9 @@ public void GeoHash() var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - db.GeoAdd(key, all, CommandFlags.FireAndForget); + db.GeoAdd(key, All, CommandFlags.FireAndForget); - var hashes = db.GeoHash(key, new RedisValue[] { palermo.Member, "Nowhere", agrigento.Member }); + var hashes = db.GeoHash(key, new RedisValue[] { Palermo.Member, "Nowhere", Agrigento.Member }); Assert.NotNull(hashes); Assert.Equal(3, hashes.Length); Assert.Equal("sqc8b49rny0", hashes[0]); @@ -93,12 +94,12 @@ public void GeoGetPosition() var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - db.GeoAdd(key, all, CommandFlags.FireAndForget); + db.GeoAdd(key, All, CommandFlags.FireAndForget); - var pos = db.GeoPosition(key, palermo.Member); + var pos = db.GeoPosition(key, Palermo.Member); Assert.True(pos.HasValue); - Assert.Equal(Math.Round(palermo.Longitude, 6), Math.Round(pos.Value.Longitude, 6)); - Assert.Equal(Math.Round(palermo.Latitude, 6), Math.Round(pos.Value.Latitude, 6)); + Assert.Equal(Math.Round(Palermo.Longitude, 6), Math.Round(pos.Value.Longitude, 6)); + Assert.Equal(Math.Round(Palermo.Latitude, 6), Math.Round(pos.Value.Latitude, 6)); pos = db.GeoPosition(key, "Nowhere"); Assert.False(pos.HasValue); @@ -112,7 +113,7 @@ public void GeoRemove() var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - db.GeoAdd(key, all, CommandFlags.FireAndForget); + db.GeoAdd(key, All, CommandFlags.FireAndForget); var pos = db.GeoPosition(key, "Palermo"); Assert.True(pos.HasValue); @@ -133,37 +134,37 @@ public void GeoRadius() var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - db.GeoAdd(key, all, CommandFlags.FireAndForget); + db.GeoAdd(key, All, CommandFlags.FireAndForget); - var results = db.GeoRadius(key, cefalù.Member, 60, GeoUnit.Miles, 2, Order.Ascending); + var results = db.GeoRadius(key, Cefalù.Member, 60, GeoUnit.Miles, 2, Order.Ascending); Assert.Equal(2, results.Length); - Assert.Equal(results[0].Member, cefalù.Member); + Assert.Equal(results[0].Member, Cefalù.Member); Assert.Equal(0, results[0].Distance); var position0 = results[0].Position; Assert.NotNull(position0); - Assert.Equal(Math.Round(position0!.Value.Longitude, 5), Math.Round(cefalù.Position.Longitude, 5)); - Assert.Equal(Math.Round(position0!.Value.Latitude, 5), Math.Round(cefalù.Position.Latitude, 5)); + Assert.Equal(Math.Round(position0!.Value.Longitude, 5), Math.Round(Cefalù.Position.Longitude, 5)); + Assert.Equal(Math.Round(position0!.Value.Latitude, 5), Math.Round(Cefalù.Position.Latitude, 5)); Assert.False(results[0].Hash.HasValue); - Assert.Equal(results[1].Member, palermo.Member); + Assert.Equal(results[1].Member, Palermo.Member); var distance1 = results[1].Distance; Assert.NotNull(distance1); Assert.Equal(Math.Round(36.5319, 6), Math.Round(distance1!.Value, 6)); var position1 = results[1].Position; Assert.NotNull(position1); - Assert.Equal(Math.Round(position1!.Value.Longitude, 5), Math.Round(palermo.Position.Longitude, 5)); - Assert.Equal(Math.Round(position1!.Value.Latitude, 5), Math.Round(palermo.Position.Latitude, 5)); + Assert.Equal(Math.Round(position1!.Value.Longitude, 5), Math.Round(Palermo.Position.Longitude, 5)); + Assert.Equal(Math.Round(position1!.Value.Latitude, 5), Math.Round(Palermo.Position.Latitude, 5)); Assert.False(results[1].Hash.HasValue); - results = db.GeoRadius(key, cefalù.Member, 60, GeoUnit.Miles, 2, Order.Ascending, GeoRadiusOptions.None); + results = db.GeoRadius(key, Cefalù.Member, 60, GeoUnit.Miles, 2, Order.Ascending, GeoRadiusOptions.None); Assert.Equal(2, results.Length); - Assert.Equal(results[0].Member, cefalù.Member); + Assert.Equal(results[0].Member, Cefalù.Member); Assert.False(results[0].Position.HasValue); Assert.False(results[0].Distance.HasValue); Assert.False(results[0].Hash.HasValue); - Assert.Equal(results[1].Member, palermo.Member); + Assert.Equal(results[1].Member, Palermo.Member); Assert.False(results[1].Position.HasValue); Assert.False(results[1].Distance.HasValue); Assert.False(results[1].Hash.HasValue); @@ -622,7 +623,6 @@ public void GeoSearchBadArgs() var exception = Assert.Throws(() => db.GeoSearch(key, "irrelevant", circle, demandClosest: false)); - Assert.Contains("demandClosest must be true if you are not limiting the count for a GEOSEARCH", - exception.Message); + Assert.Contains("demandClosest must be true if you are not limiting the count for a GEOSEARCH", exception.Message); } } diff --git a/tests/StackExchange.Redis.Tests/GlobalSuppressions.cs b/tests/StackExchange.Redis.Tests/GlobalSuppressions.cs index 503124c7d..05be64b21 100644 --- a/tests/StackExchange.Redis.Tests/GlobalSuppressions.cs +++ b/tests/StackExchange.Redis.Tests/GlobalSuppressions.cs @@ -1,22 +1,21 @@ - -// This file is used by Code Analysis to maintain SuppressMessage +// This file is used by Code Analysis to maintain SuppressMessage // attributes that are applied to this project. -// Project-level suppressions either have no target or are given +// Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. using System.Diagnostics.CodeAnalysis; -[assembly: SuppressMessage("Redundancy", "RCS1163:Unused parameter.", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.Tests.ConnectionFailedErrorsTests.SSLCertificateValidationError(System.Boolean)")] -[assembly: SuppressMessage("Redundancy", "RCS1163:Unused parameter.", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.Tests.PubSubTests.ExplicitPublishMode")] -[assembly: SuppressMessage("Redundancy", "RCS1163:Unused parameter.", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SSLTests.ConnectToSSLServer(System.Boolean,System.Boolean)")] -[assembly: SuppressMessage("Redundancy", "RCS1163:Unused parameter.", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SSLTests.ShowCertFailures(StackExchange.Redis.Tests.Helpers.TextWriterOutputHelper)~System.Net.Security.RemoteCertificateValidationCallback")] -[assembly: SuppressMessage("Usage", "xUnit1004:Test methods should not be skipped", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.Tests.ConnectionShutdownTests.ShutdownRaisesConnectionFailedAndRestore")] -[assembly: SuppressMessage("Usage", "xUnit1004:Test methods should not be skipped", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.Tests.Issues.BgSaveResponseTests.ShouldntThrowException(StackExchange.Redis.SaveType)")] -[assembly: SuppressMessage("Roslynator", "RCS1077:Optimize LINQ method call.", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SentinelTests.PrimaryConnectTest~System.Threading.Tasks.Task")] -[assembly: SuppressMessage("Roslynator", "RCS1077:Optimize LINQ method call.", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SentinelTests.PrimaryConnectAsyncTest~System.Threading.Tasks.Task")] -[assembly: SuppressMessage("Roslynator", "RCS1077:Optimize LINQ method call.", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SentinelBase.WaitForReplicationAsync(StackExchange.Redis.IServer,System.Nullable{System.TimeSpan})~System.Threading.Tasks.Task")] -[assembly: SuppressMessage("Roslynator", "RCS1077:Optimize LINQ method call.", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SentinelFailoverTests.ManagedPrimaryConnectionEndToEndWithFailoverTest~System.Threading.Tasks.Task")] -[assembly: SuppressMessage("Performance", "CA1846:Prefer 'AsSpan' over 'Substring'", Justification = "", Scope = "member", Target = "~M:RedisSharp.Redis.ReadData~System.Byte[]")] -[assembly: SuppressMessage("Style", "IDE0066:Convert switch statement to expression", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.Tests.NamingTests.IgnoreMethodConventions(System.Reflection.MethodInfo)~System.Boolean")] -[assembly: SuppressMessage("Roslynator", "RCS1075:Avoid empty catch clause that catches System.Exception.", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SentinelBase.WaitForReadyAsync(System.Net.EndPoint,System.Boolean,System.Nullable{System.TimeSpan})~System.Threading.Tasks.Task")] -[assembly: SuppressMessage("Roslynator", "RCS1075:Avoid empty catch clause that catches System.Exception.", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SentinelBase.WaitForRoleAsync(StackExchange.Redis.IServer,System.String,System.Nullable{System.TimeSpan})~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Redundancy", "RCS1163:Unused parameter.", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.Tests.ConnectionFailedErrorsTests.SSLCertificateValidationError(System.Boolean)")] +[assembly: SuppressMessage("Redundancy", "RCS1163:Unused parameter.", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.Tests.PubSubTests.ExplicitPublishMode")] +[assembly: SuppressMessage("Redundancy", "RCS1163:Unused parameter.", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SSLTests.ConnectToSSLServer(System.Boolean,System.Boolean)")] +[assembly: SuppressMessage("Redundancy", "RCS1163:Unused parameter.", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SSLTests.ShowCertFailures(StackExchange.Redis.Tests.Helpers.TextWriterOutputHelper)~System.Net.Security.RemoteCertificateValidationCallback")] +[assembly: SuppressMessage("Usage", "xUnit1004:Test methods should not be skipped", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.Tests.ConnectionShutdownTests.ShutdownRaisesConnectionFailedAndRestore")] +[assembly: SuppressMessage("Usage", "xUnit1004:Test methods should not be skipped", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.Tests.Issues.BgSaveResponseTests.ShouldntThrowException(StackExchange.Redis.SaveType)")] +[assembly: SuppressMessage("Roslynator", "RCS1077:Optimize LINQ method call.", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SentinelTests.PrimaryConnectTest~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Roslynator", "RCS1077:Optimize LINQ method call.", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SentinelTests.PrimaryConnectAsyncTest~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Roslynator", "RCS1077:Optimize LINQ method call.", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SentinelBase.WaitForReplicationAsync(StackExchange.Redis.IServer,System.Nullable{System.TimeSpan})~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Roslynator", "RCS1077:Optimize LINQ method call.", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SentinelFailoverTests.ManagedPrimaryConnectionEndToEndWithFailoverTest~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1846:Prefer 'AsSpan' over 'Substring'", Justification = "Pending", Scope = "member", Target = "~M:RedisSharp.Redis.ReadData~System.Byte[]")] +[assembly: SuppressMessage("Style", "IDE0066:Convert switch statement to expression", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.Tests.NamingTests.IgnoreMethodConventions(System.Reflection.MethodInfo)~System.Boolean")] +[assembly: SuppressMessage("Roslynator", "RCS1075:Avoid empty catch clause that catches System.Exception.", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SentinelBase.WaitForReadyAsync(System.Net.EndPoint,System.Boolean,System.Nullable{System.TimeSpan})~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Roslynator", "RCS1075:Avoid empty catch clause that catches System.Exception.", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.Tests.SentinelBase.WaitForRoleAsync(StackExchange.Redis.IServer,System.String,System.Nullable{System.TimeSpan})~System.Threading.Tasks.Task")] diff --git a/tests/StackExchange.Redis.Tests/HashTests.cs b/tests/StackExchange.Redis.Tests/HashTests.cs index 34a2d12c1..31f3fa9f6 100644 --- a/tests/StackExchange.Redis.Tests/HashTests.cs +++ b/tests/StackExchange.Redis.Tests/HashTests.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; -using System.Text; using System.Linq; +using System.Text; +using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; -using System.Threading.Tasks; namespace StackExchange.Redis.Tests; @@ -576,10 +576,11 @@ public void TestSetPairs() var result0 = db.HashGetAllAsync(hashkey); - var data = new[] { - new HashEntry("foo", Encoding.UTF8.GetBytes("abc")), - new HashEntry("bar", Encoding.UTF8.GetBytes("def")) - }; + var data = new[] + { + new HashEntry("foo", Encoding.UTF8.GetBytes("abc")), + new HashEntry("bar", Encoding.UTF8.GetBytes("def")), + }; db.HashSetAsync(hashkey, data).ForAwait(); var result1 = db.Wait(db.HashGetAllAsync(hashkey)); diff --git a/tests/StackExchange.Redis.Tests/Helpers/Attributes.cs b/tests/StackExchange.Redis.Tests/Helpers/Attributes.cs index 6b72b659e..1fab56cbb 100644 --- a/tests/StackExchange.Redis.Tests/Helpers/Attributes.cs +++ b/tests/StackExchange.Redis.Tests/Helpers/Attributes.cs @@ -101,7 +101,7 @@ public class SkippableTestCase : XunitTestCase, IRedisTest { RedisProtocol.Resp2 => "RESP2", RedisProtocol.Resp3 => "RESP3", - _ => "UnknownProtocolFixMeeeeee" + _ => "UnknownProtocolFixMeeeeee", }; protected override string GetUniqueID() => base.GetUniqueID() + ProtocolString; diff --git a/tests/StackExchange.Redis.Tests/Helpers/SharedConnectionFixture.cs b/tests/StackExchange.Redis.Tests/Helpers/SharedConnectionFixture.cs index 1d7396033..ae48ff676 100644 --- a/tests/StackExchange.Redis.Tests/Helpers/SharedConnectionFixture.cs +++ b/tests/StackExchange.Redis.Tests/Helpers/SharedConnectionFixture.cs @@ -29,8 +29,7 @@ public SharedConnectionFixture() output: null, clientName: nameof(SharedConnectionFixture), configuration: Configuration, - allowAdmin: true - ); + allowAdmin: true); _actualConnection.InternalError += OnInternalError; _actualConnection.ConnectionFailed += OnConnectionFailed; } @@ -43,7 +42,8 @@ internal IInternalConnectionMultiplexer GetConnection(TestBase obj, RedisProtoco { ref NonDisposingConnection? field = ref protocol == RedisProtocol.Resp3 ? ref resp3 : ref resp2; if (field is { IsConnected: false }) - { // abandon memoized connection if disconnected + { + // abandon memoized connection if disconnected var muxer = field.UnderlyingMultiplexer; field = null; muxer.Dispose(); @@ -271,7 +271,7 @@ public void Teardown(TextWriter output) } privateExceptions.Clear(); } - //Assert.True(false, $"There were {privateFailCount} private ambient exceptions."); + // Assert.True(false, $"There were {privateFailCount} private ambient exceptions."); } if (_actualConnection != null) diff --git a/tests/StackExchange.Redis.Tests/Helpers/TestConfig.cs b/tests/StackExchange.Redis.Tests/Helpers/TestConfig.cs index 6c86e10ab..fafb30543 100644 --- a/tests/StackExchange.Redis.Tests/Helpers/TestConfig.cs +++ b/tests/StackExchange.Redis.Tests/Helpers/TestConfig.cs @@ -1,9 +1,9 @@ -using System.IO; -using System; -using Newtonsoft.Json; -using System.Threading; +using System; +using System.IO; using System.Linq; using System.Net.Sockets; +using System.Threading; +using Newtonsoft.Json; namespace StackExchange.Redis.Tests; diff --git a/tests/StackExchange.Redis.Tests/Helpers/redis-sharp.cs b/tests/StackExchange.Redis.Tests/Helpers/redis-sharp.cs index 50fd6bbc8..fd614fa93 100644 --- a/tests/StackExchange.Redis.Tests/Helpers/redis-sharp.cs +++ b/tests/StackExchange.Redis.Tests/Helpers/redis-sharp.cs @@ -30,7 +30,10 @@ public class Redis : IDisposable public enum KeyType { - None, String, List, Set + None, + String, + List, + Set, } public class ResponseException : Exception @@ -217,7 +220,7 @@ private void Connect() socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { NoDelay = true, - SendTimeout = SendTimeout + SendTimeout = SendTimeout, }; socket.Connect(Host, Port); if (!socket.Connected) @@ -232,7 +235,7 @@ private void Connect() SendExpectSuccess("AUTH {0}\r\n", Password); } - private readonly byte[] end_data = new byte[] { (byte)'\r', (byte)'\n' }; + private readonly byte[] endData = new byte[] { (byte)'\r', (byte)'\n' }; private bool SendDataCommand(byte[] data, string cmd, params object[] args) { @@ -250,7 +253,7 @@ private bool SendDataCommand(byte[] data, string cmd, params object[] args) if (data != null) { socket.Send(data); - socket.Send(end_data); + socket.Send(endData); } } catch (SocketException) @@ -380,9 +383,7 @@ private string SendExpectString(string cmd, params object[] args) throw new ResponseException("Unknown reply on integer request: " + c + s); } - // // This one does not throw errors - // private string SendGetString(string cmd, params object[] args) { if (!SendCommand(cmd, args)) @@ -435,7 +436,7 @@ private byte[] ReadData() throw new ResponseException("Invalid length"); } - //returns the number of matches + // returns the number of matches if (c == '*') { if (int.TryParse(r.Substring(1), out int n)) diff --git a/tests/StackExchange.Redis.Tests/InfoReplicationCheckTests.cs b/tests/StackExchange.Redis.Tests/InfoReplicationCheckTests.cs index b0311a7f1..547d3cc88 100644 --- a/tests/StackExchange.Redis.Tests/InfoReplicationCheckTests.cs +++ b/tests/StackExchange.Redis.Tests/InfoReplicationCheckTests.cs @@ -7,7 +7,7 @@ namespace StackExchange.Redis.Tests; public class InfoReplicationCheckTests : TestBase { protected override string GetConfiguration() => base.GetConfiguration() + ",configCheckSeconds=2"; - public InfoReplicationCheckTests(ITestOutputHelper output) : base (output) { } + public InfoReplicationCheckTests(ITestOutputHelper output) : base(output) { } [Fact] public async Task Exec() diff --git a/tests/StackExchange.Redis.Tests/Issues/BgSaveResponseTests.cs b/tests/StackExchange.Redis.Tests/Issues/BgSaveResponseTests.cs index a7bcfc737..2b4a8797e 100644 --- a/tests/StackExchange.Redis.Tests/Issues/BgSaveResponseTests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/BgSaveResponseTests.cs @@ -6,17 +6,17 @@ namespace StackExchange.Redis.Tests.Issues; public class BgSaveResponseTests : TestBase { - public BgSaveResponseTests(ITestOutputHelper output) : base (output) { } + public BgSaveResponseTests(ITestOutputHelper output) : base(output) { } - [Theory (Skip = "We don't need to test this, and it really screws local testing hard.")] + [Theory(Skip = "We don't need to test this, and it really screws local testing hard.")] [InlineData(SaveType.BackgroundSave)] [InlineData(SaveType.BackgroundRewriteAppendOnlyFile)] public async Task ShouldntThrowException(SaveType saveType) { using var conn = Create(allowAdmin: true); - var Server = GetServer(conn); - Server.Save(saveType); + var server = GetServer(conn); + server.Save(saveType); await Task.Delay(1000); } } diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue182Tests.cs b/tests/StackExchange.Redis.Tests/Issues/Issue182Tests.cs index 1f8837d0b..396b40b5f 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue182Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue182Tests.cs @@ -10,7 +10,7 @@ public class Issue182Tests : TestBase { protected override string GetConfiguration() => $"{TestConfig.Current.PrimaryServerAndPort},responseTimeout=10000"; - public Issue182Tests(ITestOutputHelper output) : base (output) { } + public Issue182Tests(ITestOutputHelper output) : base(output) { } [FactLongRunning] public async Task SetMembers() diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue2176Tests.cs b/tests/StackExchange.Redis.Tests/Issues/Issue2176Tests.cs index acfa67bb8..6ec0b86f5 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue2176Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue2176Tests.cs @@ -29,8 +29,7 @@ public void Execute_Batch() var tasks = new List(); var batch = db.CreateBatch(); tasks.Add(batch.SortedSetAddAsync(key2, "a", 4567)); - tasks.Add(batch.SortedSetCombineAndStoreAsync(SetOperation.Intersect, - keyIntersect, new RedisKey[] { key, key2 })); + tasks.Add(batch.SortedSetCombineAndStoreAsync(SetOperation.Intersect, keyIntersect, new RedisKey[] { key, key2 })); var rangeByRankTask = batch.SortedSetRangeByRankAsync(keyIntersect); tasks.Add(rangeByRankTask); batch.Execute(); @@ -64,8 +63,7 @@ public void Execute_Transaction() var tasks = new List(); var batch = db.CreateTransaction(); tasks.Add(batch.SortedSetAddAsync(key2, "a", 4567)); - tasks.Add(batch.SortedSetCombineAndStoreAsync(SetOperation.Intersect, - keyIntersect, new RedisKey[] { key, key2 })); + tasks.Add(batch.SortedSetCombineAndStoreAsync(SetOperation.Intersect, keyIntersect, new RedisKey[] { key, key2 })); var rangeByRankTask = batch.SortedSetRangeByRankAsync(keyIntersect); tasks.Add(rangeByRankTask); batch.Execute(); diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue2418.cs b/tests/StackExchange.Redis.Tests/Issues/Issue2418.cs index 4fc034843..a22bbbcbd 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue2418.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue2418.cs @@ -35,7 +35,6 @@ await db.HashSetAsync(key, new[] Log($"'{pair.Name}'='{pair.Value}'"); } - // filter with LINQ Assert.True(entry.Any(x => x.Name == "some_int"), "Any"); someInt = entry.FirstOrDefault(x => x.Name == "some_int").Value; diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue25Tests.cs b/tests/StackExchange.Redis.Tests/Issues/Issue25Tests.cs index bcba4fa0c..8841d81d3 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue25Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue25Tests.cs @@ -6,7 +6,7 @@ namespace StackExchange.Redis.Tests.Issues; public class Issue25Tests : TestBase { - public Issue25Tests(ITestOutputHelper output) : base (output) { } + public Issue25Tests(ITestOutputHelper output) : base(output) { } [Fact] public void CaseInsensitive() diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue6Tests.cs b/tests/StackExchange.Redis.Tests/Issues/Issue6Tests.cs index 8043a317e..3b6d4f8fc 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue6Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue6Tests.cs @@ -2,9 +2,9 @@ namespace StackExchange.Redis.Tests.Issues; -public class Issue6Tests : TestBase +public class Issue6Tests : TestBase { - public Issue6Tests(ITestOutputHelper output) : base (output) { } + public Issue6Tests(ITestOutputHelper output) : base(output) { } [Fact] public void ShouldWorkWithoutEchoOrPing() diff --git a/tests/StackExchange.Redis.Tests/Issues/MassiveDeleteTests.cs b/tests/StackExchange.Redis.Tests/Issues/MassiveDeleteTests.cs index 2655592da..bbd9171ea 100644 --- a/tests/StackExchange.Redis.Tests/Issues/MassiveDeleteTests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/MassiveDeleteTests.cs @@ -67,8 +67,7 @@ public async Task ExecuteMassiveDelete() } watch.Stop(); long remaining = await db.SetLengthAsync(key).ForAwait(); - Log("From {0} to {1}; {2}ms", originally, remaining, - watch.ElapsedMilliseconds); + Log($"From {originally} to {remaining}; {watch.ElapsedMilliseconds}ms"); var counters = GetServer(conn).GetCounters(); Log("Completions: {0} sync, {1} async", counters.Interactive.CompletedSynchronously, counters.Interactive.CompletedAsynchronously); diff --git a/tests/StackExchange.Redis.Tests/Issues/SO22786599Tests.cs b/tests/StackExchange.Redis.Tests/Issues/SO22786599Tests.cs index b958b52e1..562eef8c5 100644 --- a/tests/StackExchange.Redis.Tests/Issues/SO22786599Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/SO22786599Tests.cs @@ -12,8 +12,8 @@ public SO22786599Tests(ITestOutputHelper output) : base(output) { } [Fact] public void Execute() { - string CurrentIdsSetDbKey = Me() + ".x"; - string CurrentDetailsSetDbKey = Me() + ".y"; + string currentIdsSetDbKey = Me() + ".x"; + string currentDetailsSetDbKey = Me() + ".y"; RedisValue[] stringIds = Enumerable.Range(1, 750).Select(i => (RedisValue)(i + " id")).ToArray(); RedisValue[] stringDetails = Enumerable.Range(1, 750).Select(i => (RedisValue)(i + " detail")).ToArray(); @@ -23,8 +23,8 @@ public void Execute() var db = conn.GetDatabase(); var tran = db.CreateTransaction(); - tran.SetAddAsync(CurrentIdsSetDbKey, stringIds); - tran.SetAddAsync(CurrentDetailsSetDbKey, stringDetails); + tran.SetAddAsync(currentIdsSetDbKey, stringIds); + tran.SetAddAsync(currentDetailsSetDbKey, stringDetails); var watch = Stopwatch.StartNew(); var isOperationSuccessful = tran.Execute(); diff --git a/tests/StackExchange.Redis.Tests/Issues/SO23949477Tests.cs b/tests/StackExchange.Redis.Tests/Issues/SO23949477Tests.cs index 87d26ee05..aa545a3cb 100644 --- a/tests/StackExchange.Redis.Tests/Issues/SO23949477Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/SO23949477Tests.cs @@ -5,7 +5,7 @@ namespace StackExchange.Redis.Tests.Issues; public class SO23949477Tests : TestBase { - public SO23949477Tests(ITestOutputHelper output) : base (output) { } + public SO23949477Tests(ITestOutputHelper output) : base(output) { } [Fact] public void Execute() @@ -16,12 +16,14 @@ public void Execute() RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); db.SortedSetAdd(key, "c", 3, When.Always, CommandFlags.FireAndForget); - db.SortedSetAdd(key, - new[] { - new SortedSetEntry("a", 1), - new SortedSetEntry("b", 2), - new SortedSetEntry("d", 4), - new SortedSetEntry("e", 5) + db.SortedSetAdd( + key, + new[] + { + new SortedSetEntry("a", 1), + new SortedSetEntry("b", 2), + new SortedSetEntry("d", 4), + new SortedSetEntry("e", 5), }, When.Always, CommandFlags.FireAndForget); diff --git a/tests/StackExchange.Redis.Tests/Issues/SO24807536Tests.cs b/tests/StackExchange.Redis.Tests/Issues/SO24807536Tests.cs index 9881b8c38..d4b449dd3 100644 --- a/tests/StackExchange.Redis.Tests/Issues/SO24807536Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/SO24807536Tests.cs @@ -7,7 +7,7 @@ namespace StackExchange.Redis.Tests.Issues; public class SO24807536Tests : TestBase { - public SO24807536Tests(ITestOutputHelper output) : base (output) { } + public SO24807536Tests(ITestOutputHelper output) : base(output) { } [Fact] public async Task Exec() diff --git a/tests/StackExchange.Redis.Tests/Issues/SO25113323Tests.cs b/tests/StackExchange.Redis.Tests/Issues/SO25113323Tests.cs index b10be1aea..8de318e2a 100644 --- a/tests/StackExchange.Redis.Tests/Issues/SO25113323Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/SO25113323Tests.cs @@ -6,7 +6,7 @@ namespace StackExchange.Redis.Tests.Issues; public class SO25113323Tests : TestBase { - public SO25113323Tests(ITestOutputHelper output) : base (output) { } + public SO25113323Tests(ITestOutputHelper output) : base(output) { } [Fact] public async Task SetExpirationToPassed() diff --git a/tests/StackExchange.Redis.Tests/Issues/SO25567566Tests.cs b/tests/StackExchange.Redis.Tests/Issues/SO25567566Tests.cs index f7bde6c4a..b71b2a1f9 100644 --- a/tests/StackExchange.Redis.Tests/Issues/SO25567566Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/SO25567566Tests.cs @@ -47,8 +47,8 @@ private async Task DoStuff(ConnectionMultiplexer conn) var exec = tran.ExecuteAsync(); // SWAP THESE TWO + // bool ok = true; bool ok = await Task.WhenAny(exec, timeout).ForAwait() == exec; - //bool ok = true; if (ok) { diff --git a/tests/StackExchange.Redis.Tests/KeyAndValueTests.cs b/tests/StackExchange.Redis.Tests/KeyAndValueTests.cs index 38f7f062e..1f8864083 100644 --- a/tests/StackExchange.Redis.Tests/KeyAndValueTests.cs +++ b/tests/StackExchange.Redis.Tests/KeyAndValueTests.cs @@ -72,7 +72,7 @@ internal static void CheckSame(RedisValue x, RedisValue y) Assert.True(y == x, "y==x"); Assert.False(x != y, "x!=y"); Assert.False(y != x, "y!=x"); - Assert.True(x.Equals(y),"x.EQ(y)"); + Assert.True(x.Equals(y), "x.EQ(y)"); Assert.True(y.Equals(x), "y.EQ(x)"); Assert.True(x.GetHashCode() == y.GetHashCode(), "GetHashCode"); } @@ -122,9 +122,9 @@ internal static void CheckNull(RedisValue value) Assert.Equal(0L, (long)value); CheckSame(value, value); - //CheckSame(value, default(RedisValue)); - //CheckSame(value, (string)null); - //CheckSame(value, (byte[])null); + // CheckSame(value, default(RedisValue)); + // CheckSame(value, (string)null); + // CheckSame(value, (byte[])null); } [Fact] @@ -145,14 +145,14 @@ public void ValuesAreConvertible() // ReSharper disable RedundantCast Assert.Equal((short)123, c.ToInt16(CultureInfo.InvariantCulture)); Assert.Equal((int)123, c.ToInt32(CultureInfo.InvariantCulture)); - Assert.Equal((long)123, c.ToInt64(CultureInfo.InvariantCulture)); - Assert.Equal((float)123, c.ToSingle(CultureInfo.InvariantCulture)); + Assert.Equal(123L, c.ToInt64(CultureInfo.InvariantCulture)); + Assert.Equal(123F, c.ToSingle(CultureInfo.InvariantCulture)); Assert.Equal("123", c.ToString(CultureInfo.InvariantCulture)); - Assert.Equal((double)123, c.ToDouble(CultureInfo.InvariantCulture)); - Assert.Equal((decimal)123, c.ToDecimal(CultureInfo.InvariantCulture)); + Assert.Equal(123D, c.ToDouble(CultureInfo.InvariantCulture)); + Assert.Equal(123M, c.ToDecimal(CultureInfo.InvariantCulture)); Assert.Equal((ushort)123, c.ToUInt16(CultureInfo.InvariantCulture)); - Assert.Equal((uint)123, c.ToUInt32(CultureInfo.InvariantCulture)); - Assert.Equal((ulong)123, c.ToUInt64(CultureInfo.InvariantCulture)); + Assert.Equal(123U, c.ToUInt32(CultureInfo.InvariantCulture)); + Assert.Equal(123UL, c.ToUInt64(CultureInfo.InvariantCulture)); blob = (byte[])c.ToType(typeof(byte[]), CultureInfo.InvariantCulture); Assert.Equal(3, blob.Length); diff --git a/tests/StackExchange.Redis.Tests/KeyPrefixedBatchTests.cs b/tests/StackExchange.Redis.Tests/KeyPrefixedBatchTests.cs index 0a38766af..e92a7a227 100644 --- a/tests/StackExchange.Redis.Tests/KeyPrefixedBatchTests.cs +++ b/tests/StackExchange.Redis.Tests/KeyPrefixedBatchTests.cs @@ -1,6 +1,6 @@ -using StackExchange.Redis.KeyspaceIsolation; -using System.Text; +using System.Text; using NSubstitute; +using StackExchange.Redis.KeyspaceIsolation; using Xunit; namespace StackExchange.Redis.Tests; diff --git a/tests/StackExchange.Redis.Tests/KeyPrefixedTests.cs b/tests/StackExchange.Redis.Tests/KeyPrefixedTests.cs index 8cbe7ad7f..aebc8fc6d 100644 --- a/tests/StackExchange.Redis.Tests/KeyPrefixedTests.cs +++ b/tests/StackExchange.Redis.Tests/KeyPrefixedTests.cs @@ -3,10 +3,10 @@ using System.Linq.Expressions; using System.Net; using System.Text; +using System.Threading.Tasks; using NSubstitute; using StackExchange.Redis.KeyspaceIsolation; using Xunit; -using System.Threading.Tasks; namespace StackExchange.Redis.Tests { @@ -133,7 +133,7 @@ public async Task HashSetAsync_2() [Fact] public async Task HashStringLengthAsync() { - await prefixed.HashStringLengthAsync("key","field", CommandFlags.None); + await prefixed.HashStringLengthAsync("key", "field", CommandFlags.None); await mock.Received().HashStringLengthAsync("prefix:key", "field", CommandFlags.None); } diff --git a/tests/StackExchange.Redis.Tests/KeyTests.cs b/tests/StackExchange.Redis.Tests/KeyTests.cs index b0c028d56..bfb57a425 100644 --- a/tests/StackExchange.Redis.Tests/KeyTests.cs +++ b/tests/StackExchange.Redis.Tests/KeyTests.cs @@ -273,7 +273,7 @@ public async Task KeyEncoding() db.ListLeftPush(key, "new value", flags: CommandFlags.FireAndForget); // Depending on server version, this is going to vary - we're sanity checking here. - var listTypes = new [] { "ziplist", "quicklist", "listpack" }; + var listTypes = new[] { "ziplist", "quicklist", "listpack" }; Assert.Contains(db.KeyEncoding(key), listTypes); Assert.Contains(await db.KeyEncodingAsync(key), listTypes); @@ -381,7 +381,7 @@ private static int GetHashSlot(in RedisKey key) { var strategy = new ServerSelectionStrategy(null!) { - ServerType = ServerType.Cluster + ServerType = ServerType.Cluster, }; return strategy.HashSlot(key); } diff --git a/tests/StackExchange.Redis.Tests/LexTests.cs b/tests/StackExchange.Redis.Tests/LexTests.cs index ace821ca6..a72aeb142 100644 --- a/tests/StackExchange.Redis.Tests/LexTests.cs +++ b/tests/StackExchange.Redis.Tests/LexTests.cs @@ -17,17 +17,19 @@ public void QueryRangeAndLengthByLex() RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - db.SortedSetAdd(key, + db.SortedSetAdd( + key, new[] - { - new SortedSetEntry("a", 0), - new SortedSetEntry("b", 0), - new SortedSetEntry("c", 0), - new SortedSetEntry("d", 0), - new SortedSetEntry("e", 0), - new SortedSetEntry("f", 0), - new SortedSetEntry("g", 0), - }, CommandFlags.FireAndForget); + { + new SortedSetEntry("a", 0), + new SortedSetEntry("b", 0), + new SortedSetEntry("c", 0), + new SortedSetEntry("d", 0), + new SortedSetEntry("e", 0), + new SortedSetEntry("f", 0), + new SortedSetEntry("g", 0), + }, + CommandFlags.FireAndForget); var set = db.SortedSetRangeByValue(key, default(RedisValue), "c"); var count = db.SortedSetLengthByValue(key, default(RedisValue), "c"); @@ -64,24 +66,28 @@ public void RemoveRangeByLex() RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - db.SortedSetAdd(key, + db.SortedSetAdd( + key, new[] - { - new SortedSetEntry("aaaa", 0), - new SortedSetEntry("b", 0), - new SortedSetEntry("c", 0), - new SortedSetEntry("d", 0), - new SortedSetEntry("e", 0), - }, CommandFlags.FireAndForget); - db.SortedSetAdd(key, + { + new SortedSetEntry("aaaa", 0), + new SortedSetEntry("b", 0), + new SortedSetEntry("c", 0), + new SortedSetEntry("d", 0), + new SortedSetEntry("e", 0), + }, + CommandFlags.FireAndForget); + db.SortedSetAdd( + key, new[] - { - new SortedSetEntry("foo", 0), - new SortedSetEntry("zap", 0), - new SortedSetEntry("zip", 0), - new SortedSetEntry("ALPHA", 0), - new SortedSetEntry("alpha", 0), - }, CommandFlags.FireAndForget); + { + new SortedSetEntry("foo", 0), + new SortedSetEntry("zap", 0), + new SortedSetEntry("zip", 0), + new SortedSetEntry("ALPHA", 0), + new SortedSetEntry("alpha", 0), + }, + CommandFlags.FireAndForget); var set = db.SortedSetRangeByRank(key); Equate(set, set.Length, "ALPHA", "aaaa", "alpha", "b", "c", "d", "e", "foo", "zap", "zip"); diff --git a/tests/StackExchange.Redis.Tests/LockingTests.cs b/tests/StackExchange.Redis.Tests/LockingTests.cs index a2ce6986d..c2aa3611f 100644 --- a/tests/StackExchange.Redis.Tests/LockingTests.cs +++ b/tests/StackExchange.Redis.Tests/LockingTests.cs @@ -11,13 +11,13 @@ namespace StackExchange.Redis.Tests; public class LockingTests : TestBase { protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort; - public LockingTests(ITestOutputHelper output) : base (output) { } + public LockingTests(ITestOutputHelper output) : base(output) { } public enum TestMode { MultiExec, NoMultiExec, - Twemproxy + Twemproxy, } public static IEnumerable TestModes() @@ -38,12 +38,12 @@ public void AggressiveParallel(TestMode testMode) using (var conn1 = Create(testMode)) using (var conn2 = Create(testMode)) { - void cb(object? obj) + void Inner(object? obj) { try { var conn = (IDatabase?)obj!; - conn.Multiplexer.ErrorMessage += delegate { Interlocked.Increment(ref errorCount); }; + conn.Multiplexer.ErrorMessage += (sender, e) => Interlocked.Increment(ref errorCount); for (int i = 0; i < 1000; i++) { @@ -58,8 +58,8 @@ void cb(object? obj) } } int db = testMode == TestMode.Twemproxy ? 0 : 2; - ThreadPool.QueueUserWorkItem(cb, conn1.GetDatabase(db)); - ThreadPool.QueueUserWorkItem(cb, conn2.GetDatabase(db)); + ThreadPool.QueueUserWorkItem(Inner, conn1.GetDatabase(db)); + ThreadPool.QueueUserWorkItem(Inner, conn2.GetDatabase(db)); evt.WaitOne(8000); } Assert.Equal(0, Interlocked.CompareExchange(ref errorCount, 0, 0)); @@ -78,23 +78,23 @@ public void TestOpCountByVersionLocal_UpLevel() private void TestLockOpCountByVersion(IConnectionMultiplexer conn, int expectedOps, bool existFirst) { const int LockDuration = 30; - RedisKey Key = Me(); + RedisKey key = Me(); var db = conn.GetDatabase(); - db.KeyDelete(Key, CommandFlags.FireAndForget); + db.KeyDelete(key, CommandFlags.FireAndForget); RedisValue newVal = "us:" + Guid.NewGuid().ToString(); RedisValue expectedVal = newVal; if (existFirst) { expectedVal = "other:" + Guid.NewGuid().ToString(); - db.StringSet(Key, expectedVal, TimeSpan.FromSeconds(LockDuration), flags: CommandFlags.FireAndForget); + db.StringSet(key, expectedVal, TimeSpan.FromSeconds(LockDuration), flags: CommandFlags.FireAndForget); } long countBefore = GetServer(conn).GetCounters().Interactive.OperationCount; - var taken = db.LockTake(Key, newVal, TimeSpan.FromSeconds(LockDuration)); + var taken = db.LockTake(key, newVal, TimeSpan.FromSeconds(LockDuration)); long countAfter = GetServer(conn).GetCounters().Interactive.OperationCount; - var valAfter = db.StringGet(Key); + var valAfter = db.StringGet(key); Assert.Equal(!existFirst, taken); Assert.Equal(expectedVal, valAfter); @@ -118,28 +118,28 @@ public async Task TakeLockAndExtend(TestMode testMode) RedisValue right = Guid.NewGuid().ToString(), wrong = Guid.NewGuid().ToString(); - int DB = testMode == TestMode.Twemproxy ? 0 : 7; - RedisKey Key = Me() + testMode; + int dbId = testMode == TestMode.Twemproxy ? 0 : 7; + RedisKey key = Me() + testMode; - var db = conn.GetDatabase(DB); + var db = conn.GetDatabase(dbId); - db.KeyDelete(Key, CommandFlags.FireAndForget); + db.KeyDelete(key, CommandFlags.FireAndForget); bool withTran = testMode == TestMode.MultiExec; - var t1 = db.LockTakeAsync(Key, right, TimeSpan.FromSeconds(20)); - var t1b = db.LockTakeAsync(Key, wrong, TimeSpan.FromSeconds(10)); - var t2 = db.LockQueryAsync(Key); - var t3 = withTran ? db.LockReleaseAsync(Key, wrong) : null; - var t4 = db.LockQueryAsync(Key); - var t5 = withTran ? db.LockExtendAsync(Key, wrong, TimeSpan.FromSeconds(60)) : null; - var t6 = db.LockQueryAsync(Key); - var t7 = db.KeyTimeToLiveAsync(Key); - var t8 = db.LockExtendAsync(Key, right, TimeSpan.FromSeconds(60)); - var t9 = db.LockQueryAsync(Key); - var t10 = db.KeyTimeToLiveAsync(Key); - var t11 = db.LockReleaseAsync(Key, right); - var t12 = db.LockQueryAsync(Key); - var t13 = db.LockTakeAsync(Key, wrong, TimeSpan.FromSeconds(10)); + var t1 = db.LockTakeAsync(key, right, TimeSpan.FromSeconds(20)); + var t1b = db.LockTakeAsync(key, wrong, TimeSpan.FromSeconds(10)); + var t2 = db.LockQueryAsync(key); + var t3 = withTran ? db.LockReleaseAsync(key, wrong) : null; + var t4 = db.LockQueryAsync(key); + var t5 = withTran ? db.LockExtendAsync(key, wrong, TimeSpan.FromSeconds(60)) : null; + var t6 = db.LockQueryAsync(key); + var t7 = db.KeyTimeToLiveAsync(key); + var t8 = db.LockExtendAsync(key, right, TimeSpan.FromSeconds(60)); + var t9 = db.LockQueryAsync(key); + var t10 = db.KeyTimeToLiveAsync(key); + var t11 = db.LockReleaseAsync(key, right); + var t12 = db.LockQueryAsync(key); + var t13 = db.LockTakeAsync(key, wrong, TimeSpan.FromSeconds(10)); Assert.NotEqual(default(RedisValue), right); Assert.NotEqual(default(RedisValue), wrong); @@ -168,7 +168,7 @@ public async Task TestBasicLockNotTaken(TestMode testMode) using var conn = Create(testMode); int errorCount = 0; - conn.ErrorMessage += delegate { Interlocked.Increment(ref errorCount); }; + conn.ErrorMessage += (sender, e) => Interlocked.Increment(ref errorCount); Task? taken = null; Task? newValue = null; Task? ttl = null; diff --git a/tests/StackExchange.Redis.Tests/LoggerTests.cs b/tests/StackExchange.Redis.Tests/LoggerTests.cs index 1d15a69b9..217864ba7 100644 --- a/tests/StackExchange.Redis.Tests/LoggerTests.cs +++ b/tests/StackExchange.Redis.Tests/LoggerTests.cs @@ -1,10 +1,10 @@ -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using System; +using System; using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Xunit; using Xunit.Abstractions; @@ -65,16 +65,16 @@ public void Dispose() { } public class TestWrapperLogger : ILogger { public int LogCount = 0; - public ILogger _inner { get; } + private ILogger Inner { get; } - public TestWrapperLogger(ILogger toWrap) => _inner = toWrap; + public TestWrapperLogger(ILogger toWrap) => Inner = toWrap; - public IDisposable BeginScope(TState state) => _inner.BeginScope(state); - public bool IsEnabled(LogLevel logLevel) => _inner.IsEnabled(logLevel); + public IDisposable BeginScope(TState state) => Inner.BeginScope(state); + public bool IsEnabled(LogLevel logLevel) => Inner.IsEnabled(logLevel); public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) { Interlocked.Increment(ref LogCount); - _inner.Log(logLevel, eventId, state, exception, formatter); + Inner.Log(logLevel, eventId, state, exception, formatter); } } diff --git a/tests/StackExchange.Redis.Tests/MassiveOpsTests.cs b/tests/StackExchange.Redis.Tests/MassiveOpsTests.cs index 26816a8b1..3b3f8157e 100644 --- a/tests/StackExchange.Redis.Tests/MassiveOpsTests.cs +++ b/tests/StackExchange.Redis.Tests/MassiveOpsTests.cs @@ -38,7 +38,7 @@ public async Task MassiveBulkOpsAsync(bool withContinuation) RedisKey key = Me(); var db = conn.GetDatabase(); await db.PingAsync().ForAwait(); - static void nonTrivial(Task _) + static void NonTrivial(Task unused) { Thread.SpinWait(5); } @@ -49,13 +49,12 @@ static void nonTrivial(Task _) if (withContinuation) { // Intentionally unawaited - _ = t.ContinueWith(nonTrivial); + _ = t.ContinueWith(NonTrivial); } } Assert.Equal(AsyncOpsQty, await db.StringGetAsync(key).ForAwait()); watch.Stop(); - Log("{2}: Time for {0} ops: {1}ms ({3}, any order); ops/s: {4}", AsyncOpsQty, watch.ElapsedMilliseconds, Me(), - withContinuation ? "with continuation" : "no continuation", AsyncOpsQty / watch.Elapsed.TotalSeconds); + Log($"{Me()}: Time for {AsyncOpsQty} ops: {watch.ElapsedMilliseconds}ms ({(withContinuation ? "with continuation" : "no continuation")}, any order); ops/s: {AsyncOpsQty / watch.Elapsed.TotalSeconds}"); } [TheoryLongRunning] @@ -71,18 +70,19 @@ public void MassiveBulkOpsSync(int threads) var db = conn.GetDatabase(); db.KeyDelete(key, CommandFlags.FireAndForget); int workPerThread = SyncOpsQty / threads; - var timeTaken = RunConcurrent(delegate - { - for (int i = 0; i < workPerThread; i++) + var timeTaken = RunConcurrent( + () => { - db.StringIncrement(key, flags: CommandFlags.FireAndForget); - } - }, threads); + for (int i = 0; i < workPerThread; i++) + { + db.StringIncrement(key, flags: CommandFlags.FireAndForget); + } + }, + threads); int val = (int)db.StringGet(key); Assert.Equal(workPerThread * threads, val); - Log("{2}: Time for {0} ops on {3} threads: {1}ms (any order); ops/s: {4}", - threads * workPerThread, timeTaken.TotalMilliseconds, Me(), threads, (workPerThread * threads) / timeTaken.TotalSeconds); + Log($"{Me()}: Time for {threads * workPerThread} ops on {threads} threads: {timeTaken.TotalMilliseconds}ms (any order); ops/s: {(workPerThread * threads) / timeTaken.TotalSeconds}"); } [Theory] @@ -98,19 +98,19 @@ public void MassiveBulkOpsFireAndForget(int threads) db.KeyDelete(key, CommandFlags.FireAndForget); int perThread = AsyncOpsQty / threads; - var elapsed = RunConcurrent(delegate - { - for (int i = 0; i < perThread; i++) + var elapsed = RunConcurrent( + () => { - db.StringIncrement(key, flags: CommandFlags.FireAndForget); - } - db.Ping(); - }, threads); + for (int i = 0; i < perThread; i++) + { + db.StringIncrement(key, flags: CommandFlags.FireAndForget); + } + db.Ping(); + }, + threads); var val = (long)db.StringGet(key); Assert.Equal(perThread * threads, val); - Log("{2}: Time for {0} ops over {4} threads: {1:###,###}ms (any order); ops/s: {3:###,###,##0}", - val, elapsed.TotalMilliseconds, Me(), - val / elapsed.TotalSeconds, threads); + Log($"{Me()}: Time for {val} ops over {threads} threads: {elapsed.TotalMilliseconds:###,###}ms (any order); ops/s: {val / elapsed.TotalSeconds:###,###,##0}"); } } diff --git a/tests/StackExchange.Redis.Tests/MigrateTests.cs b/tests/StackExchange.Redis.Tests/MigrateTests.cs index 1fad9adf3..54fe77649 100644 --- a/tests/StackExchange.Redis.Tests/MigrateTests.cs +++ b/tests/StackExchange.Redis.Tests/MigrateTests.cs @@ -8,7 +8,7 @@ namespace StackExchange.Redis.Tests; public class MigrateTests : TestBase { - public MigrateTests(ITestOutputHelper output) : base (output) { } + public MigrateTests(ITestOutputHelper output) : base(output) { } [FactLongRunning] public async Task Basic() diff --git a/tests/StackExchange.Redis.Tests/MultiAddTests.cs b/tests/StackExchange.Redis.Tests/MultiAddTests.cs index d542b80b6..cf5f70c23 100644 --- a/tests/StackExchange.Redis.Tests/MultiAddTests.cs +++ b/tests/StackExchange.Redis.Tests/MultiAddTests.cs @@ -19,20 +19,40 @@ public void AddSortedSetEveryWay() db.KeyDelete(key, CommandFlags.FireAndForget); db.SortedSetAdd(key, "a", 1, CommandFlags.FireAndForget); - db.SortedSetAdd(key, new[] { - new SortedSetEntry("b", 2) }, CommandFlags.FireAndForget); - db.SortedSetAdd(key, new[] { + db.SortedSetAdd( + key, + new[] + { + new SortedSetEntry("b", 2), + }, + CommandFlags.FireAndForget); + db.SortedSetAdd( + key, + new[] + { new SortedSetEntry("c", 3), - new SortedSetEntry("d", 4)}, CommandFlags.FireAndForget); - db.SortedSetAdd(key, new[] { + new SortedSetEntry("d", 4), + }, + CommandFlags.FireAndForget); + db.SortedSetAdd( + key, + new[] + { new SortedSetEntry("e", 5), new SortedSetEntry("f", 6), - new SortedSetEntry("g", 7)}, CommandFlags.FireAndForget); - db.SortedSetAdd(key, new[] { + new SortedSetEntry("g", 7), + }, + CommandFlags.FireAndForget); + db.SortedSetAdd( + key, + new[] + { new SortedSetEntry("h", 8), new SortedSetEntry("i", 9), new SortedSetEntry("j", 10), - new SortedSetEntry("k", 11)}, CommandFlags.FireAndForget); + new SortedSetEntry("k", 11), + }, + CommandFlags.FireAndForget); var vals = db.SortedSetRangeByScoreWithScores(key); string s = string.Join(",", vals.OrderByDescending(x => x.Score).Select(x => x.Element)); Assert.Equal("k,j,i,h,g,f,e,d,c,b,a", s); @@ -50,20 +70,40 @@ public void AddHashEveryWay() db.KeyDelete(key, CommandFlags.FireAndForget); db.HashSet(key, "a", 1, flags: CommandFlags.FireAndForget); - db.HashSet(key, new[] { - new HashEntry("b", 2) }, CommandFlags.FireAndForget); - db.HashSet(key, new[] { + db.HashSet( + key, + new[] + { + new HashEntry("b", 2), + }, + CommandFlags.FireAndForget); + db.HashSet( + key, + new[] + { new HashEntry("c", 3), - new HashEntry("d", 4)}, CommandFlags.FireAndForget); - db.HashSet(key, new[] { + new HashEntry("d", 4), + }, + CommandFlags.FireAndForget); + db.HashSet( + key, + new[] + { new HashEntry("e", 5), new HashEntry("f", 6), - new HashEntry("g", 7)}, CommandFlags.FireAndForget); - db.HashSet(key, new[] { + new HashEntry("g", 7), + }, + CommandFlags.FireAndForget); + db.HashSet( + key, + new[] + { new HashEntry("h", 8), new HashEntry("i", 9), new HashEntry("j", 10), - new HashEntry("k", 11)}, CommandFlags.FireAndForget); + new HashEntry("k", 11), + }, + CommandFlags.FireAndForget); var vals = db.HashGetAll(key); string s = string.Join(",", vals.OrderByDescending(x => (double)x.Value).Select(x => x.Name)); Assert.Equal("k,j,i,h,g,f,e,d,c,b,a", s); diff --git a/tests/StackExchange.Redis.Tests/MultiPrimaryTests.cs b/tests/StackExchange.Redis.Tests/MultiPrimaryTests.cs index 52b6c6297..bf3e5690e 100644 --- a/tests/StackExchange.Redis.Tests/MultiPrimaryTests.cs +++ b/tests/StackExchange.Redis.Tests/MultiPrimaryTests.cs @@ -10,7 +10,7 @@ public class MultiPrimaryTests : TestBase { protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort + "," + TestConfig.Current.SecureServerAndPort + ",password=" + TestConfig.Current.SecurePassword; - public MultiPrimaryTests(ITestOutputHelper output) : base (output) { } + public MultiPrimaryTests(ITestOutputHelper output) : base(output) { } [Fact] public void CannotFlushReplica() diff --git a/tests/StackExchange.Redis.Tests/OverloadCompatTests.cs b/tests/StackExchange.Redis.Tests/OverloadCompatTests.cs index e0b09d545..f562a850b 100644 --- a/tests/StackExchange.Redis.Tests/OverloadCompatTests.cs +++ b/tests/StackExchange.Redis.Tests/OverloadCompatTests.cs @@ -12,7 +12,7 @@ namespace StackExchange.Redis.Tests; [Collection(SharedConnectionFixture.Key)] public class OverloadCompatTests : TestBase { - public OverloadCompatTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base (output, fixture) { } + public OverloadCompatTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } [Fact] public async Task KeyExpire() @@ -42,7 +42,6 @@ public async Task KeyExpire() db.KeyExpire(key, expireTime, when: when, flags: flags); // Async - await db.KeyExpireAsync(key, expiresIn); await db.KeyExpireAsync(key, expiresIn, when); await db.KeyExpireAsync(key, expiresIn, when: when); @@ -89,7 +88,6 @@ public async Task StringBitCount() db.StringBitCount(key, start: 1, end: 1, flags: flags); // Async - await db.StringBitCountAsync(key); await db.StringBitCountAsync(key, 1); await db.StringBitCountAsync(key, 0, 0); @@ -138,7 +136,6 @@ public async Task StringBitPosition() db.StringBitPosition(key, true, start: 1, end: 1, flags: flags); // Async - await db.StringBitPositionAsync(key, true); await db.StringBitPositionAsync(key, true, 1); await db.StringBitPositionAsync(key, true, 1, 3); @@ -166,7 +163,7 @@ public async Task SortedSetAdd() RedisKey key = Me(); RedisValue val = "myval"; var score = 1.0d; - var values = new SortedSetEntry[]{new SortedSetEntry(val, score)}; + var values = new SortedSetEntry[] { new SortedSetEntry(val, score) }; var when = When.Exists; var flags = CommandFlags.None; @@ -191,7 +188,6 @@ public async Task SortedSetAdd() db.SortedSetAdd(key, values, when: when, flags: flags); // Async - await db.SortedSetAddAsync(key, val, score); await db.SortedSetAddAsync(key, val, score, when); await db.SortedSetAddAsync(key, val, score, when: when); @@ -239,7 +235,6 @@ public async Task StringSet() db.StringSet(key, val, null, When.NotExists, flags); // Async - await db.StringSetAsync(key, val); await db.StringSetAsync(key, val, expiry: expiresIn); await db.StringSetAsync(key, val, when: when); diff --git a/tests/StackExchange.Redis.Tests/PreserveOrderTests.cs b/tests/StackExchange.Redis.Tests/PreserveOrderTests.cs index f11cda5c5..0cb5eb271 100644 --- a/tests/StackExchange.Redis.Tests/PreserveOrderTests.cs +++ b/tests/StackExchange.Redis.Tests/PreserveOrderTests.cs @@ -10,7 +10,7 @@ namespace StackExchange.Redis.Tests; [Collection(SharedConnectionFixture.Key)] public class PreserveOrderTests : TestBase { - public PreserveOrderTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base (output, fixture) { } + public PreserveOrderTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } [Fact] public void Execute() diff --git a/tests/StackExchange.Redis.Tests/ProfilingTests.cs b/tests/StackExchange.Redis.Tests/ProfilingTests.cs index 7c4dcbe59..2d0264984 100644 --- a/tests/StackExchange.Redis.Tests/ProfilingTests.cs +++ b/tests/StackExchange.Redis.Tests/ProfilingTests.cs @@ -1,12 +1,12 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; using System.Threading; -using System.Collections.Concurrent; +using System.Threading.Tasks; +using StackExchange.Redis.Profiling; using Xunit; using Xunit.Abstractions; -using StackExchange.Redis.Profiling; namespace StackExchange.Redis.Tests; @@ -182,8 +182,8 @@ public void ManyContexts() { var g = db.StringGetAsync(prefix + ix); var s = db.StringSetAsync(prefix + ix, "world" + ix); - // overlap the g+s, just for fun - await g; + // overlap the g+s, just for fun + await g; await s; } @@ -243,11 +243,7 @@ public void LowAllocationEnumerable() foreach (var i in Enumerable.Range(0, OuterLoop)) { - var t = - db.StringSetAsync(prefix + i, "bar" + i) - .ContinueWith( - async _ => (string?)(await db.StringGetAsync(prefix + i).ForAwait()) - ); + var t = db.StringSetAsync(prefix + i, "bar" + i).ContinueWith(async _ => (string?)(await db.StringGetAsync(prefix + i).ForAwait())); var finalResult = t.Unwrap(); allTasks.Add(finalResult); diff --git a/tests/StackExchange.Redis.Tests/PubSubCommandTests.cs b/tests/StackExchange.Redis.Tests/PubSubCommandTests.cs index e689c980b..f3ea9eca7 100644 --- a/tests/StackExchange.Redis.Tests/PubSubCommandTests.cs +++ b/tests/StackExchange.Redis.Tests/PubSubCommandTests.cs @@ -29,7 +29,7 @@ public void SubscriberCount() _ = server.SubscriptionPatternCount(); var count = server.SubscriptionSubscriberCount(channel); Assert.Equal(0, count); - conn.GetSubscriber().Subscribe(channel, delegate { }); + conn.GetSubscriber().Subscribe(channel, (channel, value) => { }); count = server.SubscriptionSubscriberCount(channel); Assert.Equal(1, count); @@ -57,7 +57,7 @@ public async Task SubscriberCountAsync() _ = await server.SubscriptionPatternCountAsync().WithTimeout(2000); var count = await server.SubscriptionSubscriberCountAsync(channel).WithTimeout(2000); Assert.Equal(0, count); - await conn.GetSubscriber().SubscribeAsync(channel, delegate { }).WithTimeout(2000); + await conn.GetSubscriber().SubscribeAsync(channel, (channel, value) => { }).WithTimeout(2000); count = await server.SubscriptionSubscriberCountAsync(channel).WithTimeout(2000); Assert.Equal(1, count); @@ -69,8 +69,7 @@ public async Task SubscriberCountAsync() } internal static class Util { - public static async Task WithTimeout(this Task task, int timeoutMs, - [CallerMemberName] string? caller = null, [CallerLineNumber] int line = 0) + public static async Task WithTimeout(this Task task, int timeoutMs, [CallerMemberName] string? caller = null, [CallerLineNumber] int line = 0) { var cts = new CancellationTokenSource(); if (task == await Task.WhenAny(task, Task.Delay(timeoutMs, cts.Token)).ForAwait()) @@ -83,8 +82,7 @@ public static async Task WithTimeout(this Task task, int timeoutMs, throw new TimeoutException($"timout from {caller} line {line}"); } } - public static async Task WithTimeout(this Task task, int timeoutMs, - [CallerMemberName] string? caller = null, [CallerLineNumber] int line = 0) + public static async Task WithTimeout(this Task task, int timeoutMs, [CallerMemberName] string? caller = null, [CallerLineNumber] int line = 0) { var cts = new CancellationTokenSource(); if (task == await Task.WhenAny(task, Task.Delay(timeoutMs, cts.Token)).ForAwait()) diff --git a/tests/StackExchange.Redis.Tests/PubSubMultiserverTests.cs b/tests/StackExchange.Redis.Tests/PubSubMultiserverTests.cs index aa363984f..d7a0ee513 100644 --- a/tests/StackExchange.Redis.Tests/PubSubMultiserverTests.cs +++ b/tests/StackExchange.Redis.Tests/PubSubMultiserverTests.cs @@ -123,11 +123,14 @@ public async Task PrimaryReplicaSubscriptionFailover(CommandFlags flags, bool ex var count = 0; Log("Subscribing..."); - await sub.SubscribeAsync(channel, (_, val) => - { - Interlocked.Increment(ref count); - Log("Message: " + val); - }, flags); + await sub.SubscribeAsync( + channel, + (_, val) => + { + Interlocked.Increment(ref count); + Log("Message: " + val); + }, + flags); Assert.True(sub.IsConnected(channel)); Log("Publishing (1)..."); diff --git a/tests/StackExchange.Redis.Tests/PubSubTests.cs b/tests/StackExchange.Redis.Tests/PubSubTests.cs index 697bf2771..d064f298d 100644 --- a/tests/StackExchange.Redis.Tests/PubSubTests.cs +++ b/tests/StackExchange.Redis.Tests/PubSubTests.cs @@ -8,7 +8,6 @@ using StackExchange.Redis.Maintenance; using Xunit; using Xunit.Abstractions; -// ReSharper disable AccessToModifiedClosure namespace StackExchange.Redis.Tests; @@ -33,7 +32,8 @@ public async Task ExplicitPublishMode() pub.Publish("abcd", "efg"); #pragma warning restore CS0618 - await UntilConditionAsync(TimeSpan.FromSeconds(10), + await UntilConditionAsync( + TimeSpan.FromSeconds(10), () => Thread.VolatileRead(ref b) == 1 && Thread.VolatileRead(ref c) == 1 && Thread.VolatileRead(ref d) == 1); @@ -80,8 +80,7 @@ public async Task TestBasicPubSub(string channelPrefix, bool wildCard, string br Log(channel); } } - } - , handler2 = (_, __) => Interlocked.Increment(ref secondHandler); + }, handler2 = (_, __) => Interlocked.Increment(ref secondHandler); #pragma warning disable CS0618 sub.Subscribe(subChannel, handler1); sub.Subscribe(subChannel, handler2); @@ -154,16 +153,19 @@ public async Task TestBasicPubSubFireAndForget() HashSet received = new(); int secondHandler = 0; await PingAsync(pub, sub).ForAwait(); - sub.Subscribe(key, (channel, payload) => - { - lock (received) + sub.Subscribe( + key, + (channel, payload) => { - if (channel == key) + lock (received) { - received.Add(payload); + if (channel == key) + { + received.Add(payload); + } } - } - }, CommandFlags.FireAndForget); + }, + CommandFlags.FireAndForget); sub.Subscribe(key, (_, __) => Interlocked.Increment(ref secondHandler), CommandFlags.FireAndForget); Log(profiler); @@ -326,8 +328,7 @@ private void TestMassivePublish(ISubscriber sub, string channel, string caption) sub.WaitAll(tasks); withAsync.Stop(); - Log("{2}: {0}ms (F+F) vs {1}ms (async)", - withFAF.ElapsedMilliseconds, withAsync.ElapsedMilliseconds, caption); + Log($"{caption}: {withFAF.ElapsedMilliseconds}ms (F+F) vs {withAsync.ElapsedMilliseconds}ms (async)"); // We've made async so far, this test isn't really valid anymore // So let's check they're at least within a few seconds. Assert.True(withFAF.ElapsedMilliseconds < withAsync.ElapsedMilliseconds + 3000, caption); @@ -345,7 +346,8 @@ public async Task SubscribeAsyncEnumerable() var gotall = new TaskCompletionSource(); var source = await sub.SubscribeAsync(channel); - var op = Task.Run(async () => { + var op = Task.Run(async () => + { int count = 0; await foreach (var item in source) { @@ -479,10 +481,7 @@ async Task RunLoop() Log("Awaiting completion."); await subChannel.Completion; Log("Completion awaited."); - await Assert.ThrowsAsync(async delegate - { - await subChannel.ReadAsync().ForAwait(); - }).ForAwait(); + await Assert.ThrowsAsync(async () => await subChannel.ReadAsync().ForAwait()).ForAwait(); Log("End of muxer."); } Log("End of test."); @@ -548,10 +547,7 @@ public async Task PubSubGetAllCorrectOrder_OnMessage_Sync() await subChannel.Completion; Log("Completion awaited."); Assert.True(subChannel.Completion.IsCompleted); - await Assert.ThrowsAsync(async delegate - { - await subChannel.ReadAsync().ForAwait(); - }).ForAwait(); + await Assert.ThrowsAsync(async () => await subChannel.ReadAsync().ForAwait()).ForAwait(); Log("End of muxer."); } Log("End of test."); @@ -622,10 +618,7 @@ public async Task PubSubGetAllCorrectOrder_OnMessage_Async() await subChannel.Completion; Log("Completion awaited."); Assert.True(subChannel.Completion.IsCompleted); - await Assert.ThrowsAsync(async delegate - { - await subChannel.ReadAsync().ForAwait(); - }).ForAwait(); + await Assert.ThrowsAsync(async () => await subChannel.ReadAsync().ForAwait()).ForAwait(); Log("End of muxer."); } Log("End of test."); @@ -642,8 +635,8 @@ public async Task TestPublishWithSubscribers() var listenA = connA.GetSubscriber(); var listenB = connB.GetSubscriber(); #pragma warning disable CS0618 - var t1 = listenA.SubscribeAsync(channel, delegate { }); - var t2 = listenB.SubscribeAsync(channel, delegate { }); + var t1 = listenA.SubscribeAsync(channel, (arg1, arg2) => { }); + var t2 = listenB.SubscribeAsync(channel, (arg1, arg2) => { }); #pragma warning restore CS0618 await Task.WhenAll(t1, t2).ForAwait(); @@ -696,12 +689,12 @@ public async Task Issue38() var sub = conn.GetSubscriber(); int count = 0; var prefix = Me(); - void handler(RedisChannel _, RedisValue __) => Interlocked.Increment(ref count); + void Handler(RedisChannel unused, RedisValue unused2) => Interlocked.Increment(ref count); #pragma warning disable CS0618 - var a0 = sub.SubscribeAsync(prefix + "foo", handler); - var a1 = sub.SubscribeAsync(prefix + "bar", handler); - var b0 = sub.SubscribeAsync(prefix + "f*o", handler); - var b1 = sub.SubscribeAsync(prefix + "b*r", handler); + var a0 = sub.SubscribeAsync(prefix + "foo", Handler); + var a1 = sub.SubscribeAsync(prefix + "bar", Handler); + var b0 = sub.SubscribeAsync(prefix + "f*o", Handler); + var b1 = sub.SubscribeAsync(prefix + "b*r", Handler); #pragma warning restore CS0618 await Task.WhenAll(a0, a1, b0, b1).ForAwait(); @@ -767,8 +760,8 @@ public async Task TestSubscribeUnsubscribeAndSubscribeAgain() var sub = connSub.GetSubscriber(); int x = 0, y = 0; #pragma warning disable CS0618 - var t1 = sub.SubscribeAsync(prefix + "abc", delegate { Interlocked.Increment(ref x); }); - var t2 = sub.SubscribeAsync(prefix + "ab*", delegate { Interlocked.Increment(ref y); }); + var t1 = sub.SubscribeAsync(prefix + "abc", (arg1, arg2) => Interlocked.Increment(ref x)); + var t2 = sub.SubscribeAsync(prefix + "ab*", (arg1, arg2) => Interlocked.Increment(ref y)); await Task.WhenAll(t1, t2).ForAwait(); pub.Publish(prefix + "abc", ""); await AllowReasonableTimeToPublishAndProcess().ForAwait(); @@ -780,8 +773,8 @@ public async Task TestSubscribeUnsubscribeAndSubscribeAgain() pub.Publish(prefix + "abc", ""); Assert.Equal(1, Volatile.Read(ref x)); Assert.Equal(1, Volatile.Read(ref y)); - t1 = sub.SubscribeAsync(prefix + "abc", delegate { Interlocked.Increment(ref x); }); - t2 = sub.SubscribeAsync(prefix + "ab*", delegate { Interlocked.Increment(ref y); }); + t1 = sub.SubscribeAsync(prefix + "abc", (arg1, arg2) => Interlocked.Increment(ref x)); + t2 = sub.SubscribeAsync(prefix + "ab*", (arg1, arg2) => Interlocked.Increment(ref y)); await Task.WhenAll(t1, t2).ForAwait(); pub.Publish(prefix + "abc", ""); #pragma warning restore CS0618 @@ -801,7 +794,7 @@ public async Task AzureRedisEventsAutomaticSubscribe() { EndPoints = { TestConfig.Current.AzureCacheServer }, Password = TestConfig.Current.AzureCachePassword, - Ssl = true + Ssl = true, }; using (var connection = await ConnectionMultiplexer.ConnectAsync(options)) diff --git a/tests/StackExchange.Redis.Tests/RedisResultTests.cs b/tests/StackExchange.Redis.Tests/RedisResultTests.cs index 27ceba755..47ac20a9e 100644 --- a/tests/StackExchange.Redis.Tests/RedisResultTests.cs +++ b/tests/StackExchange.Redis.Tests/RedisResultTests.cs @@ -5,12 +5,12 @@ namespace StackExchange.Redis.Tests; /// -/// Tests for +/// Tests for . /// public sealed class RedisResultTests { /// - /// Tests the basic functionality of + /// Tests the basic functionality of . /// [Fact] public void ToDictionaryWorks() @@ -29,16 +29,16 @@ public void ToDictionaryWorks() /// /// Tests the basic functionality of - /// when the results contain a nested results array, which is common for lua script results + /// when the results contain a nested results array, which is common for lua script results. /// [Fact] public void ToDictionaryWorksWhenNested() { var redisArrayResult = RedisResult.Create( - new [] + new[] { RedisResult.Create((RedisValue)"one"), - RedisResult.Create(new RedisValue[]{"two", 2, "three", 3}), + RedisResult.Create(new RedisValue[] { "two", 2, "three", 3 }), RedisResult.Create((RedisValue)"four"), RedisResult.Create(new RedisValue[] { "five", 5, "six", 6 }), @@ -67,7 +67,7 @@ public void ToDictionaryFailsWithDuplicateKeys() } /// - /// Tests that correctly uses the provided comparator + /// Tests that correctly uses the provided comparator. /// [Fact] public void ToDictionaryWorksWithCustomComparator() @@ -84,7 +84,7 @@ public void ToDictionaryWorksWithCustomComparator() /// /// Tests that fails when the redis results array contains an odd number - /// of elements. In other words, it's not actually a Key,Value,Key,Value... etc. array + /// of elements. In other words, it's not actually a Key,Value,Key,Value... etc. array. /// [Fact] public void ToDictionaryFailsOnMishapenResults() @@ -92,7 +92,7 @@ public void ToDictionaryFailsOnMishapenResults() var redisArrayResult = RedisResult.Create( new RedisValue[] { "one", 1, "two", 2, "three", 3, "four" /* missing 4 */ }); - Assert.Throws(()=>redisArrayResult.ToDictionary(StringComparer.Ordinal)); + Assert.Throws(() => redisArrayResult.ToDictionary(StringComparer.Ordinal)); } [Fact] @@ -101,8 +101,8 @@ public void SingleResultConvertibleViaTo() var value = RedisResult.Create(123); Assert.StrictEqual((int)123, Convert.ToInt32(value)); Assert.StrictEqual((uint)123U, Convert.ToUInt32(value)); - Assert.StrictEqual((long)123, Convert.ToInt64(value)); - Assert.StrictEqual((ulong)123U, Convert.ToUInt64(value)); + Assert.StrictEqual(123L, Convert.ToInt64(value)); + Assert.StrictEqual(123UL, Convert.ToUInt64(value)); Assert.StrictEqual((byte)123, Convert.ToByte(value)); Assert.StrictEqual((sbyte)123, Convert.ToSByte(value)); Assert.StrictEqual((short)123, Convert.ToInt16(value)); @@ -120,8 +120,8 @@ public void SingleResultConvertibleDirectViaChangeType_Type() var value = RedisResult.Create(123); Assert.StrictEqual((int)123, Convert.ChangeType(value, typeof(int))); Assert.StrictEqual((uint)123U, Convert.ChangeType(value, typeof(uint))); - Assert.StrictEqual((long)123, Convert.ChangeType(value, typeof(long))); - Assert.StrictEqual((ulong)123U, Convert.ChangeType(value, typeof(ulong))); + Assert.StrictEqual(123L, Convert.ChangeType(value, typeof(long))); + Assert.StrictEqual(123UL, Convert.ChangeType(value, typeof(ulong))); Assert.StrictEqual((byte)123, Convert.ChangeType(value, typeof(byte))); Assert.StrictEqual((sbyte)123, Convert.ChangeType(value, typeof(sbyte))); Assert.StrictEqual((short)123, Convert.ChangeType(value, typeof(short))); @@ -139,8 +139,8 @@ public void SingleResultConvertibleDirectViaChangeType_TypeCode() var value = RedisResult.Create(123); Assert.StrictEqual((int)123, Convert.ChangeType(value, TypeCode.Int32)); Assert.StrictEqual((uint)123U, Convert.ChangeType(value, TypeCode.UInt32)); - Assert.StrictEqual((long)123, Convert.ChangeType(value, TypeCode.Int64)); - Assert.StrictEqual((ulong)123U, Convert.ChangeType(value, TypeCode.UInt64)); + Assert.StrictEqual(123L, Convert.ChangeType(value, TypeCode.Int64)); + Assert.StrictEqual(123UL, Convert.ChangeType(value, TypeCode.UInt64)); Assert.StrictEqual((byte)123, Convert.ChangeType(value, TypeCode.Byte)); Assert.StrictEqual((sbyte)123, Convert.ChangeType(value, TypeCode.SByte)); Assert.StrictEqual((short)123, Convert.ChangeType(value, TypeCode.Int16)); diff --git a/tests/StackExchange.Redis.Tests/RedisValueEquivalencyTests.cs b/tests/StackExchange.Redis.Tests/RedisValueEquivalencyTests.cs index 2d9c69fad..7a56d16b0 100644 --- a/tests/StackExchange.Redis.Tests/RedisValueEquivalencyTests.cs +++ b/tests/StackExchange.Redis.Tests/RedisValueEquivalencyTests.cs @@ -9,7 +9,6 @@ public class RedisValueEquivalency { // internal storage types: null, integer, double, string, raw // public perceived types: int, long, double, bool, memory / byte[] - [Fact] public void Int32_Matrix() { diff --git a/tests/StackExchange.Redis.Tests/RespProtocolTests.cs b/tests/StackExchange.Redis.Tests/RespProtocolTests.cs index 6c444e43c..c2cd8a026 100644 --- a/tests/StackExchange.Redis.Tests/RespProtocolTests.cs +++ b/tests/StackExchange.Redis.Tests/RespProtocolTests.cs @@ -132,8 +132,7 @@ public async Task ConnectWithBrokenHello(string command, bool isResp3) [InlineData(@"return {1,2,3}", RedisProtocol.Resp2, ResultType.Array, ResultType.Array, ARR_123)] [InlineData("return nil", RedisProtocol.Resp2, ResultType.BulkString, ResultType.Null, null)] [InlineData(@"return redis.pcall('hgetall', 'key')", RedisProtocol.Resp2, ResultType.Array, ResultType.Array, MAP_ABC)] - [InlineData(@"redis.setresp(3) -return redis.pcall('hgetall', 'key')", RedisProtocol.Resp2, ResultType.Array, ResultType.Array, MAP_ABC)] + [InlineData(@"redis.setresp(3) return redis.pcall('hgetall', 'key')", RedisProtocol.Resp2, ResultType.Array, ResultType.Array, MAP_ABC)] [InlineData("return true", RedisProtocol.Resp2, ResultType.Integer, ResultType.Integer, 1)] [InlineData("return false", RedisProtocol.Resp2, ResultType.BulkString, ResultType.Null, null)] [InlineData("redis.setresp(3) return true", RedisProtocol.Resp2, ResultType.Integer, ResultType.Integer, 1)] @@ -148,8 +147,7 @@ public async Task ConnectWithBrokenHello(string command, bool isResp3) [InlineData("return {1,2,3}", RedisProtocol.Resp3, ResultType.Array, ResultType.Array, ARR_123)] [InlineData("return nil", RedisProtocol.Resp3, ResultType.BulkString, ResultType.Null, null)] [InlineData(@"return redis.pcall('hgetall', 'key')", RedisProtocol.Resp3, ResultType.Array, ResultType.Array, MAP_ABC)] - [InlineData(@"redis.setresp(3) -return redis.pcall('hgetall', 'key')", RedisProtocol.Resp3, ResultType.Array, ResultType.Map, MAP_ABC)] + [InlineData(@"redis.setresp(3) return redis.pcall('hgetall', 'key')", RedisProtocol.Resp3, ResultType.Array, ResultType.Map, MAP_ABC)] [InlineData("return true", RedisProtocol.Resp3, ResultType.Integer, ResultType.Integer, 1)] [InlineData("return false", RedisProtocol.Resp3, ResultType.BulkString, ResultType.Null, null)] [InlineData("redis.setresp(3) return true", RedisProtocol.Resp3, ResultType.Integer, ResultType.Boolean, true)] @@ -230,23 +228,20 @@ public async Task CheckLuaResult(string script, RedisProtocol protocol, ResultTy } } - [Theory] - //[InlineData("return 42", false, ResultType.Integer, ResultType.Integer, 42)] - //[InlineData("return 'abc'", false, ResultType.BulkString, ResultType.BulkString, "abc")] - //[InlineData(@"return {1,2,3}", false, ResultType.Array, ResultType.Array, ARR_123)] - //[InlineData("return nil", false, ResultType.BulkString, ResultType.Null, null)] - //[InlineData(@"return redis.pcall('hgetall', 'key')", false, ResultType.Array, ResultType.Array, MAP_ABC)] - //[InlineData("return true", false, ResultType.Integer, ResultType.Integer, 1)] - - //[InlineData("return 42", true, ResultType.Integer, ResultType.Integer, 42)] - //[InlineData("return 'abc'", true, ResultType.BulkString, ResultType.BulkString, "abc")] - //[InlineData("return {1,2,3}", true, ResultType.Array, ResultType.Array, ARR_123)] - //[InlineData("return nil", true, ResultType.BulkString, ResultType.Null, null)] - //[InlineData(@"return redis.pcall('hgetall', 'key')", true, ResultType.Array, ResultType.Array, MAP_ABC)] - //[InlineData("return true", true, ResultType.Integer, ResultType.Integer, 1)] - - + // [InlineData("return 42", false, ResultType.Integer, ResultType.Integer, 42)] + // [InlineData("return 'abc'", false, ResultType.BulkString, ResultType.BulkString, "abc")] + // [InlineData(@"return {1,2,3}", false, ResultType.Array, ResultType.Array, ARR_123)] + // [InlineData("return nil", false, ResultType.BulkString, ResultType.Null, null)] + // [InlineData(@"return redis.pcall('hgetall', 'key')", false, ResultType.Array, ResultType.Array, MAP_ABC)] + // [InlineData("return true", false, ResultType.Integer, ResultType.Integer, 1)] + + // [InlineData("return 42", true, ResultType.Integer, ResultType.Integer, 42)] + // [InlineData("return 'abc'", true, ResultType.BulkString, ResultType.BulkString, "abc")] + // [InlineData("return {1,2,3}", true, ResultType.Array, ResultType.Array, ARR_123)] + // [InlineData("return nil", true, ResultType.BulkString, ResultType.Null, null)] + // [InlineData(@"return redis.pcall('hgetall', 'key')", true, ResultType.Array, ResultType.Array, MAP_ABC)] + // [InlineData("return true", true, ResultType.Integer, ResultType.Integer, 1)] [InlineData("incrby", RedisProtocol.Resp2, ResultType.Integer, ResultType.Integer, 42, "ikey", 2)] [InlineData("incrby", RedisProtocol.Resp3, ResultType.Integer, ResultType.Integer, 42, "ikey", 2)] [InlineData("incrby", RedisProtocol.Resp2, ResultType.Integer, ResultType.Integer, 2, "nkey", 2)] @@ -322,7 +317,7 @@ public async Task CheckCommandResult(string command, RedisProtocol protocol, Res { var muxer = Create(protocol: protocol); var ep = muxer.GetServerEndPoint(muxer.GetEndPoints().Single()); - if (command == "debug" && args.Length > 0 && args[0] is "protocol" && !ep.GetFeatures().Resp3 /* v6 check */ ) + if (command == "debug" && args.Length > 0 && args[0] is "protocol" && !ep.GetFeatures().Resp3 /* v6 check */) { Skip.Inconclusive("debug protocol not available"); } @@ -341,7 +336,7 @@ public async Task CheckCommandResult(string command, RedisProtocol protocol, Res await db.SetAddAsync("skey", new RedisValue[] { "a", "b", "c" }); break; case "hkey": - await db.HashSetAsync("hkey", new HashEntry[] { new("a", 1), new("b", 2), new("c",3) }); + await db.HashSetAsync("hkey", new HashEntry[] { new("a", 1), new("b", 2), new("c", 3) }); break; } } @@ -382,7 +377,7 @@ public async Task CheckCommandResult(string command, RedisProtocol protocol, Res Log(scontent); if (protocol == RedisProtocol.Resp3) { - Assert.Equal("txt", type); + Assert.Equal("txt", type); } else { @@ -418,14 +413,14 @@ public async Task CheckCommandResult(string command, RedisProtocol protocol, Res Assert.Equal(b ? 1 : 0, result.AsInt64()); break; } - - } +#pragma warning disable SA1310 // Field names should not contain underscore private const string SET_ABC = nameof(SET_ABC); private const string ARR_123 = nameof(ARR_123); private const string MAP_ABC = nameof(MAP_ABC); private const string EMPTY_ARR = nameof(EMPTY_ARR); private const string STR_DAVE = nameof(STR_DAVE); private const string ANY = nameof(ANY); +#pragma warning restore SA1310 // Field names should not contain underscore } diff --git a/tests/StackExchange.Redis.Tests/SSDBTests.cs b/tests/StackExchange.Redis.Tests/SSDBTests.cs index 6f3348892..b05a781b2 100644 --- a/tests/StackExchange.Redis.Tests/SSDBTests.cs +++ b/tests/StackExchange.Redis.Tests/SSDBTests.cs @@ -5,7 +5,7 @@ namespace StackExchange.Redis.Tests; public class SSDBTests : TestBase { - public SSDBTests(ITestOutputHelper output) : base (output) { } + public SSDBTests(ITestOutputHelper output) : base(output) { } [Fact] public void ConnectToSSDB() @@ -15,7 +15,7 @@ public void ConnectToSSDB() using var conn = ConnectionMultiplexer.Connect(new ConfigurationOptions { EndPoints = { { TestConfig.Current.SSDBServer, TestConfig.Current.SSDBPort } }, - CommandMap = CommandMap.SSDB + CommandMap = CommandMap.SSDB, }); RedisKey key = Me(); diff --git a/tests/StackExchange.Redis.Tests/SSLTests.cs b/tests/StackExchange.Redis.Tests/SSLTests.cs index 87e589b97..2a261fe1a 100644 --- a/tests/StackExchange.Redis.Tests/SSLTests.cs +++ b/tests/StackExchange.Redis.Tests/SSLTests.cs @@ -23,10 +23,9 @@ public class SSLTests : TestBase, IClassFixture public SSLTests(ITestOutputHelper output, SSLServerFixture fixture) : base(output) => Fixture = fixture; - [Theory] + [Theory] // (note the 6379 port is closed) [InlineData(null, true)] // auto-infer port (but specify 6380) [InlineData(6380, true)] // all explicit - // (note the 6379 port is closed) public void ConnectToAzure(int? port, bool ssl) { Skip.IfNoConfig(nameof(TestConfig.Config.AzureCacheServer), TestConfig.Current.AzureCacheServer); @@ -82,7 +81,7 @@ public async Task ConnectToSSLServer(bool useSsl, bool specifyHost) }; var map = new Dictionary { - ["config"] = null // don't rely on config working + ["config"] = null, // don't rely on config working }; if (!isAzure) map["cluster"] = null; config.CommandMap = CommandMap.Create(map); @@ -152,18 +151,14 @@ public async Task ConnectToSSLServer(bool useSsl, bool specifyHost) long value = (long)await db.StringGetAsync(key).ForAwait(); watch.Stop(); Assert.Equal(AsyncLoop, value); - Log("F&F: {0} INCR, {1:###,##0}ms, {2} ops/s; final value: {3}", - AsyncLoop, - watch.ElapsedMilliseconds, - (long)(AsyncLoop / watch.Elapsed.TotalSeconds), - value); + Log($"F&F: {AsyncLoop} INCR, {watch.ElapsedMilliseconds:###,##0}ms, {(long)(AsyncLoop / watch.Elapsed.TotalSeconds)} ops/s; final value: {value}"); // perf: sync/multi-threaded // TestConcurrent(db, key, 30, 10); - //TestConcurrent(db, key, 30, 20); - //TestConcurrent(db, key, 30, 30); - //TestConcurrent(db, key, 30, 40); - //TestConcurrent(db, key, 30, 50); + // TestConcurrent(db, key, 30, 20); + // TestConcurrent(db, key, 30, 30); + // TestConcurrent(db, key, 30, 40); + // TestConcurrent(db, key, 30, 50); } else { @@ -176,8 +171,8 @@ public async Task ConnectToSSLServer(bool useSsl, bool specifyHost) // Docker configured with only TLS_AES_256_GCM_SHA384 for testing [Theory] [InlineData(SslProtocols.None, true, TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TlsCipherSuite.TLS_AES_256_GCM_SHA384)] - [InlineData(SslProtocols.Tls12 , true, TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TlsCipherSuite.TLS_AES_256_GCM_SHA384)] - [InlineData(SslProtocols.Tls13 , true, TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TlsCipherSuite.TLS_AES_256_GCM_SHA384)] + [InlineData(SslProtocols.Tls12, true, TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TlsCipherSuite.TLS_AES_256_GCM_SHA384)] + [InlineData(SslProtocols.Tls13, true, TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TlsCipherSuite.TLS_AES_256_GCM_SHA384)] [InlineData(SslProtocols.Tls12, false, TlsCipherSuite.TLS_AES_128_CCM_8_SHA256)] [InlineData(SslProtocols.Tls12, true)] [InlineData(SslProtocols.Tls13, true)] @@ -209,8 +204,8 @@ public async Task ConnectSslClientAuthenticationOptions(SslProtocols protocols, Log(" Errors: " + errors); Log(" Cert issued to: " + cert?.Subject); return true; - } - } + }, + }, }; try @@ -258,9 +253,14 @@ public void RedisLabsSSL() EndPoints = { { TestConfig.Current.RedisLabsSslServer, TestConfig.Current.RedisLabsSslPort } }, ConnectTimeout = timeout, AllowAdmin = true, - CommandMap = CommandMap.Create(new HashSet { - "subscribe", "unsubscribe", "cluster" - }, false) + CommandMap = CommandMap.Create( + new HashSet + { + "subscribe", + "unsubscribe", + "cluster", + }, + false), }; options.TrustIssuer("redislabs_ca.pem"); @@ -270,10 +270,7 @@ public void RedisLabsSSL() ConnectionMultiplexer.EchoPath = Me(); #endif options.Ssl = true; - options.CertificateSelection += delegate - { - return cert; - }; + options.CertificateSelection += (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => cert; using var conn = ConnectionMultiplexer.Connect(options); @@ -320,9 +317,14 @@ public void RedisLabsEnvironmentVariableClientCertificate(bool setEnv) EndPoints = { { TestConfig.Current.RedisLabsSslServer, TestConfig.Current.RedisLabsSslPort } }, ConnectTimeout = timeout, AllowAdmin = true, - CommandMap = CommandMap.Create(new HashSet { - "subscribe", "unsubscribe", "cluster" - }, false) + CommandMap = CommandMap.Create( + new HashSet + { + "subscribe", + "unsubscribe", + "cluster", + }, + false), }; if (!Directory.Exists(Me())) Directory.CreateDirectory(Me()); @@ -366,19 +368,18 @@ public void SSLHostInferredFromEndpoints() { var options = new ConfigurationOptions { - EndPoints = { - { "mycache.rediscache.windows.net", 15000}, - { "mycache.rediscache.windows.net", 15001 }, - { "mycache.rediscache.windows.net", 15002 }, - }, + EndPoints = + { + { "mycache.rediscache.windows.net", 15000 }, + { "mycache.rediscache.windows.net", 15001 }, + { "mycache.rediscache.windows.net", 15002 }, + }, Ssl = true, }; Assert.True(options.SslHost == "mycache.rediscache.windows.net"); options = new ConfigurationOptions() { - EndPoints = { - { "121.23.23.45", 15000}, - } + EndPoints = { { "121.23.23.45", 15000 } }, }; Assert.True(options.SslHost == null); } @@ -453,7 +454,7 @@ public void SSLParseViaConfig_Issue883_ConfigObject() SyncTimeout = 5000, DefaultDatabase = 0, EndPoints = { { TestConfig.Current.AzureCacheServer, 6380 } }, - Password = TestConfig.Current.AzureCachePassword + Password = TestConfig.Current.AzureCachePassword, }; options.CertificateValidation += ShowCertFailures(Writer); @@ -538,7 +539,7 @@ public void ConfigObject_Issue1407_ToStringIncludesSslProtocols() SyncTimeout = 5000, DefaultDatabase = 0, EndPoints = { { "endpoint.test", 6380 } }, - Password = "123456" + Password = "123456", }; var targetOptions = ConfigurationOptions.Parse(sourceOptions.ToString()); diff --git a/tests/StackExchange.Redis.Tests/SanityCheckTests.cs b/tests/StackExchange.Redis.Tests/SanityCheckTests.cs index e1a2de977..353098fd5 100644 --- a/tests/StackExchange.Redis.Tests/SanityCheckTests.cs +++ b/tests/StackExchange.Redis.Tests/SanityCheckTests.cs @@ -1,7 +1,7 @@ using System; using System.IO; -using System.Reflection.PortableExecutable; using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; using Xunit; namespace StackExchange.Redis.Tests; @@ -9,11 +9,11 @@ namespace StackExchange.Redis.Tests; public sealed class SanityChecks { /// - /// Ensure we don't reference System.ValueTuple as it causes issues with .NET Full Framework + /// Ensure we don't reference System.ValueTuple as it causes issues with .NET Full Framework. /// /// /// Modified from . - /// Thanks Lucas Trzesniewski! + /// Thanks Lucas Trzesniewski!. /// [Fact] public void ValueTupleNotReferenced() diff --git a/tests/StackExchange.Redis.Tests/ScanTests.cs b/tests/StackExchange.Redis.Tests/ScanTests.cs index bcab2da4c..4524aed9f 100644 --- a/tests/StackExchange.Redis.Tests/ScanTests.cs +++ b/tests/StackExchange.Redis.Tests/ScanTests.cs @@ -3,7 +3,6 @@ using System.Linq; using Xunit; using Xunit.Abstractions; -// ReSharper disable PossibleMultipleEnumeration namespace StackExchange.Redis.Tests; @@ -146,7 +145,6 @@ public void ScanResume() // page size, with zero guarantees; in this particular test, the first page actually has 19 elements, for example. So: we cannot // make the following assertion: // Assert.Equal(12, snapOffset); - seq = server.Keys(dbId, prefix + ":*", pageSize: 15, cursor: snapCursor, pageOffset: snapOffset); var seqCur = (IScanningCursor)seq; Assert.Equal(snapCursor, seqCur.Cursor); @@ -257,7 +255,7 @@ public void SortedSetScan(bool supported) Assert.Equal(2, basicArr[1].Score); Assert.Equal(3, basicArr[2].Score); basic = basicArr.ToDictionary(); - Assert.Equal(3, basic.Count); //asc + Assert.Equal(3, basic.Count); // asc Assert.Equal(1, basic["a"]); Assert.Equal(2, basic["b"]); Assert.Equal(3, basic["c"]); @@ -364,7 +362,7 @@ private static bool GotCursors(IConnectionMultiplexer conn, RedisKey key, int co var found = false; var response = db.HashScan(key); - var cursor = ((IScanningCursor)response); + var cursor = (IScanningCursor)response; foreach (var _ in response) { if (cursor.Cursor > 0) diff --git a/tests/StackExchange.Redis.Tests/ScriptingTests.cs b/tests/StackExchange.Redis.Tests/ScriptingTests.cs index 35bfbf36d..bbacb96bd 100644 --- a/tests/StackExchange.Redis.Tests/ScriptingTests.cs +++ b/tests/StackExchange.Redis.Tests/ScriptingTests.cs @@ -36,10 +36,14 @@ public async Task BasicScripting() using var conn = GetScriptConn(); var db = conn.GetDatabase(); - var noCache = db.ScriptEvaluateAsync("return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", - new RedisKey[] { "key1", "key2" }, new RedisValue[] { "first", "second" }); - var cache = db.ScriptEvaluateAsync("return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", - new RedisKey[] { "key1", "key2" }, new RedisValue[] { "first", "second" }); + var noCache = db.ScriptEvaluateAsync( + "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", + new RedisKey[] { "key1", "key2" }, + new RedisValue[] { "first", "second" }); + var cache = db.ScriptEvaluateAsync( + "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", + new RedisKey[] { "key1", "key2" }, + new RedisValue[] { "first", "second" }); var results = (string[]?)await noCache; Assert.NotNull(results); Assert.Equal(4, results.Length); @@ -144,8 +148,8 @@ public async Task MultiIncrByWithoutReplies() db.StringIncrement(prefix + "c", flags: CommandFlags.FireAndForget); db.StringIncrement(prefix + "c", flags: CommandFlags.FireAndForget); - //run the script, passing "a", "b", "c" and 1,2,3 - // increment a &b by 1, c twice + // run the script, passing "a", "b", "c" and 1,2,3 + // increment a & b by 1, c twice var result = db.ScriptEvaluateAsync( "for i,key in ipairs(KEYS) do redis.call('incrby', key, ARGV[i]) end", new RedisKey[] { prefix + "a", prefix + "b", prefix + "c" }, // <== aka "KEYS" in the script @@ -190,7 +194,7 @@ public void FlushDetection() // now cause all kinds of problems GetServer(conn).ScriptFlush(); - //expect this one to fail just work fine (self-fix) + // expect this one to fail just work fine (self-fix) db.ScriptEvaluate("return redis.call('get', KEYS[1])", new RedisKey[] { key }, null); result = (string?)db.ScriptEvaluate("return redis.call('get', KEYS[1])", new RedisKey[] { key }, null); @@ -210,7 +214,7 @@ public void PrepareScript() server.ScriptLoad(scripts[0]); server.ScriptLoad(scripts[1]); - //when known to exist + // when known to exist server.ScriptLoad(scripts[0]); server.ScriptLoad(scripts[1]); } @@ -218,15 +222,15 @@ public void PrepareScript() { var server = GetServer(conn); - //when vanilla + // when vanilla server.ScriptLoad(scripts[0]); server.ScriptLoad(scripts[1]); - //when known to exist + // when known to exist server.ScriptLoad(scripts[0]); server.ScriptLoad(scripts[1]); - //when known to exist + // when known to exist server.ScriptLoad(scripts[0]); server.ScriptLoad(scripts[1]); } @@ -317,8 +321,11 @@ public async Task ChangeDbInScript() Log("Key: " + key); var db = conn.GetDatabase(2); - var evalResult = db.ScriptEvaluateAsync(@"redis.call('select', 1) - return redis.call('get','" + key + "')", null, null); + var evalResult = db.ScriptEvaluateAsync( + @"redis.call('select', 1) + return redis.call('get','" + key + "')", + null, + null); var getResult = db.StringGetAsync(key); Assert.Equal("db 1", (string?)await evalResult); @@ -337,8 +344,11 @@ public async Task ChangeDbInTranScript() var db = conn.GetDatabase(2); var tran = db.CreateTransaction(); - var evalResult = tran.ScriptEvaluateAsync(@"redis.call('select', 1) - return redis.call('get','" + key + "')", null, null); + var evalResult = tran.ScriptEvaluateAsync( + @"redis.call('select', 1) + return redis.call('get','" + key + "')", + null, + null); var getResult = tran.StringGetAsync(key); Assert.True(tran.Execute()); @@ -358,13 +368,17 @@ public void TestBasicScripting() db.KeyDelete(key, CommandFlags.FireAndForget); db.HashSet(key, "id", 123, flags: CommandFlags.FireAndForget); - var wasSet = (bool)db.ScriptEvaluate("if redis.call('hexists', KEYS[1], 'UniqueId') then return redis.call('hset', KEYS[1], 'UniqueId', ARGV[1]) else return 0 end", - new[] { key }, new[] { newId }); + var wasSet = (bool)db.ScriptEvaluate( + "if redis.call('hexists', KEYS[1], 'UniqueId') then return redis.call('hset', KEYS[1], 'UniqueId', ARGV[1]) else return 0 end", + new[] { key }, + new[] { newId }); Assert.True(wasSet); - wasSet = (bool)db.ScriptEvaluate("if redis.call('hexists', KEYS[1], 'UniqueId') then return redis.call('hset', KEYS[1], 'UniqueId', ARGV[1]) else return 0 end", - new[] { key }, new[] { newId }); + wasSet = (bool)db.ScriptEvaluate( + "if redis.call('hexists', KEYS[1], 'UniqueId') then return redis.call('hset', KEYS[1], 'UniqueId', ARGV[1]) else return 0 end", + new[] { key }, + new[] { newId }); Assert.False(wasSet); } @@ -460,9 +474,7 @@ public void CompareScriptToDirect() Assert.Equal(LOOP, (long)scriptResult); Assert.Equal(LOOP, directResult); - Log("script: {0}ms; direct: {1}ms", - scriptTime.TotalMilliseconds, - directTime.TotalMilliseconds); + Log("script: {0}ms; direct: {1}ms", scriptTime.TotalMilliseconds, directTime.TotalMilliseconds); } [Fact] @@ -505,6 +517,7 @@ public void SimpleLuaScript() var db = conn.GetDatabase(); + // Scopes for repeated use { var val = prepared.Evaluate(db, new { ident = "hello" }); Assert.Equal("hello", (string?)val); @@ -556,6 +569,7 @@ public void SimpleRawScriptEvaluate() var db = conn.GetDatabase(); + // Scopes for repeated use { var val = db.ScriptEvaluate(Script, values: new RedisValue[] { "hello" }); Assert.Equal("hello", (string?)val); @@ -671,6 +685,7 @@ public void SimpleLoadedLuaScript() var db = conn.GetDatabase(); + // Scopes for repeated use { var val = loaded.Evaluate(db, new { ident = "hello" }); Assert.Equal("hello", (string?)val); @@ -836,7 +851,7 @@ public void LuaScriptPrefixedKeys() Assert.Equal("prefix-" + key, keys[0]); Assert.NotNull(args); Assert.Equal(2, args.Length); - Assert.Equal("prefix-" + key, args[0]); + Assert.Equal("prefix-" + key, args[0]); Assert.Equal("hello", args[1]); } diff --git a/tests/StackExchange.Redis.Tests/SecureTests.cs b/tests/StackExchange.Redis.Tests/SecureTests.cs index 9763cc15f..35e9dd580 100644 --- a/tests/StackExchange.Redis.Tests/SecureTests.cs +++ b/tests/StackExchange.Redis.Tests/SecureTests.cs @@ -11,7 +11,7 @@ public class SecureTests : TestBase protected override string GetConfiguration() => TestConfig.Current.SecureServerAndPort + ",password=" + TestConfig.Current.SecurePassword + ",name=MyClient"; - public SecureTests(ITestOutputHelper output) : base (output) { } + public SecureTests(ITestOutputHelper output) : base(output) { } [Fact] public void MassiveBulkOpsFireAndForgetSecure() @@ -31,8 +31,7 @@ public void MassiveBulkOpsFireAndForgetSecure() int val = (int)db.StringGet(key); Assert.Equal(AsyncOpsQty, val); watch.Stop(); - Log("{2}: Time for {0} ops: {1}ms (any order); ops/s: {3}", AsyncOpsQty, watch.ElapsedMilliseconds, Me(), - AsyncOpsQty / watch.Elapsed.TotalSeconds); + Log("{2}: Time for {0} ops: {1}ms (any order); ops/s: {3}", AsyncOpsQty, watch.ElapsedMilliseconds, Me(), AsyncOpsQty / watch.Elapsed.TotalSeconds); } [Fact] diff --git a/tests/StackExchange.Redis.Tests/SentinelTests.cs b/tests/StackExchange.Redis.Tests/SentinelTests.cs index 49e96a82d..3fc2afd4e 100644 --- a/tests/StackExchange.Redis.Tests/SentinelTests.cs +++ b/tests/StackExchange.Redis.Tests/SentinelTests.cs @@ -95,8 +95,7 @@ public void SentinelConnectTest() var db = conn.GetDatabase(); var test = db.Ping(); - Log("ping to sentinel {0}:{1} took {2} ms", TestConfig.Current.SentinelServer, - TestConfig.Current.SentinelPortA, test.TotalMilliseconds); + Log("ping to sentinel {0}:{1} took {2} ms", TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortA, test.TotalMilliseconds); } [Fact] @@ -116,8 +115,7 @@ public void SentinelRepeatConnectTest() var db = conn.GetDatabase(); var test = db.Ping(); - Log("ping to 1st sentinel {0}:{1} took {2} ms", TestConfig.Current.SentinelServer, - TestConfig.Current.SentinelPortA, test.TotalMilliseconds); + Log("ping to 1st sentinel {0}:{1} took {2} ms", TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortA, test.TotalMilliseconds); Log("Service Name: " + options.ServiceName); foreach (var ep in options.EndPoints) @@ -129,8 +127,7 @@ public void SentinelRepeatConnectTest() var db2 = conn2.GetDatabase(); var test2 = db2.Ping(); - Log("ping to 2nd sentinel {0}:{1} took {2} ms", TestConfig.Current.SentinelServer, - TestConfig.Current.SentinelPortA, test2.TotalMilliseconds); + Log("ping to 2nd sentinel {0}:{1} took {2} ms", TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortA, test2.TotalMilliseconds); } [Fact] @@ -142,8 +139,7 @@ public async Task SentinelConnectAsyncTest() var db = conn.GetDatabase(); var test = await db.PingAsync(); - Log("ping to sentinel {0}:{1} took {2} ms", TestConfig.Current.SentinelServer, - TestConfig.Current.SentinelPortA, test.TotalMilliseconds); + Log("ping to sentinel {0}:{1} took {2} ms", TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortA, test.TotalMilliseconds); } [Fact] @@ -163,14 +159,11 @@ public void SentinelRole() public void PingTest() { var test = SentinelServerA.Ping(); - Log("ping to sentinel {0}:{1} took {2} ms", TestConfig.Current.SentinelServer, - TestConfig.Current.SentinelPortA, test.TotalMilliseconds); + Log("ping to sentinel {0}:{1} took {2} ms", TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortA, test.TotalMilliseconds); test = SentinelServerB.Ping(); - Log("ping to sentinel {0}:{1} took {1} ms", TestConfig.Current.SentinelServer, - TestConfig.Current.SentinelPortB, test.TotalMilliseconds); + Log("ping to sentinel {0}:{1} took {1} ms", TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortB, test.TotalMilliseconds); test = SentinelServerC.Ping(); - Log("ping to sentinel {0}:{1} took {1} ms", TestConfig.Current.SentinelServer, - TestConfig.Current.SentinelPortC, test.TotalMilliseconds); + Log("ping to sentinel {0}:{1} took {1} ms", TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortC, test.TotalMilliseconds); } [Fact] @@ -260,9 +253,10 @@ public void SentinelSentinelsTest() { var sentinels = SentinelServerA.SentinelSentinels(ServiceName); - var expected = new List { + var expected = new List + { SentinelServerB.EndPoint.ToString(), - SentinelServerC.EndPoint.ToString() + SentinelServerC.EndPoint.ToString(), }; var actual = new List(); @@ -282,9 +276,11 @@ public void SentinelSentinelsTest() var data = kv.ToDictionary(); actual.Add(data["ip"] + ":" + data["port"]); } - expected = new List { + + expected = new List + { SentinelServerA.EndPoint.ToString(), - SentinelServerC.EndPoint.ToString() + SentinelServerC.EndPoint.ToString(), }; Assert.All(expected, ep => Assert.NotEqual(ep, SentinelServerB.EndPoint.ToString())); @@ -297,9 +293,11 @@ public void SentinelSentinelsTest() var data = kv.ToDictionary(); actual.Add(data["ip"] + ":" + data["port"]); } - expected = new List { + + expected = new List + { SentinelServerA.EndPoint.ToString(), - SentinelServerB.EndPoint.ToString() + SentinelServerB.EndPoint.ToString(), }; Assert.All(expected, ep => Assert.NotEqual(ep, SentinelServerC.EndPoint.ToString())); @@ -311,9 +309,10 @@ public void SentinelSentinelsTest() public async Task SentinelSentinelsAsyncTest() { var sentinels = await SentinelServerA.SentinelSentinelsAsync(ServiceName).ForAwait(); - var expected = new List { + var expected = new List + { SentinelServerB.EndPoint.ToString(), - SentinelServerC.EndPoint.ToString() + SentinelServerC.EndPoint.ToString(), }; var actual = new List(); @@ -322,15 +321,17 @@ public async Task SentinelSentinelsAsyncTest() var data = kv.ToDictionary(); actual.Add(data["ip"] + ":" + data["port"]); } + Assert.All(expected, ep => Assert.NotEqual(ep, SentinelServerA.EndPoint.ToString())); Assert.True(sentinels.Length == 2); Assert.All(expected, ep => Assert.Contains(ep, actual, _ipComparer)); sentinels = await SentinelServerB.SentinelSentinelsAsync(ServiceName).ForAwait(); - expected = new List { + expected = new List + { SentinelServerA.EndPoint.ToString(), - SentinelServerC.EndPoint.ToString() + SentinelServerC.EndPoint.ToString(), }; actual = new List(); @@ -339,14 +340,16 @@ public async Task SentinelSentinelsAsyncTest() var data = kv.ToDictionary(); actual.Add(data["ip"] + ":" + data["port"]); } + Assert.All(expected, ep => Assert.NotEqual(ep, SentinelServerB.EndPoint.ToString())); Assert.True(sentinels.Length == 2); Assert.All(expected, ep => Assert.Contains(ep, actual, _ipComparer)); sentinels = await SentinelServerC.SentinelSentinelsAsync(ServiceName).ForAwait(); - expected = new List { + expected = new List + { SentinelServerA.EndPoint.ToString(), - SentinelServerB.EndPoint.ToString() + SentinelServerB.EndPoint.ToString(), }; actual = new List(); foreach (var kv in sentinels) @@ -354,6 +357,7 @@ public async Task SentinelSentinelsAsyncTest() var data = kv.ToDictionary(); actual.Add(data["ip"] + ":" + data["port"]); } + Assert.All(expected, ep => Assert.NotEqual(ep, SentinelServerC.EndPoint.ToString())); Assert.True(sentinels.Length == 2); Assert.All(expected, ep => Assert.Contains(ep, actual, _ipComparer)); @@ -470,7 +474,5 @@ public async Task ReadOnlyConnectionReplicasTest() var db = readonlyConn.GetDatabase(); var s = db.StringGet("test"); Assert.True(s.IsNullOrEmpty); - //var ex = Assert.Throws(() => db.StringSet("test", "try write to read only instance")); - //Assert.StartsWith("No connection is available to service this operation", ex.Message); } } diff --git a/tests/StackExchange.Redis.Tests/SetTests.cs b/tests/StackExchange.Redis.Tests/SetTests.cs index d90e4a8c3..22df40be7 100644 --- a/tests/StackExchange.Redis.Tests/SetTests.cs +++ b/tests/StackExchange.Redis.Tests/SetTests.cs @@ -90,9 +90,9 @@ public void SetIntersectionLength() db.KeyDelete(key2, CommandFlags.FireAndForget); db.SetAdd(key2, new RedisValue[] { 1, 2, 3, 4, 5 }, CommandFlags.FireAndForget); - Assert.Equal(4, db.SetIntersectionLength(new RedisKey[]{ key1, key2})); + Assert.Equal(4, db.SetIntersectionLength(new RedisKey[] { key1, key2 })); // with limit - Assert.Equal(3, db.SetIntersectionLength(new RedisKey[]{ key1, key2}, 3)); + Assert.Equal(3, db.SetIntersectionLength(new RedisKey[] { key1, key2 }, 3)); // Missing keys should be 0 var key3 = Me() + "3"; @@ -116,9 +116,9 @@ public async Task SetIntersectionLengthAsync() db.KeyDelete(key2, CommandFlags.FireAndForget); db.SetAdd(key2, new RedisValue[] { 1, 2, 3, 4, 5 }, CommandFlags.FireAndForget); - Assert.Equal(4, await db.SetIntersectionLengthAsync(new RedisKey[]{ key1, key2})); + Assert.Equal(4, await db.SetIntersectionLengthAsync(new RedisKey[] { key1, key2 })); // with limit - Assert.Equal(3, await db.SetIntersectionLengthAsync(new RedisKey[]{ key1, key2}, 3)); + Assert.Equal(3, await db.SetIntersectionLengthAsync(new RedisKey[] { key1, key2 }, 3)); // Missing keys should be 0 var key3 = Me() + "3"; @@ -356,10 +356,10 @@ public async Task TestSortReadonlyPrimary() var random = new Random(); var items = Enumerable.Repeat(0, 200).Select(_ => random.Next()).ToList(); - await db.SetAddAsync(key, items.Select(x=>(RedisValue)x).ToArray()); + await db.SetAddAsync(key, items.Select(x => (RedisValue)x).ToArray()); items.Sort(); - var result = db.Sort(key).Select(x=>(int)x); + var result = db.Sort(key).Select(x => (int)x); Assert.Equal(items, result); result = (await db.SortAsync(key)).Select(x => (int)x); @@ -377,7 +377,7 @@ public async Task TestSortReadonlyReplica() var random = new Random(); var items = Enumerable.Repeat(0, 200).Select(_ => random.Next()).ToList(); - await db.SetAddAsync(key, items.Select(x=>(RedisValue)x).ToArray()); + await db.SetAddAsync(key, items.Select(x => (RedisValue)x).ToArray()); using var readonlyConn = Create(configuration: TestConfig.Current.ReplicaServerAndPort, require: RedisFeatures.v7_0_0_rc1); var readonlyDb = conn.GetDatabase(); diff --git a/tests/StackExchange.Redis.Tests/SocketTests.cs b/tests/StackExchange.Redis.Tests/SocketTests.cs index 10723d7d0..71a1ffe47 100644 --- a/tests/StackExchange.Redis.Tests/SocketTests.cs +++ b/tests/StackExchange.Redis.Tests/SocketTests.cs @@ -6,7 +6,7 @@ namespace StackExchange.Redis.Tests; public class SocketTests : TestBase { protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort; - public SocketTests(ITestOutputHelper output) : base (output) { } + public SocketTests(ITestOutputHelper output) : base(output) { } [FactLongRunning] public void CheckForSocketLeaks() diff --git a/tests/StackExchange.Redis.Tests/SortedSetTests.cs b/tests/StackExchange.Redis.Tests/SortedSetTests.cs index 49c464142..9bcd02e2e 100644 --- a/tests/StackExchange.Redis.Tests/SortedSetTests.cs +++ b/tests/StackExchange.Redis.Tests/SortedSetTests.cs @@ -22,7 +22,7 @@ public SortedSetTests(ITestOutputHelper output, SharedConnectionFixture fixture) new SortedSetEntry("g", 7), new SortedSetEntry("h", 8), new SortedSetEntry("i", 9), - new SortedSetEntry("j", 10) + new SortedSetEntry("j", 10), }; private static readonly SortedSetEntry[] entriesPow2 = new SortedSetEntry[] @@ -36,7 +36,7 @@ public SortedSetTests(ITestOutputHelper output, SharedConnectionFixture fixture) new SortedSetEntry("g", 64), new SortedSetEntry("h", 128), new SortedSetEntry("i", 256), - new SortedSetEntry("j", 512) + new SortedSetEntry("j", 512), }; private static readonly SortedSetEntry[] entriesPow3 = new SortedSetEntry[] @@ -59,7 +59,7 @@ public SortedSetTests(ITestOutputHelper output, SharedConnectionFixture fixture) new SortedSetEntry("g", 0), new SortedSetEntry("h", 0), new SortedSetEntry("i", 0), - new SortedSetEntry("j", 0) + new SortedSetEntry("j", 0), }; [Fact] @@ -1051,7 +1051,10 @@ public void SortedSetMultiPopSingleKey() var key = Me(); db.KeyDelete(key); - db.SortedSetAdd(key, new SortedSetEntry[] { + db.SortedSetAdd( + key, + new SortedSetEntry[] + { new SortedSetEntry("rays", 100), new SortedSetEntry("yankees", 92), new SortedSetEntry("red sox", 92), @@ -1085,7 +1088,10 @@ public void SortedSetMultiPopMultiKey() var key = Me(); db.KeyDelete(key); - db.SortedSetAdd(key, new SortedSetEntry[] { + db.SortedSetAdd( + key, + new SortedSetEntry[] + { new SortedSetEntry("rays", 100), new SortedSetEntry("yankees", 92), new SortedSetEntry("red sox", 92), @@ -1143,7 +1149,10 @@ public async Task SortedSetMultiPopAsync() var key = Me(); db.KeyDelete(key); - db.SortedSetAdd(key, new SortedSetEntry[] { + db.SortedSetAdd( + key, + new SortedSetEntry[] + { new SortedSetEntry("rays", 100), new SortedSetEntry("yankees", 92), new SortedSetEntry("red sox", 92), @@ -1451,7 +1460,7 @@ public async Task SortedSetUpdate() var db = conn.GetDatabase(); var key = Me(); var member = "a"; - var values = new SortedSetEntry[] {new SortedSetEntry(member, 5)}; + var values = new SortedSetEntry[] { new SortedSetEntry(member, 5) }; db.KeyDelete(key, CommandFlags.FireAndForget); db.SortedSetAdd(key, member, 2); @@ -1459,6 +1468,6 @@ public async Task SortedSetUpdate() Assert.Equal(1, db.SortedSetUpdate(key, values)); Assert.True(await db.SortedSetUpdateAsync(key, member, 1)); - Assert.Equal(1,await db.SortedSetUpdateAsync(key, values)); + Assert.Equal(1, await db.SortedSetUpdateAsync(key, values)); } } diff --git a/tests/StackExchange.Redis.Tests/StreamTests.cs b/tests/StackExchange.Redis.Tests/StreamTests.cs index fefff3b02..0ea744848 100644 --- a/tests/StackExchange.Redis.Tests/StreamTests.cs +++ b/tests/StackExchange.Redis.Tests/StreamTests.cs @@ -96,9 +96,9 @@ public void StreamAddMultipleValuePairsWithManualId() var fields = new[] { - new NameValueEntry("field1", "value1"), - new NameValueEntry("field2", "value2") - }; + new NameValueEntry("field1", "value1"), + new NameValueEntry("field2", "value2"), + }; var messageId = db.StreamAdd(key, fields, id); var entries = db.StreamRange(key); @@ -754,12 +754,15 @@ public void StreamConsumerGroupClaimMessages() // Claim the 3 messages consumed by consumer2 for consumer1. // Get the pending messages for consumer2. - var pendingMessages = db.StreamPendingMessages(key, groupName, + var pendingMessages = db.StreamPendingMessages( + key, + groupName, 10, consumer2); // Claim the messages for consumer1. - var messages = db.StreamClaim(key, + var messages = db.StreamClaim( + key, groupName, consumer1, 0, // Min message idle time @@ -801,12 +804,15 @@ public void StreamConsumerGroupClaimMessagesReturningIds() // Claim the 3 messages consumed by consumer2 for consumer1. // Get the pending messages for consumer2. - var pendingMessages = db.StreamPendingMessages(key, groupName, + var pendingMessages = db.StreamPendingMessages( + key, + groupName, 10, consumer2); // Claim the messages for consumer1. - var messageIds = db.StreamClaimIdsOnly(key, + var messageIds = db.StreamClaimIdsOnly( + key, groupName, consumer1, 0, // Min message idle time @@ -827,7 +833,6 @@ public void StreamConsumerGroupReadMultipleOneReadBeginningOneReadNew() // Ask redis to read from the beginning of both stream, expect messages // for only the stream set to read from the beginning. - using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); @@ -851,10 +856,10 @@ public void StreamConsumerGroupReadMultipleOneReadBeginningOneReadNew() // Read for both streams from the beginning. We shouldn't get anything back for stream1. var pairs = new[] { - // StreamPosition.NewMessages will send ">" which indicates "Undelivered" messages. - new StreamPosition(stream1, StreamPosition.NewMessages), - new StreamPosition(stream2, StreamPosition.NewMessages) - }; + // StreamPosition.NewMessages will send ">" which indicates "Undelivered" messages. + new StreamPosition(stream1, StreamPosition.NewMessages), + new StreamPosition(stream2, StreamPosition.NewMessages), + }; var streams = db.StreamReadGroup(pairs, groupName, "test_consumer"); @@ -884,9 +889,9 @@ public void StreamConsumerGroupReadMultipleOnlyNewMessagesExpectNoResult() // We shouldn't get anything for either stream. var pairs = new[] { - new StreamPosition(stream1, StreamPosition.Beginning), - new StreamPosition(stream2, StreamPosition.Beginning) - }; + new StreamPosition(stream1, StreamPosition.Beginning), + new StreamPosition(stream2, StreamPosition.Beginning), + }; var streams = db.StreamReadGroup(pairs, groupName, "test_consumer"); @@ -921,9 +926,9 @@ public void StreamConsumerGroupReadMultipleOnlyNewMessagesExpect1Result() // Read the new messages (messages created after the group was created). var pairs = new[] { - new StreamPosition(stream1, StreamPosition.NewMessages), - new StreamPosition(stream2, StreamPosition.NewMessages) - }; + new StreamPosition(stream1, StreamPosition.NewMessages), + new StreamPosition(stream2, StreamPosition.NewMessages), + }; var streams = db.StreamReadGroup(pairs, groupName, "test_consumer"); @@ -958,10 +963,10 @@ public void StreamConsumerGroupReadMultipleRestrictCount() var pairs = new[] { - // Read after the first id in both streams - new StreamPosition(stream1, StreamPosition.NewMessages), - new StreamPosition(stream2, StreamPosition.NewMessages) - }; + // Read after the first id in both streams + new StreamPosition(stream1, StreamPosition.NewMessages), + new StreamPosition(stream2, StreamPosition.NewMessages), + }; // Restrict the count to 2 (expect only 1 message from first stream, 2 from the second). var streams = db.StreamReadGroup(pairs, groupName, "test_consumer", 2); @@ -1008,7 +1013,8 @@ public void StreamConsumerGroupViewPendingInfoWhenNothingPending() db.StreamCreateConsumerGroup(key, groupName, "0-0"); - var pendingMessages = db.StreamPendingMessages(key, + var pendingMessages = db.StreamPendingMessages( + key, groupName, 10, consumerName: RedisValue.Null); @@ -1117,7 +1123,8 @@ public void StreamConsumerGroupViewPendingMessageInfoForConsumer() db.StreamReadGroup(key, groupName, consumer2); // Get the pending info about the messages themselves. - var pendingMessageInfoList = db.StreamPendingMessages(key, + var pendingMessageInfoList = db.StreamPendingMessages( + key, groupName, 10, consumer2); @@ -1350,7 +1357,6 @@ public void StreamInfoGetWithEmptyStream() // Add an entry and then delete it so the stream is empty, then run streaminfo // to ensure it functions properly on an empty stream. Namely, the first-entry // and last-entry messages should be null. - var id = db.StreamAdd(key, "field1", "value1"); db.StreamDelete(key, new[] { id }); @@ -1538,7 +1544,7 @@ public void StreamReadExpectedExceptionInvalidCountMultipleStream() var streamPositions = new[] { new StreamPosition("key1", "0-0"), - new StreamPosition("key2", "0-0") + new StreamPosition("key2", "0-0"), }; Assert.Throws(() => db.StreamRead(streamPositions, 0)); } @@ -1589,9 +1595,9 @@ public void StreamReadMultipleStreams() // Read from both streams at the same time. var streamList = new[] { - new StreamPosition(key1, "0-0"), - new StreamPosition(key2, "0-0") - }; + new StreamPosition(key1, "0-0"), + new StreamPosition(key2, "0-0"), + }; var streams = db.StreamRead(streamList); @@ -1650,7 +1656,6 @@ public void StreamReadMultipleStreamsLastMessage() Assert.Equal(new[] { new NameValueEntry("field8", "value8") }, stream2.Entries[0].Values); } - [Fact] public void StreamReadMultipleStreamsWithCount() { @@ -1667,9 +1672,9 @@ public void StreamReadMultipleStreamsWithCount() var streamList = new[] { - new StreamPosition(key1, "0-0"), - new StreamPosition(key2, "0-0") - }; + new StreamPosition(key1, "0-0"), + new StreamPosition(key2, "0-0"), + }; var streams = db.StreamRead(streamList, countPerStream: 1); @@ -1701,11 +1706,11 @@ public void StreamReadMultipleStreamsWithReadPastSecondStream() var streamList = new[] { - new StreamPosition(key1, "0-0"), + new StreamPosition(key1, "0-0"), - // read past the end of stream # 2 - new StreamPosition(key2, id4) - }; + // read past the end of stream # 2 + new StreamPosition(key2, id4), + }; var streams = db.StreamRead(streamList); @@ -1732,10 +1737,10 @@ public void StreamReadMultipleStreamsWithEmptyResponse() var streamList = new[] { - // Read past the end of both streams. - new StreamPosition(key1, id2), - new StreamPosition(key2, id4) - }; + // Read past the end of both streams. + new StreamPosition(key1, id2), + new StreamPosition(key2, id4), + }; var streams = db.StreamRead(streamList); @@ -1755,7 +1760,6 @@ public void StreamReadPastEndOfStream() var id2 = db.StreamAdd(key, "field2", "value2"); // Read after the final ID in the stream, we expect an empty array as a response. - var entries = db.StreamRead(key, id2); Assert.Empty(entries); @@ -1964,7 +1968,8 @@ public void StreamReadGroupWithNoAckShowsNoPendingMessages() db.StreamCreateConsumerGroup(key, groupName, StreamPosition.NewMessages); - db.StreamReadGroup(key, + db.StreamReadGroup( + key, groupName, consumer, StreamPosition.NewMessages, @@ -1995,10 +2000,11 @@ public void StreamReadGroupMultiStreamWithNoAckShowsNoPendingMessages() db.StreamCreateConsumerGroup(key1, groupName, StreamPosition.NewMessages); db.StreamCreateConsumerGroup(key2, groupName, StreamPosition.NewMessages); - db.StreamReadGroup(new[] + db.StreamReadGroup( + new[] { new StreamPosition(key1, StreamPosition.NewMessages), - new StreamPosition(key2, StreamPosition.NewMessages) + new StreamPosition(key2, StreamPosition.NewMessages), }, groupName, consumer, @@ -2019,7 +2025,10 @@ public async Task StreamReadIndexerUsage() var db = conn.GetDatabase(); var streamName = Me(); - await db.StreamAddAsync(streamName, new[] { + await db.StreamAddAsync( + streamName, + new[] + { new NameValueEntry("x", "blah"), new NameValueEntry("msg", /*lang=json,strict*/ @"{""name"":""test"",""id"":123}"), new NameValueEntry("y", "more blah"), diff --git a/tests/StackExchange.Redis.Tests/StringTests.cs b/tests/StackExchange.Redis.Tests/StringTests.cs index 23acf737f..275f15fe2 100644 --- a/tests/StackExchange.Redis.Tests/StringTests.cs +++ b/tests/StackExchange.Redis.Tests/StringTests.cs @@ -527,7 +527,6 @@ public async Task BitCount() Assert.Equal(6, r3); // Async - r1 = await db.StringBitCountAsync(key); r2 = await db.StringBitCountAsync(key, 0, 0); r3 = await db.StringBitCountAsync(key, 1, 1); @@ -554,7 +553,6 @@ public async Task BitCountWithBitUnit() Assert.Equal(1, r2); // Async - r1 = await db.StringBitCountAsync(key, 1, 1); // Using default byte r2 = await db.StringBitCountAsync(key, 1, 1, StringIndexType.Bit); @@ -616,7 +614,6 @@ public async Task BitPosition() Assert.Equal(9, r3); // Async - r1 = await db.StringBitPositionAsync(key, true); r2 = await db.StringBitPositionAsync(key, true, 10, 10); r3 = await db.StringBitPositionAsync(key, true, 1, 3); @@ -670,7 +667,6 @@ public async Task HashStringLengthAsync() Assert.Equal(0, await resNonExistingAsync); } - [Fact] public void HashStringLength() { diff --git a/tests/StackExchange.Redis.Tests/SyncContextTests.cs b/tests/StackExchange.Redis.Tests/SyncContextTests.cs index 9acfa83be..fcc183ca4 100644 --- a/tests/StackExchange.Redis.Tests/SyncContextTests.cs +++ b/tests/StackExchange.Redis.Tests/SyncContextTests.cs @@ -135,11 +135,13 @@ public override void Post(SendOrPostCallback d, object? state) { Log(_log, "sync-ctx: Post"); Incr(); - ThreadPool.QueueUserWorkItem(static state => - { - var tuple = (Tuple)state!; - tuple.Item1.Invoke(tuple.Item2, tuple.Item3); - }, Tuple.Create(this, d, state)); + ThreadPool.QueueUserWorkItem( + static state => + { + var tuple = (Tuple)state!; + tuple.Item1.Invoke(tuple.Item2, tuple.Item3); + }, + Tuple.Create(this, d, state)); } private void Invoke(SendOrPostCallback d, object? state) diff --git a/tests/StackExchange.Redis.Tests/TestBase.cs b/tests/StackExchange.Redis.Tests/TestBase.cs index 7038aaa2f..230438d07 100644 --- a/tests/StackExchange.Redis.Tests/TestBase.cs +++ b/tests/StackExchange.Redis.Tests/TestBase.cs @@ -1,6 +1,4 @@ -using StackExchange.Redis.Profiling; -using StackExchange.Redis.Tests.Helpers; -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -9,6 +7,8 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using StackExchange.Redis.Profiling; +using StackExchange.Redis.Tests.Helpers; using Xunit; using Xunit.Abstractions; @@ -23,7 +23,7 @@ public abstract class TestBase : IDisposable internal static string GetDefaultConfiguration() => TestConfig.Current.PrimaryServerAndPort; /// - /// Gives the current TestContext, propulated by the runner (this type of thing will be built-in in xUnit 3.x) + /// Gives the current TestContext, propulated by the runner (this type of thing will be built-in in xUnit 3.x). /// protected TestContext Context => _context.Value!; private static readonly AsyncLocal _context = new(); @@ -94,7 +94,7 @@ protected static void CollectGarbage() GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "Trust me yo")] public void Dispose() { _fixture?.Teardown(Writer); @@ -293,13 +293,27 @@ internal virtual IInternalConnectionMultiplexer Create( var conn = CreateDefault( Writer, configuration ?? GetConfiguration(), - clientName, syncTimeout, asyncTimeout, allowAdmin, keepAlive, - connectTimeout, password, tieBreaker, log, - fail, disabledCommands, enabledCommands, - checkConnect, failMessage, - channelPrefix, proxy, - logTransactionData, defaultDatabase, - backlogPolicy, protocol, highIntegrity, + clientName, + syncTimeout, + asyncTimeout, + allowAdmin, + keepAlive, + connectTimeout, + password, + tieBreaker, + log, + fail, + disabledCommands, + enabledCommands, + checkConnect, + failMessage, + channelPrefix, + proxy, + logTransactionData, + defaultDatabase, + backlogPolicy, + protocol, + highIntegrity, caller); ThrowIfIncorrectProtocol(conn, protocol); @@ -323,8 +337,7 @@ internal static bool CanShare( string? configuration, int? defaultDatabase, BacklogPolicy? backlogPolicy, - bool highIntegrity - ) + bool highIntegrity) => enabledCommands == null && disabledCommands == null && fail @@ -350,7 +363,7 @@ internal void ThrowIfIncorrectProtocol(IInternalConnectionMultiplexer conn, Redi { throw new SkipTestException($"Requires protocol {requiredProtocol}, but connection is {serverProtocol}.") { - MissingFeatures = $"Protocol {requiredProtocol}." + MissingFeatures = $"Protocol {requiredProtocol}.", }; } } @@ -367,7 +380,7 @@ internal void ThrowIfBelowMinVersion(IInternalConnectionMultiplexer conn, Versio { throw new SkipTestException($"Requires server version {requiredVersion}, but server is only {serverVersion}.") { - MissingFeatures = $"Server version >= {requiredVersion}." + MissingFeatures = $"Server version >= {requiredVersion}.", }; } } @@ -436,14 +449,16 @@ public static ConnectionMultiplexer CreateDefault( var task = ConnectionMultiplexer.ConnectAsync(config, log); if (!task.Wait(config.ConnectTimeout >= (int.MaxValue / 2) ? int.MaxValue : config.ConnectTimeout * 2)) { - task.ContinueWith(x => - { - try + task.ContinueWith( + x => { - GC.KeepAlive(x.Exception); - } - catch { /* No boom */ } - }, TaskContinuationOptions.OnlyOnFaulted); + try + { + GC.KeepAlive(x.Exception); + } + catch { /* No boom */ } + }, + TaskContinuationOptions.OnlyOnFaulted); throw new TimeoutException("Connect timeout"); } watch.Stop(); @@ -498,7 +513,7 @@ protected TimeSpan RunConcurrent(Action work, int threads, int timeout = 10000, ManualResetEvent allDone = new ManualResetEvent(false); object token = new object(); int active = 0; - void callback() + void Callback() { lock (token) { @@ -524,9 +539,9 @@ void callback() var threadArr = new Thread[threads]; for (int i = 0; i < threads; i++) { - var thd = new Thread(callback) + var thd = new Thread(Callback) { - Name = caller + Name = caller, }; threadArr[i] = thd; thd.Start(); diff --git a/tests/StackExchange.Redis.Tests/TransactionTests.cs b/tests/StackExchange.Redis.Tests/TransactionTests.cs index ac67961be..b1f676d67 100644 --- a/tests/StackExchange.Redis.Tests/TransactionTests.cs +++ b/tests/StackExchange.Redis.Tests/TransactionTests.cs @@ -330,7 +330,7 @@ public enum ComparisonType { Equal, LessThan, - GreaterThan + GreaterThan, } [Theory] @@ -1232,7 +1232,7 @@ public async Task TransactionWithAdHocCommandsAndSelectDisabled() var a = tran.ExecuteAsync("SET", "foo", "bar"); Assert.True(await tran.ExecuteAsync()); var setting = db.StringGet("foo"); - Assert.Equal("bar",setting); + Assert.Equal("bar", setting); } #if VERBOSE @@ -1296,9 +1296,9 @@ public async Task ExecCompletes_Issue943() { RedisKey key = Me(); await db.KeyDeleteAsync(key); - HashEntry[] hashEntries = new [] + HashEntry[] hashEntries = new[] { - new HashEntry("blah", DateTime.UtcNow.ToString("R")) + new HashEntry("blah", DateTime.UtcNow.ToString("R")), }; ITransaction transaction = db.CreateTransaction(); transaction.AddCondition(Condition.KeyNotExists(key)); diff --git a/tests/StackExchange.Redis.Tests/ValueTests.cs b/tests/StackExchange.Redis.Tests/ValueTests.cs index f4d13617a..1877eb7c7 100644 --- a/tests/StackExchange.Redis.Tests/ValueTests.cs +++ b/tests/StackExchange.Redis.Tests/ValueTests.cs @@ -8,7 +8,7 @@ namespace StackExchange.Redis.Tests; public class ValueTests : TestBase { - public ValueTests(ITestOutputHelper output) : base (output) { } + public ValueTests(ITestOutputHelper output) : base(output) { } [Fact] public void NullValueChecks() diff --git a/toys/KestrelRedisServer/Program.cs b/toys/KestrelRedisServer/Program.cs index 349ad5d71..6cabf95d1 100644 --- a/toys/KestrelRedisServer/Program.cs +++ b/toys/KestrelRedisServer/Program.cs @@ -19,17 +19,20 @@ var app = builder.Build(); // redis-specific hack - there is a redis command to shutdown the server -_ = server.Shutdown.ContinueWith(static (t, s) => -{ - try - { // if the resp server is shutdown by a client: stop the kestrel server too - if (t.Result == RespServer.ShutdownReason.ClientInitiated) +_ = server.Shutdown.ContinueWith( + static (t, s) => + { + try { - ((IServiceProvider)s!).GetService()?.StopApplication(); + // if the resp server is shutdown by a client: stop the kestrel server too + if (t.Result == RespServer.ShutdownReason.ClientInitiated) + { + ((IServiceProvider)s!).GetService()?.StopApplication(); + } } - } - catch { /* Don't go boom on shutdown */ } -}, app.Services); + catch { /* Don't go boom on shutdown */ } + }, + app.Services); // add debug route app.Run(context => context.Response.WriteAsync(server.GetStats())); diff --git a/toys/StackExchange.Redis.Server/GlobalSuppressions.cs b/toys/StackExchange.Redis.Server/GlobalSuppressions.cs index 150a689ac..8784fa37f 100644 --- a/toys/StackExchange.Redis.Server/GlobalSuppressions.cs +++ b/toys/StackExchange.Redis.Server/GlobalSuppressions.cs @@ -5,4 +5,4 @@ using System.Diagnostics.CodeAnalysis; -[assembly: SuppressMessage("Style", "IDE0066:Convert switch statement to expression", Justification = "", Scope = "member", Target = "~M:StackExchange.Redis.TypedRedisValue.ToString~System.String")] +[assembly: SuppressMessage("Style", "IDE0066:Convert switch statement to expression", Justification = "Pending", Scope = "member", Target = "~M:StackExchange.Redis.TypedRedisValue.ToString~System.String")] diff --git a/toys/StackExchange.Redis.Server/MemoryCacheRedisServer.cs b/toys/StackExchange.Redis.Server/MemoryCacheRedisServer.cs index f7c100afe..b57ec4aea 100644 --- a/toys/StackExchange.Redis.Server/MemoryCacheRedisServer.cs +++ b/toys/StackExchange.Redis.Server/MemoryCacheRedisServer.cs @@ -18,7 +18,7 @@ private void CreateNewCache() { var old = _cache; _cache = new MemoryCache(GetType().Name); - if (old != null) old.Dispose(); + old?.Dispose(); } protected override void Dispose(bool disposing) @@ -100,7 +100,7 @@ protected override RedisValue Lpop(int database, RedisKey key) if (stack == null) return RedisValue.Null; var val = stack.Pop(); - if(stack.Count == 0) _cache.Remove(key); + if (stack.Count == 0) _cache.Remove(key); return val; } diff --git a/toys/StackExchange.Redis.Server/RedisRequest.cs b/toys/StackExchange.Redis.Server/RedisRequest.cs index 36d73a4bc..54102815c 100644 --- a/toys/StackExchange.Redis.Server/RedisRequest.cs +++ b/toys/StackExchange.Redis.Server/RedisRequest.cs @@ -3,7 +3,8 @@ namespace StackExchange.Redis.Server { public readonly ref struct RedisRequest - { // why ref? don't *really* need it, but: these things are "in flight" + { + // why ref? don't *really* need it, but: these things are "in flight" // based on an open RawResult (which is just the detokenized ReadOnlySequence) // so: using "ref" makes it clear that you can't expect to store these and have // them keep working diff --git a/toys/StackExchange.Redis.Server/RedisServer.cs b/toys/StackExchange.Redis.Server/RedisServer.cs index 8d3607e28..63efbfd1b 100644 --- a/toys/StackExchange.Redis.Server/RedisServer.cs +++ b/toys/StackExchange.Redis.Server/RedisServer.cs @@ -383,8 +383,8 @@ StringBuilder AddHeader() { sb.Append("process:").Append(process.Id).AppendLine(); } - //var port = TcpPort(); - //if (port >= 0) sb.Append("tcp_port:").Append(port).AppendLine(); + // var port = TcpPort(); + // if (port >= 0) sb.Append("tcp_port:").Append(port).AppendLine(); break; case "Clients": AddHeader().Append("connected_clients:").Append(ClientCount).AppendLine(); diff --git a/toys/StackExchange.Redis.Server/RespServer.cs b/toys/StackExchange.Redis.Server/RespServer.cs index 1edd2a3a7..75a0273ea 100644 --- a/toys/StackExchange.Redis.Server/RespServer.cs +++ b/toys/StackExchange.Redis.Server/RespServer.cs @@ -1,5 +1,4 @@ - -using System; +using System; using System.Buffers; using System.Collections.Generic; using System.IO; @@ -21,6 +20,7 @@ public enum ShutdownReason ServerDisposed, ClientInitiated, } + private readonly List _clients = new List(); private readonly TextWriter _output; @@ -70,6 +70,7 @@ public string GetStats() AppendStats(sb); return sb.ToString(); } + protected virtual void AppendStats(StringBuilder sb) => sb.Append("Current clients:\t").Append(ClientCount).AppendLine() .Append("Total clients:\t").Append(TotalClientCount).AppendLine() @@ -79,8 +80,10 @@ protected virtual void AppendStats(StringBuilder sb) => [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] protected sealed class RedisCommandAttribute : Attribute { - public RedisCommandAttribute(int arity, - string command = null, string subcommand = null) + public RedisCommandAttribute( + int arity, + string command = null, + string subcommand = null) { Command = command; SubCommand = subcommand; @@ -276,7 +279,8 @@ public async Task RunClientAsync(IDuplexPipe pipe) if (ex.GetType().Name != nameof(ConnectionResetException)) { // aspnet core has one too; swallow it by pattern - fault = ex; throw; + fault = ex; + throw; } } finally @@ -411,7 +415,7 @@ static async ValueTask Awaited(ValueTask wwrite, TypedRedisValue rresponse public TypedRedisValue Execute(RedisClient client, RedisRequest request) { - if (request.Count == 0) return default;// not a request + if (request.Count == 0) return default; // not a request if (!request.TryGetCommandBytes(0, out var cmdBytes)) return request.CommandNotFound(); if (cmdBytes.Length == 0) return default; // not a request @@ -496,11 +500,12 @@ protected virtual TypedRedisValue CommandInfo(RedisClient client, RedisRequest r for (int i = 2; i < request.Count; i++) { span[i - 2] = request.TryGetCommandBytes(i, out var cmdBytes) - &&_commands.TryGetValue(cmdBytes, out var cmdInfo) + && _commands.TryGetValue(cmdBytes, out var cmdInfo) ? CommandInfo(cmdInfo) : TypedRedisValue.NullArray; } return results; } + private TypedRedisValue CommandInfo(RespCommand command) { var arr = TypedRedisValue.Rent(6, out var span); diff --git a/toys/StackExchange.Redis.Server/TypedRedisValue.cs b/toys/StackExchange.Redis.Server/TypedRedisValue.cs index b7240370b..a67ab8d5a 100644 --- a/toys/StackExchange.Redis.Server/TypedRedisValue.cs +++ b/toys/StackExchange.Redis.Server/TypedRedisValue.cs @@ -27,6 +27,7 @@ internal static TypedRedisValue Rent(int count, out Span span) /// An invalid empty value that has no type. /// public static TypedRedisValue Nil => default; + /// /// Returns whether this value is an invalid empty value. /// @@ -70,7 +71,7 @@ public static TypedRedisValue SimpleString(string value) => new TypedRedisValue(value, ResultType.SimpleString); /// - /// The simple string OK + /// The simple string OK. /// public static TypedRedisValue OK { get; } = SimpleString("OK"); internal static TypedRedisValue Zero { get; } = Integer(0); @@ -79,7 +80,7 @@ public static TypedRedisValue SimpleString(string value) internal static TypedRedisValue EmptyArray { get; } = new TypedRedisValue(Array.Empty(), 0); /// - /// Gets the array elements as a span + /// Gets the array elements as a span. /// public ReadOnlySpan Span { @@ -175,7 +176,7 @@ internal void Recycle(int limit = -1) /// /// Get the underlying assuming that it is a valid type with a meaningful value. /// - internal RedisValue AsRedisValue() => Type == ResultType.Array ? default :_value; + internal RedisValue AsRedisValue() => Type == ResultType.Array ? default : _value; /// /// Obtain the value as a string.