Skip to content

Commit 2471c60

Browse files
committed
- set max len
- use in physicalconnection
1 parent 022a36b commit 2471c60

3 files changed

Lines changed: 35 additions & 12 deletions

File tree

src/StackExchange.Redis/Format.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,14 +399,15 @@ internal static unsafe string GetString(ReadOnlySpan<byte> span)
399399

400400
internal const int
401401
MaxInt32TextLen = 11, // -2,147,483,648 (not including the commas)
402-
MaxInt64TextLen = 20; // -9,223,372,036,854,775,808 (not including the commas)
402+
MaxInt64TextLen = 20, // -9,223,372,036,854,775,808 (not including the commas),
403+
MaxDoubleTextLen = 40; // we use G17, allow for sign/E/and allow plenty of panic room
403404

404405
internal static int MeasureDouble(double value)
405406
{
406407
if (double.IsInfinity(value)) return 4; // +inf / -inf
407408

408409
#if NET8_0_OR_GREATER // can use IUtf8Formattable
409-
Span<byte> buffer = stackalloc byte[64];
410+
Span<byte> buffer = stackalloc byte[MaxDoubleTextLen];
410411
if (value.TryFormat(buffer, out int len, "G17", NumberFormatInfo.InvariantInfo))
411412
{
412413
return len;

src/StackExchange.Redis/PhysicalConnection.cs

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,9 @@ internal static void WriteBulkString(in RedisValue value, PipeWriter? maybeNullW
845845
case RedisValue.StorageType.UInt64:
846846
WriteUnifiedUInt64(writer, value.OverlappedValueUInt64);
847847
break;
848-
case RedisValue.StorageType.Double: // use string
848+
case RedisValue.StorageType.Double:
849+
WriteUnifiedDouble(writer, value.OverlappedValueDouble);
850+
break;
849851
case RedisValue.StorageType.String:
850852
WriteUnifiedPrefixedString(writer, null, (string?)value);
851853
break;
@@ -1341,9 +1343,9 @@ private static void WriteUnifiedInt64(PipeWriter writer, long value)
13411343
// note from specification: A client sends to the Redis server a RESP Array consisting of just Bulk Strings.
13421344
// (i.e. we can't just send ":123\r\n", we need to send "$3\r\n123\r\n"
13431345

1344-
// ${asc-len}\r\n = 3 + MaxInt32TextLen
1346+
// ${asc-len}\r\n = 4/5 (asc-len at most 2 digits)
13451347
// {asc}\r\n = MaxInt64TextLen + 2
1346-
var span = writer.GetSpan(5 + Format.MaxInt32TextLen + Format.MaxInt64TextLen);
1348+
var span = writer.GetSpan(7 + Format.MaxInt64TextLen);
13471349

13481350
span[0] = (byte)'$';
13491351
var bytes = WriteRaw(span, value, withLengthPrefix: true, offset: 1);
@@ -1354,20 +1356,40 @@ private static void WriteUnifiedUInt64(PipeWriter writer, ulong value)
13541356
{
13551357
// note from specification: A client sends to the Redis server a RESP Array consisting of just Bulk Strings.
13561358
// (i.e. we can't just send ":123\r\n", we need to send "$3\r\n123\r\n"
1357-
1358-
// ${asc-len}\r\n = 3 + MaxInt32TextLen
1359-
// {asc}\r\n = MaxInt64TextLen + 2
1360-
var span = writer.GetSpan(5 + Format.MaxInt32TextLen + Format.MaxInt64TextLen);
1361-
13621359
Span<byte> valueSpan = stackalloc byte[Format.MaxInt64TextLen];
1360+
13631361
var len = Format.FormatUInt64(value, valueSpan);
1362+
// ${asc-len}\r\n = 4/5 (asc-len at most 2 digits)
1363+
// {asc}\r\n = {len} + 2
1364+
var span = writer.GetSpan(7 + len);
13641365
span[0] = (byte)'$';
13651366
int offset = WriteRaw(span, len, withLengthPrefix: false, offset: 1);
13661367
valueSpan.Slice(0, len).CopyTo(span.Slice(offset));
13671368
offset += len;
13681369
offset = WriteCrlf(span, offset);
13691370
writer.Advance(offset);
13701371
}
1372+
1373+
private static void WriteUnifiedDouble(PipeWriter writer, double value)
1374+
{
1375+
#if NET8_0_OR_GREATER
1376+
Span<byte> valueSpan = stackalloc byte[Format.MaxDoubleTextLen];
1377+
var len = Format.FormatDouble(value, valueSpan);
1378+
1379+
// ${asc-len}\r\n = 4/5 (asc-len at most 2 digits)
1380+
// {asc}\r\n = {len} + 2
1381+
var span = writer.GetSpan(7 + len);
1382+
span[0] = (byte)'$';
1383+
int offset = WriteRaw(span, len, withLengthPrefix: false, offset: 1);
1384+
offset += len;
1385+
offset = WriteCrlf(span, offset);
1386+
writer.Advance(offset);
1387+
#else
1388+
// fallback: drop to string
1389+
WriteUnifiedPrefixedString(writer, null, Format.ToString(value));
1390+
#endif
1391+
}
1392+
13711393
internal static void WriteInteger(PipeWriter writer, long value)
13721394
{
13731395
// note: client should never write integer; only server does this

src/StackExchange.Redis/RedisValue.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ public bool IsNullOrEmpty
149149
/// <param name="y">The second <see cref="RedisValue"/> to compare.</param>
150150
public static bool operator !=(RedisValue x, RedisValue y) => !(x == y);
151151

152-
private double OverlappedValueDouble
152+
internal double OverlappedValueDouble
153153
{
154154
[MethodImpl(MethodImplOptions.AggressiveInlining)]
155155
get => BitConverter.Int64BitsToDouble(_overlappedBits64);
@@ -849,7 +849,7 @@ private static string ToHex(ReadOnlySpan<byte> src)
849849
len = Format.FormatUInt64(value.OverlappedValueUInt64, span);
850850
return span.Slice(0, len).ToArray();
851851
case StorageType.Double:
852-
span = stackalloc byte[128];
852+
span = stackalloc byte[Format.MaxDoubleTextLen];
853853
len = Format.FormatDouble(value.OverlappedValueDouble, span);
854854
return span.Slice(0, len).ToArray();
855855
case StorageType.String:

0 commit comments

Comments
 (0)