Skip to content

Commit 220d060

Browse files
committed
different A:A approach - use a multiplexer that spans multiple sub muxers
1 parent feb122c commit 220d060

27 files changed

Lines changed: 2322 additions & 6 deletions

src/StackExchange.Redis/ConfigurationOptions.cs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ public static int ParseInt32(string key, string value, int minValue = int.MinVal
4040
return tmp;
4141
}
4242

43+
public static float ParseSingle(string key, string value)
44+
{
45+
if (!Format.TryParseDouble(value, out double tmp)) throw new ArgumentOutOfRangeException(key, $"Keyword '{key}' requires a numeric value; the value '{value}' is not recognised.");
46+
return (float)tmp;
47+
}
48+
4349
internal static bool ParseBoolean(string key, string value)
4450
{
4551
if (!Format.TryParseBoolean(value, out bool tmp)) throw new ArgumentOutOfRangeException(key, $"Keyword '{key}' requires a boolean value; the value '{value}' is not recognised.");
@@ -111,7 +117,8 @@ internal const string
111117
Tunnel = "tunnel",
112118
SetClientLibrary = "setlib",
113119
Protocol = "protocol",
114-
HighIntegrity = "highIntegrity";
120+
HighIntegrity = "highIntegrity",
121+
Weight = "weight";
115122

116123
private static readonly Dictionary<string, string> normalizedOptions = new[]
117124
{
@@ -143,6 +150,7 @@ internal const string
143150
CheckCertificateRevocation,
144151
Protocol,
145152
HighIntegrity,
153+
Weight,
146154
}.ToDictionary(x => x, StringComparer.OrdinalIgnoreCase);
147155

148156
public static string TryNormalize(string value)
@@ -843,6 +851,7 @@ public static ConfigurationOptions Parse(string configuration, bool ignoreUnknow
843851
heartbeatInterval = heartbeatInterval,
844852
heartbeatConsistencyChecks = heartbeatConsistencyChecks,
845853
highIntegrity = highIntegrity,
854+
Weight = Weight,
846855
};
847856

848857
/// <summary>
@@ -925,6 +934,11 @@ public string ToString(bool includePassword)
925934
Append(sb, OptionKeys.SetClientLibrary, setClientLibrary);
926935
Append(sb, OptionKeys.HighIntegrity, highIntegrity);
927936
Append(sb, OptionKeys.Protocol, FormatProtocol(Protocol));
937+
var weight = Weight;
938+
if (!float.IsNaN(weight))
939+
{
940+
Append(sb, OptionKeys.Weight, weight);
941+
}
928942
if (Tunnel is { IsInbuilt: true } tunnel)
929943
{
930944
Append(sb, OptionKeys.Tunnel, tunnel.ToString());
@@ -940,9 +954,9 @@ public string ToString(bool includePassword)
940954
};
941955
}
942956

