Skip to content

Commit 51079ec

Browse files
committed
merge
1 parent be738e4 commit 51079ec

7 files changed

Lines changed: 103 additions & 34 deletions

File tree

src/RESPite/Messages/RespReader.cs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,6 @@ private readonly unsafe bool TryParseSlow<T>(
746746
/// <param name="value">The parsed value if successful.</param>
747747
/// <returns><c>true</c> if parsing succeeded; otherwise, <c>false</c>.</returns>
748748
#pragma warning disable RS0016, RS0027 // public API
749-
[Experimental(Experiments.Respite, UrlFormat = Experiments.UrlFormat)]
750749
[MethodImpl(MethodImplOptions.AggressiveInlining)]
751750
#if DEBUG
752751
[Obsolete("Please prefer the function-pointer API for library-internal use.")]
@@ -758,6 +757,52 @@ public readonly bool TryParseScalar<T>(ScalarParser<byte, T> parser, out T value
758757
return TryGetSpan(out var span) ? parser(span, out value) : TryParseSlow(parser, out value);
759758
}
760759

760+
private readonly ReadOnlySpan<char> BufferChars(Span<char> target, out char[]? lease)
761+
{
762+
byte[] byteLease = [];
763+
var bytes = Buffer(ref byteLease, byteLease);
764+
765+
int len = RespConstants.UTF8.GetMaxCharCount(bytes.Length);
766+
if (len <= target.Length)
767+
{
768+
lease = null;
769+
}
770+
else
771+
{
772+
target = lease = ArrayPool<char>.Shared.Rent(len);
773+
}
774+
len = RespConstants.UTF8.GetChars(bytes, target);
775+
return target.Slice(0, len);
776+
}
777+
778+
/// <summary>
779+
/// Tries to read the current scalar element using a parser callback.
780+
/// </summary>
781+
/// <typeparam name="T">The type of data being parsed.</typeparam>
782+
/// <param name="parser">The parser callback.</param>
783+
/// <param name="value">The parsed value if successful.</param>
784+
/// <returns><c>true</c> if parsing succeeded; otherwise, <c>false</c>.</returns>
785+
public readonly bool TryParseScalar<T>(ScalarParser<char, T> parser, out T value)
786+
{
787+
// note: no benefit in a function-ptr overload, after we've dealt with decoding bytes etc
788+
var buffer = BufferChars(stackalloc char[128], out var lease);
789+
try
790+
{
791+
return parser(buffer, out value);
792+
}
793+
finally
794+
{
795+
if (lease is not null) ArrayPool<char>.Shared.Return(lease);
796+
}
797+
}
798+
799+
/// <summary>
800+
/// Tries to read the current scalar element using a parser callback.
801+
/// </summary>
802+
/// <typeparam name="T">The type of data being parsed.</typeparam>
803+
/// <param name="parser">The parser callback.</param>
804+
/// <param name="value">The parsed value if successful.</param>
805+
/// <returns><c>true</c> if parsing succeeded; otherwise, <c>false</c>.</returns>
761806
[MethodImpl(MethodImplOptions.NoInlining)]
762807
private readonly bool TryParseSlow<T>(ScalarParser<byte, T> parser, out T value)
763808
{

src/RESPite/PublicAPI/PublicAPI.Unshipped.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
[SER004]RESPite.Messages.RespReader.ScalarParser<TSource, TValue>
5959
[SER004]RESPite.Messages.RespReader.TryParseScalar<T>(delegate*<System.ReadOnlySpan<byte>, out T, bool> parser, out T value) -> bool
6060
[SER004]RESPite.Messages.RespReader.TryParseScalar<T>(RESPite.Messages.RespReader.ScalarParser<byte, T>! parser, out T value) -> bool
61+
[SER004]RESPite.Messages.RespReader.TryParseScalar<T>(RESPite.Messages.RespReader.ScalarParser<char, T>! parser, out T value) -> bool
6162
[SER004]static RESPite.AsciiHash.CaseInsensitiveEqualityComparer.get -> System.Collections.Generic.IEqualityComparer<RESPite.AsciiHash>!
6263
[SER004]static RESPite.AsciiHash.CaseSensitiveEqualityComparer.get -> System.Collections.Generic.IEqualityComparer<RESPite.AsciiHash>!
6364
[SER004]static RESPite.AsciiHash.EqualsCI(System.ReadOnlySpan<byte> first, System.ReadOnlySpan<byte> second) -> bool

src/StackExchange.Redis/Enums/ServerType.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ internal static partial class ServerTypeMetadata
4747
[AsciiHash]
4848
internal static partial bool TryParse(ReadOnlySpan<char> value, out ServerType serverType);
4949

50+
[AsciiHash]
51+
internal static partial bool TryParse(ReadOnlySpan<byte> value, out ServerType serverType);
52+
5053
internal static bool TryParse(string? val, out ServerType serverType)
5154
{
5255
if (val is not null) return TryParse(val.AsSpan().Trim(), out serverType);

src/StackExchange.Redis/KnownRole.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,27 @@ internal enum KnownRole
3232
/// </summary>
3333
internal static partial class KnownRoleMetadata
3434
{
35+
[AsciiHash]
36+
private static partial bool TryParseCore(ReadOnlySpan<byte> value, out KnownRole role);
37+
3538
[AsciiHash]
3639
private static partial bool TryParseCore(ReadOnlySpan<char> value, out KnownRole role);
3740

41+
internal static bool TryParse(ReadOnlySpan<byte> value, out bool isReplica)
42+
{
43+
if (!TryParseCore(value, out var role))
44+
{
45+
isReplica = false;
46+
return false;
47+
}
48+
49+
isReplica = role is KnownRole.Replica or KnownRole.Slave;
50+
return true;
51+
}
52+
3853
internal static bool TryParse(ReadOnlySpan<char> value, out bool isReplica)
3954
{
40-
if (!TryParseCore(value.Trim(), out var role))
55+
if (!TryParseCore(value, out var role))
4156
{
4257
isReplica = false;
4358
return false;
@@ -46,9 +61,10 @@ internal static bool TryParse(ReadOnlySpan<char> value, out bool isReplica)
4661
isReplica = role is KnownRole.Replica or KnownRole.Slave;
4762
return true;
4863
}
49-
internal static bool TryParse(string? val, out bool isReplica)
64+
65+
internal static bool TryParse(string? value, out bool isReplica)
5066
{
51-
if (val is not null) return TryParse(val.AsSpan(), out isReplica);
67+
if (value is not null) return TryParse(value.AsSpan(), out isReplica);
5268
isReplica = false;
5369
return false;
5470
}

src/StackExchange.Redis/ResultProcessor.cs

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,43 +1073,48 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes
10731073
var iter = reader.AggregateChildren();
10741074
while (iter.MoveNext())
10751075
{
1076-
var key = iter.Value;
10771076
HelloField field;
10781077
unsafe
10791078
{
1080-
if (!key.TryParseScalar(&HelloFieldMetadata.TryParse, out field))
1079+
if (!iter.Value.TryParseScalar(&HelloFieldMetadata.TryParse, out field))
10811080
{
10821081
field = HelloField.Unknown;
10831082
}
1084-
}
10851083

1086-
if (!iter.MoveNext()) break;
1087-
var val = iter.Value;
1084+
if (!iter.MoveNext()) break;
10881085

1089-
switch (field)
1090-
{
1091-
case HelloField.Version when Format.TryParseVersion(val.ReadString(), out var version):
1092-
server.Version = version;
1093-
Log?.LogInformationAutoConfiguredHelloServerVersion(new(server), version);
1094-
break;
1095-
case HelloField.Proto when val.TryReadInt64(out var i64):
1096-
connection.SetProtocol(i64 >= 3 ? RedisProtocol.Resp3 : RedisProtocol.Resp2);
1097-
Log?.LogInformationAutoConfiguredHelloProtocol(new(server), connection.Protocol ?? RedisProtocol.Resp2);
1098-
break;
1099-
case HelloField.Id when val.TryReadInt64(out var i64):
1100-
connection.ConnectionId = i64;
1101-
Log?.LogInformationAutoConfiguredHelloConnectionId(new(server), i64);
1102-
break;
1103-
case HelloField.Mode when ServerTypeMetadata.TryParse(val.ReadString(), out var serverType):
1104-
server.ServerType = serverType;
1105-
Log?.LogInformationAutoConfiguredHelloServerType(new(server), serverType);
1106-
break;
1107-
case HelloField.Role when RoleTypeMetadata.TryParse(val.ReadString(), out bool isReplica):
1108-
server.IsReplica = isReplica;
1109-
Log?.LogInformationAutoConfiguredHelloRole(new(server), isReplica ? "replica" : "primary");
1110-
break;
1086+
switch (field)
1087+
{
1088+
case HelloField.Version when iter.Value.TryParseScalar(Format.TryParseVersion!, out Version version):
1089+
server.Version = version;
1090+
Log?.LogInformationAutoConfiguredHelloServerVersion(new(server), version);
1091+
break;
1092+
case HelloField.Proto when iter.Value.TryReadInt64(out var i64):
1093+
connection.SetProtocol(i64 >= 3 ? RedisProtocol.Resp3 : RedisProtocol.Resp2);
1094+
Log?.LogInformationAutoConfiguredHelloProtocol(
1095+
new(server),
1096+
connection.Protocol ?? RedisProtocol.Resp2);
1097+
break;
1098+
case HelloField.Id when iter.Value.TryReadInt64(out var i64):
1099+
connection.ConnectionId = i64;
1100+
Log?.LogInformationAutoConfiguredHelloConnectionId(new(server), i64);
1101+
break;
1102+
case HelloField.Mode
1103+
when iter.Value.TryParseScalar(&ServerTypeMetadata.TryParse, out ServerType serverType):
1104+
server.ServerType = serverType;
1105+
Log?.LogInformationAutoConfiguredHelloServerType(new(server), serverType);
1106+
break;
1107+
case HelloField.Role
1108+
when iter.Value.TryParseScalar(&KnownRoleMetadata.TryParse, out bool isReplica):
1109+
server.IsReplica = isReplica;
1110+
Log?.LogInformationAutoConfiguredHelloRole(
1111+
new(server),
1112+
isReplica ? "replica" : "primary");
1113+
break;
1114+
}
11111115
}
11121116
}
1117+
11131118
SetResult(message, true);
11141119
return true;
11151120
}

tests/StackExchange.Redis.Tests/GcraTestServer.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
extern alias respite;
2-
using respite::RESPite.Messages;
1+
using RESPite.Messages;
32
using StackExchange.Redis.Server;
43
using Xunit;
54

tests/StackExchange.Redis.Tests/InProcessTestServer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public InProcessTestServer(ITestOutputHelper? log = null, EndPoint? endpoint = n
2626
}
2727

2828
public Task<ConnectionMultiplexer> ConnectAsync(bool withPubSub = true, bool defaultOnly = false, WriteMode writeMode = WriteMode.Default, TextWriter? log = null)
29-
=> ConnectionMultiplexer.ConnectAsync(GetClientConfig(withPubSub, writeMode), log);
29+
=> ConnectionMultiplexer.ConnectAsync(GetClientConfig(withPubSub, defaultOnly, writeMode), log);
3030

3131
// view request/response highlights in the log
3232
public override TypedRedisValue Execute(RedisClient client, in RedisRequest request)

0 commit comments

Comments
 (0)