943-
private static void Append(StringBuilder sb, object value)
957+
private static void Append(StringBuilder sb, object? value)
944958
{
945-
if (value == null) return;
959+
if (value is null) return;
946960
string s = Format.ToString(value);
947961
if (!string.IsNullOrWhiteSpace(s))
948962
{
@@ -953,7 +967,8 @@ private static void Append(StringBuilder sb, object value)
953967

954968
private static void Append(StringBuilder sb, string prefix, object? value)
955969
{
956-
string? s = value?.ToString();
970+
if (value is null) return;
971+
string? s = value.ToString();
957972
if (!string.IsNullOrWhiteSpace(s))
958973
{
959974
if (sb.Length != 0) sb.Append(',');
@@ -980,6 +995,7 @@ private void Clear()
980995
ChannelPrefix = default;
981996
SocketManager = null;
982997
Tunnel = null;
998+
Weight = float.NaN;
983999
}
9841000

9851001
object ICloneable.Clone() => Clone();
@@ -1091,6 +1107,9 @@ private ConfigurationOptions DoParse(string configuration, bool ignoreUnknown)
10911107
case OptionKeys.HighIntegrity:
10921108
HighIntegrity = OptionKeys.ParseBoolean(key, value);
10931109
break;
1110+
case OptionKeys.Weight:
1111+
Weight = OptionKeys.ParseSingle(key, value);
1112+
break;
10941113
case OptionKeys.Tunnel:
10951114
if (value.IsNullOrWhiteSpace())
10961115
{
@@ -1167,6 +1186,11 @@ private ConfigurationOptions DoParse(string configuration, bool ignoreUnknown)
11671186
/// </summary>
11681187
public RedisProtocol? Protocol { get; set; }
11691188

1189+
/// <summary>
1190+
/// Specify the preference of this connection group relative to others.
1191+
/// </summary>
1192+
public float Weight { get; set; } = float.NaN;
1193+
11701194
internal bool TryResp3()
11711195
{
11721196
// note: deliberately leaving the IsAvailable duplicated to use short-circuit

src/StackExchange.Redis/ConnectionMultiplexer.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1128,7 +1128,7 @@ public IDatabase GetDatabase(int db = -1, object? asyncState = null)
11281128
}
11291129

11301130
// DB zero is stored separately, since 0-only is a massively common use-case
1131-
private const int MaxCachedDatabaseInstance = 16; // 17 items - [0,16]
1131+
internal const int MaxCachedDatabaseInstance = 16; // 17 items - [0,16]
11321132
// Side note: "databases 16" is the default in redis.conf; happy to store one extra to get nice alignment etc
11331133
private IDatabase? dbCacheZero;
11341134
private IDatabase[]? dbCacheLow;
@@ -1281,6 +1281,8 @@ public long OperationCount
12811281
}
12821282
}
12831283

1284+
internal int LatencyTicks { get; private set; }
1285+
12841286
/// <summary>
12851287
/// Reconfigure the current connections based on the existing configuration.
12861288
/// </summary>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System;
2+
using System.Net;
3+
using System.Threading.Tasks;
4+
5+
namespace StackExchange.Redis;
6+
7+
internal sealed partial class MultiGroupDatabase
8+
{
9+
// Async methods - Core operations
10+
public Task<RedisValue> DebugObjectAsync(RedisKey key, CommandFlags flags = CommandFlags.None)
11+
=> GetDatabase().DebugObjectAsync(key, flags);
12+
13+
public Task<EndPoint?> IdentifyEndpointAsync(RedisKey key = default, CommandFlags flags = CommandFlags.None)
14+
=> GetDatabase().IdentifyEndpointAsync(key, flags);
15+
16+
public Task KeyMigrateAsync(RedisKey key, EndPoint toServer, int toDatabase = 0, int timeoutMilliseconds = 0, MigrateOptions migrateOptions = MigrateOptions.None, CommandFlags flags = CommandFlags.None)
17+
=> GetDatabase().KeyMigrateAsync(key, toServer, toDatabase, timeoutMilliseconds, migrateOptions, flags);
18+
19+
public Task<TimeSpan> PingAsync(CommandFlags flags = CommandFlags.None)
20+
=> GetDatabase().PingAsync(flags);
21+
22+
public Task<long> PublishAsync(RedisChannel channel, RedisValue message, CommandFlags flags = CommandFlags.None)
23+
=> GetDatabase().PublishAsync(channel, message, flags);
24+
25+
public Task<RedisResult> ExecuteAsync(string command, params object[] args)
26+
=> GetDatabase().ExecuteAsync(command, args);
27+
28+
public Task<RedisResult> ExecuteAsync(string command, System.Collections.Generic.ICollection<object>? args, CommandFlags flags = CommandFlags.None)
29+
=> GetDatabase().ExecuteAsync(command, args, flags);
30+
31+
public Task<RedisResult> ScriptEvaluateAsync(string script, RedisKey[]? keys = null, RedisValue[]? values = null, CommandFlags flags = CommandFlags.None)
32+
=> GetDatabase().ScriptEvaluateAsync(script, keys, values, flags);
33+
34+
public Task<RedisResult> ScriptEvaluateAsync(byte[] hash, RedisKey[]? keys = null, RedisValue[]? values = null, CommandFlags flags = CommandFlags.None)
35+
=> GetDatabase().ScriptEvaluateAsync(hash, keys, values, flags);
36+
37+
public Task<RedisResult> ScriptEvaluateAsync(LuaScript script, object? parameters = null, CommandFlags flags = CommandFlags.None)
38+
=> GetDatabase().ScriptEvaluateAsync(script, parameters, flags);
39+
40+
public Task<RedisResult> ScriptEvaluateAsync(LoadedLuaScript script, object? parameters = null, CommandFlags flags = CommandFlags.None)
41+
=> GetDatabase().ScriptEvaluateAsync(script, parameters, flags);
42+
43+
public Task<RedisResult> ScriptEvaluateReadOnlyAsync(string script, RedisKey[]? keys = null, RedisValue[]? values = null, CommandFlags flags = CommandFlags.None)
44+
=> GetDatabase().ScriptEvaluateReadOnlyAsync(script, keys, values, flags);
45+
46+
public Task<RedisResult> ScriptEvaluateReadOnlyAsync(byte[] hash, RedisKey[]? keys = null, RedisValue[]? values = null, CommandFlags flags = CommandFlags.None)
47+
=> GetDatabase().ScriptEvaluateReadOnlyAsync(hash, keys, values, flags);
48+
49+
public Task<bool> LockExtendAsync(RedisKey key, RedisValue value, TimeSpan expiry, CommandFlags flags = CommandFlags.None)
50+
=> GetDatabase().LockExtendAsync(key, value, expiry, flags);
51+
52+
public Task<RedisValue> LockQueryAsync(RedisKey key, CommandFlags flags = CommandFlags.None)
53+
=> GetDatabase().LockQueryAsync(key, flags);
54+
55+
public Task<bool> LockReleaseAsync(RedisKey key, RedisValue value, CommandFlags flags = CommandFlags.None)
56+
=> GetDatabase().LockReleaseAsync(key, value, flags);
57+
58+
public Task<bool> LockTakeAsync(RedisKey key, RedisValue value, TimeSpan expiry, CommandFlags flags = CommandFlags.None)
59+
=> GetDatabase().LockTakeAsync(key, value, expiry, flags);
60+
61+
public Task<RedisValue[]> 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)
62+
=> GetDatabase().SortAsync(key, skip, take, order, sortType, by, get, flags);
63+
64+
public Task<long> 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)
65+
=> GetDatabase().SortAndStoreAsync(destination, key, skip, take, order, sortType, by, get, flags);
66+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System.Threading.Tasks;
2+
3+
namespace StackExchange.Redis;
4+
5+
internal sealed partial class MultiGroupDatabase
6+
{
7+
// Geo Async
8+
public Task<bool> GeoAddAsync(RedisKey key, double longitude, double latitude, RedisValue member, CommandFlags flags = CommandFlags.None)
9+
=> GetDatabase().GeoAddAsync(key, longitude, latitude, member, flags);
10+
11+
public Task<bool> GeoAddAsync(RedisKey key, GeoEntry value, CommandFlags flags = CommandFlags.None)
12+
=> GetDatabase().GeoAddAsync(key, value, flags);
13+
14+
public Task<long> GeoAddAsync(RedisKey key, GeoEntry[] values, CommandFlags flags = CommandFlags.None)
15+
=> GetDatabase().GeoAddAsync(key, values, flags);
16+
17+
public Task<bool> GeoRemoveAsync(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None)
18+
=> GetDatabase().GeoRemoveAsync(key, member, flags);
19+
20+
public Task<double?> GeoDistanceAsync(RedisKey key, RedisValue member1, RedisValue member2, GeoUnit unit = GeoUnit.Meters, CommandFlags flags = CommandFlags.None)
21+
=> GetDatabase().GeoDistanceAsync(key, member1, member2, unit, flags);
22+
23+
public Task<string?[]> GeoHashAsync(RedisKey key, RedisValue[] members, CommandFlags flags = CommandFlags.None)
24+
=> GetDatabase().GeoHashAsync(key, members, flags);
25+
26+
public Task<string?> GeoHashAsync(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None)
27+
=> GetDatabase().GeoHashAsync(key, member, flags);
28+
29+
public Task<GeoPosition?[]> GeoPositionAsync(RedisKey key, RedisValue[] members, CommandFlags flags = CommandFlags.None)
30+
=> GetDatabase().GeoPositionAsync(key, members, flags);
31+
32+
public Task<GeoPosition?> GeoPositionAsync(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None)
33+
=> GetDatabase().GeoPositionAsync(key, member, flags);
34+
35+
public Task<GeoRadiusResult[]> 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)
36+
=> GetDatabase().GeoRadiusAsync(key, member, radius, unit, count, order, options, flags);
37+
38+
public Task<GeoRadiusResult[]> 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)
39+
=> GetDatabase().GeoRadiusAsync(key, longitude, latitude, radius, unit, count, order, options, flags);
40+
41+
public Task<GeoRadiusResult[]> GeoSearchAsync(RedisKey key, RedisValue member, GeoSearchShape shape, int count = -1, bool demandClosest = true, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None)
42+
=> GetDatabase().GeoSearchAsync(key, member, shape, count, demandClosest, order, options, flags);
43+
44+
public Task<GeoRadiusResult[]> 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)
45+
=> GetDatabase().GeoSearchAsync(key, longitude, latitude, shape, count, demandClosest, order, options, flags);
46+
47+
public Task<long> 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)
48+
=> GetDatabase().GeoSearchAndStoreAsync(sourceKey, destinationKey, member, shape, count, demandClosest, order, storeDistances, flags);
49+
50+
public Task<long> 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)
51+
=> GetDatabase().GeoSearchAndStoreAsync(sourceKey, destinationKey, longitude, latitude, shape, count, demandClosest, order, storeDistances, flags);
52+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
namespace StackExchange.Redis;
2+
3+
internal sealed partial class MultiGroupDatabase
4+
{
5+
// Geo operations
6+
public bool GeoAdd(RedisKey key, double longitude, double latitude, RedisValue member, CommandFlags flags = CommandFlags.None)
7+
=> GetDatabase().GeoAdd(key, longitude, latitude, member, flags);
8+
9+
public bool GeoAdd(RedisKey key, GeoEntry value, CommandFlags flags = CommandFlags.None)
10+
=> GetDatabase().GeoAdd(key, value, flags);
11+
12+
public long GeoAdd(RedisKey key, GeoEntry[] values, CommandFlags flags = CommandFlags.None)
13+
=> GetDatabase().GeoAdd(key, values, flags);
14+
15+
public bool GeoRemove(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None)
16+
=> GetDatabase().GeoRemove(key, member, flags);
17+
18+
public double? GeoDistance(RedisKey key, RedisValue member1, RedisValue member2, GeoUnit unit = GeoUnit.Meters, CommandFlags flags = CommandFlags.None)
19+
=> GetDatabase().GeoDistance(key, member1, member2, unit, flags);
20+
21+
public string?[] GeoHash(RedisKey key, RedisValue[] members, CommandFlags flags = CommandFlags.None)
22+
=> GetDatabase().GeoHash(key, members, flags);
23+
24+
public string? GeoHash(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None)
25+
=> GetDatabase().GeoHash(key, member, flags);
26+
27+
public GeoPosition?[] GeoPosition(RedisKey key, RedisValue[] members, CommandFlags flags = CommandFlags.None)
28+
=> GetDatabase().GeoPosition(key, members, flags);
29+
30+
public GeoPosition? GeoPosition(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None)
31+
=> GetDatabase().GeoPosition(key, member, flags);
32+
33+
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)
34+
=> GetDatabase().GeoRadius(key, member, radius, unit, count, order, options, flags);
35+
36+
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)
37+
=> GetDatabase().GeoRadius(key, longitude, latitude, radius, unit, count, order, options, flags);
38+
39+
public GeoRadiusResult[] GeoSearch(RedisKey key, RedisValue member, GeoSearchShape shape, int count = -1, bool demandClosest = true, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None)
40+
=> GetDatabase().GeoSearch(key, member, shape, count, demandClosest, order, options, flags);
41+
42+
public GeoRadiusResult[] GeoSearch(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)
43+
=> GetDatabase().GeoSearch(key, longitude, latitude, shape, count, demandClosest, order, options, flags);
44+
45+
public long GeoSearchAndStore(RedisKey sourceKey, RedisKey destinationKey, RedisValue member, GeoSearchShape shape, int count = -1, bool demandClosest = true, Order? order = null, bool storeDistances = false, CommandFlags flags = CommandFlags.None)
46+
=> GetDatabase().GeoSearchAndStore(sourceKey, destinationKey, member, shape, count, demandClosest, order, storeDistances, flags);
47+
48+
public long GeoSearchAndStore(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)
49+
=> GetDatabase().GeoSearchAndStore(sourceKey, destinationKey, longitude, latitude, shape, count, demandClosest, order, storeDistances, flags);
50+
}

0 commit comments

Comments
 (0)