diff --git a/benchmark/Resp.benchmark/RespOnlineBench.cs b/benchmark/Resp.benchmark/RespOnlineBench.cs index e17348691d..e0bce0ed5c 100644 --- a/benchmark/Resp.benchmark/RespOnlineBench.cs +++ b/benchmark/Resp.benchmark/RespOnlineBench.cs @@ -503,7 +503,7 @@ public unsafe void OpRunnerLightClient(int thread_id) case OpType.SET: byte* setCurr = setBuffer + 13; RespWriteUtils.WriteBulkString(Encoding.ASCII.GetBytes(req.GenerateKey()), ref setCurr, setEnd); - RespWriteUtils.WriteBulkString(req.GenerateValueBytes(), ref setCurr, setEnd); + RespWriteUtils.WriteBulkString(req.GenerateValueBytes().Span, ref setCurr, setEnd); client.Send(setBuffer, (int)(setCurr - setBuffer), 1); client.CompletePendingRequests(); break; @@ -511,7 +511,7 @@ public unsafe void OpRunnerLightClient(int thread_id) byte* setexCurr = setexBuffer + 15; RespWriteUtils.WriteBulkString(Encoding.ASCII.GetBytes(req.GenerateKey()), ref setexCurr, setexEnd); RespWriteUtils.WriteIntegerAsBulkString(opts.Ttl, ref setexCurr, setexEnd); - RespWriteUtils.WriteBulkString(req.GenerateValueBytes(), ref setexCurr, setexEnd); + RespWriteUtils.WriteBulkString(req.GenerateValueBytes().Span, ref setexCurr, setexEnd); client.Send(setexBuffer, (int)(setexCurr - setexBuffer), 1); client.CompletePendingRequests(); break; diff --git a/libs/client/ClientSession/GarnetClientSession.cs b/libs/client/ClientSession/GarnetClientSession.cs index 3aa2fbb1db..0ef32907d6 100644 --- a/libs/client/ClientSession/GarnetClientSession.cs +++ b/libs/client/ClientSession/GarnetClientSession.cs @@ -195,8 +195,8 @@ public void ExecuteForArray(params string[] command) Flush(); } - static readonly byte[] CLUSTER = Encoding.ASCII.GetBytes("$7\r\nCLUSTER\r\n"); - static readonly byte[] appendLog = Encoding.ASCII.GetBytes("appendlog"); + static ReadOnlySpan CLUSTER => "$7\r\nCLUSTER\r\n"u8; + static ReadOnlySpan appendLog => "appendlog"u8; /// /// ClusterAppendLog diff --git a/libs/client/ClientSession/GarnetClientSessionClusterExtensions.cs b/libs/client/ClientSession/GarnetClientSessionClusterExtensions.cs index 6ed75f2fc9..e43019415a 100644 --- a/libs/client/ClientSession/GarnetClientSessionClusterExtensions.cs +++ b/libs/client/ClientSession/GarnetClientSessionClusterExtensions.cs @@ -16,7 +16,7 @@ namespace Garnet.client /// public sealed unsafe partial class GarnetClientSession : IServerHook, IMessageConsumer { - static readonly byte[] GOSSIP = Encoding.ASCII.GetBytes("GOSSIP"); + static ReadOnlySpan GOSSIP => "GOSSIP"u8; /// /// Send gossip message to corresponding node @@ -55,7 +55,7 @@ public Task ExecuteGossip(Memory byteArray) offset = curr; //3 - while (!RespWriteUtils.WriteBulkString(byteArray, ref curr, end)) + while (!RespWriteUtils.WriteBulkString(byteArray.Span, ref curr, end)) { Flush(); curr = offset; diff --git a/libs/client/ClientSession/GarnetClientSessionMigrationExtensions.cs b/libs/client/ClientSession/GarnetClientSessionMigrationExtensions.cs index 3b85684e7c..652bb88edf 100644 --- a/libs/client/ClientSession/GarnetClientSessionMigrationExtensions.cs +++ b/libs/client/ClientSession/GarnetClientSessionMigrationExtensions.cs @@ -18,11 +18,11 @@ namespace Garnet.client /// public sealed unsafe partial class GarnetClientSession : IServerHook, IMessageConsumer { - static readonly Memory AUTH = Encoding.ASCII.GetBytes("AUTH"); - static readonly Memory SETSLOTSRANGE = Encoding.ASCII.GetBytes("SETSLOTSRANGE"); - static readonly Memory MIGRATE = Encoding.ASCII.GetBytes("MIGRATE"); - static readonly Memory DELKEY = Encoding.ASCII.GetBytes("DELKEY"); - static readonly Memory GETKVPAIRINSLOT = Encoding.ASCII.GetBytes("GETKVPAIRINSLOT"); + static ReadOnlySpan AUTH => "AUTH"u8; + static ReadOnlySpan SETSLOTSRANGE => "SETSLOTSRANGE"u8; + static ReadOnlySpan MIGRATE => "MIGRATE"u8; + static ReadOnlySpan DELKEY => "DELKEY"u8; + static ReadOnlySpan GETKVPAIRINSLOT => "GETKVPAIRINSLOT"u8; /// /// Send AUTH command to target node to authenticate connection. @@ -119,7 +119,7 @@ public Task SetSlotRange(Memory state, string nodeid, List<(int, i offset = curr; //3 - while (!RespWriteUtils.WriteBulkString(state, ref curr, end)) + while (!RespWriteUtils.WriteBulkString(state.Span, ref curr, end)) { Flush(); curr = offset; @@ -207,7 +207,7 @@ public Task MigrateData(string sourceNodeId, Memory replaceOption, offset = curr; //4 - while (!RespWriteUtils.WriteBulkString(replaceOption, ref curr, end)) + while (!RespWriteUtils.WriteBulkString(replaceOption.Span, ref curr, end)) { Flush(); curr = offset; @@ -215,7 +215,7 @@ public Task MigrateData(string sourceNodeId, Memory replaceOption, offset = curr; //5 - while (!RespWriteUtils.WriteBulkString(storeType, ref curr, end)) + while (!RespWriteUtils.WriteBulkString(storeType.Span, ref curr, end)) { Flush(); curr = offset; @@ -223,7 +223,7 @@ public Task MigrateData(string sourceNodeId, Memory replaceOption, offset = curr; //6 - while (!RespWriteUtils.WriteBulkString(data, ref curr, end)) + while (!RespWriteUtils.WriteBulkString(data.Span, ref curr, end)) { Flush(); curr = offset; @@ -374,7 +374,7 @@ public void SetClusterMigrate(string sourceNodeId, Memory replaceOption, M offset = curr; //4 - while (!RespWriteUtils.WriteBulkString(replaceOption, ref curr, end)) + while (!RespWriteUtils.WriteBulkString(replaceOption.Span, ref curr, end)) { Flush(); curr = offset; @@ -382,7 +382,7 @@ public void SetClusterMigrate(string sourceNodeId, Memory replaceOption, M offset = curr; //5 - while (!RespWriteUtils.WriteBulkString(storeType, ref curr, end)) + while (!RespWriteUtils.WriteBulkString(storeType.Span, ref curr, end)) { Flush(); curr = offset; diff --git a/libs/client/ClientSession/GarnetClientSessionReplicationExtensions.cs b/libs/client/ClientSession/GarnetClientSessionReplicationExtensions.cs index a5f96d24a9..0ef1e08024 100644 --- a/libs/client/ClientSession/GarnetClientSessionReplicationExtensions.cs +++ b/libs/client/ClientSession/GarnetClientSessionReplicationExtensions.cs @@ -16,10 +16,10 @@ namespace Garnet.client /// public sealed unsafe partial class GarnetClientSession : IServerHook, IMessageConsumer { - static readonly byte[] initiate_replica_sync = Encoding.ASCII.GetBytes("initiate_replica_sync"); - static readonly byte[] send_ckpt_metadata = Encoding.ASCII.GetBytes("send_ckpt_metadata"); - static readonly byte[] send_ckpt_file_segment = Encoding.ASCII.GetBytes("send_ckpt_file_segment"); - static readonly byte[] begin_replica_recover = Encoding.ASCII.GetBytes("begin_replica_recover"); + static ReadOnlySpan initiate_replica_sync => "initiate_replica_sync"u8; + static ReadOnlySpan send_ckpt_metadata => "send_ckpt_metadata"u8; + static ReadOnlySpan send_ckpt_file_segment => "send_ckpt_file_segment"u8; + static ReadOnlySpan begin_replica_recover => "begin_replica_recover"u8; /// /// Initiate checkpoint retrieval from replica by sending replica checkpoint information and AOF address range @@ -142,7 +142,7 @@ public Task ExecuteSendCkptMetadata(Memory fileTokenBytes, int fil offset = curr; //3 - while (!RespWriteUtils.WriteBulkString(fileTokenBytes, ref curr, end)) + while (!RespWriteUtils.WriteBulkString(fileTokenBytes.Span, ref curr, end)) { Flush(); curr = offset; @@ -158,7 +158,7 @@ public Task ExecuteSendCkptMetadata(Memory fileTokenBytes, int fil offset = curr; //5 - while (!RespWriteUtils.WriteBulkString(data, ref curr, end)) + while (!RespWriteUtils.WriteBulkString(data.Span, ref curr, end)) { Flush(); curr = offset; @@ -208,7 +208,7 @@ public Task ExecuteSendFileSegments(Memory fileTokenBytes, int fil offset = curr; //3 - while (!RespWriteUtils.WriteBulkString(fileTokenBytes, ref curr, end)) + while (!RespWriteUtils.WriteBulkString(fileTokenBytes.Span, ref curr, end)) { Flush(); curr = offset; diff --git a/libs/client/GarnetClient.cs b/libs/client/GarnetClient.cs index cba0edf3a8..870b101e87 100644 --- a/libs/client/GarnetClient.cs +++ b/libs/client/GarnetClient.cs @@ -20,7 +20,7 @@ namespace Garnet.client { struct OK_MEM : IMemoryOwner { - static readonly Memory RESP_OK = Encoding.ASCII.GetBytes("OK"); + static readonly Memory RESP_OK = "OK"u8.ToArray(); public Memory Memory => RESP_OK; public void Dispose() { } } @@ -30,17 +30,17 @@ public void Dispose() { } /// public sealed partial class GarnetClient : IServerHook, IMessageConsumer, IDisposable { - static readonly Memory GET = Encoding.ASCII.GetBytes("$3\r\nGET\r\n"); - static readonly Memory MGET = Encoding.ASCII.GetBytes("$4\r\nMGET\r\n"); - static readonly Memory SET = Encoding.ASCII.GetBytes("$3\r\nSET\r\n"); - static readonly Memory DEL = Encoding.ASCII.GetBytes("$3\r\nDEL\r\n"); - static readonly Memory PING = Encoding.ASCII.GetBytes("$4\r\nPING\r\n"); - static readonly Memory INCR = Encoding.ASCII.GetBytes("$4\r\nINCR\r\n"); - static readonly Memory INCRBY = Encoding.ASCII.GetBytes("$6\r\nINCRBY\r\n"); - static readonly Memory DECR = Encoding.ASCII.GetBytes("$4\r\nDECR\r\n"); - static readonly Memory DECRBY = Encoding.ASCII.GetBytes("$6\r\nDECRBY\r\n"); - static readonly Memory QUIT = Encoding.ASCII.GetBytes("$4\r\nQUIT\r\n"); - static readonly Memory AUTH = Encoding.ASCII.GetBytes("$4\r\nAUTH\r\n"); + static readonly Memory GET = "$3\r\nGET\r\n"u8.ToArray(); + static readonly Memory MGET = "$4\r\nMGET\r\n"u8.ToArray(); + static readonly Memory SET = "$3\r\nSET\r\n"u8.ToArray(); + static readonly Memory DEL = "$3\r\nDEL\r\n"u8.ToArray(); + static readonly Memory PING = "$4\r\nPING\r\n"u8.ToArray(); + static readonly Memory INCR = "$4\r\nINCR\r\n"u8.ToArray(); + static readonly Memory INCRBY = "$6\r\nINCRBY\r\n"u8.ToArray(); + static readonly Memory DECR = "$4\r\nDECR\r\n"u8.ToArray(); + static readonly Memory DECRBY = "$6\r\nDECRBY\r\n"u8.ToArray(); + static readonly Memory QUIT = "$4\r\nQUIT\r\n"u8.ToArray(); + static readonly Memory AUTH = "$4\r\nAUTH\r\n"u8.ToArray(); static readonly MemoryResult RESP_OK = new(default(OK_MEM)); readonly string address; @@ -525,7 +525,7 @@ async ValueTask InternalExecuteAsync(TcsWrapper tcs, Memory op, string par byte* end = curr + totalLen; RespWriteUtils.WriteArrayLength(arraySize, ref curr, end); - RespWriteUtils.WriteDirect(op, ref curr, end); + RespWriteUtils.WriteDirect(op.Span, ref curr, end); if (param1 != null) RespWriteUtils.WriteBulkString(param1, ref curr, end); if (param2 != null) @@ -649,8 +649,8 @@ async ValueTask InternalExecuteAsync(Memory op, Memory clusterOp, st byte* end = curr + totalLen; RespWriteUtils.WriteArrayLength(arraySize, ref curr, end); - RespWriteUtils.WriteDirect(op, ref curr, end); - RespWriteUtils.WriteBulkString(clusterOp, ref curr, end); + RespWriteUtils.WriteDirect(op.Span, ref curr, end); + RespWriteUtils.WriteBulkString(clusterOp.Span, ref curr, end); RespWriteUtils.WriteBulkString(nodeId, ref curr, end); RespWriteUtils.WriteArrayItem(currentAddress, ref curr, end); RespWriteUtils.WriteArrayItem(nextAddress, ref curr, end); @@ -738,11 +738,11 @@ async ValueTask InternalExecuteAsync(TcsWrapper tcs, Memory op, Memory respOp, IColle byte* curr = (byte*)networkWriter.GetPhysicalAddress(address); byte* end = curr + totalLen; RespWriteUtils.WriteArrayLength(arraySize, ref curr, end); - RespWriteUtils.WriteDirect(respOp, ref curr, end); + RespWriteUtils.WriteDirect(respOp.Span, ref curr, end); if (isArray)//Write arg data { foreach (var arg in args) - RespWriteUtils.WriteBulkString(arg, ref curr, end); + RespWriteUtils.WriteBulkString(arg.Span, ref curr, end); } Debug.Assert(curr == end); } diff --git a/libs/client/GarnetClientAPI/GarnetClientAdminCommands.cs b/libs/client/GarnetClientAPI/GarnetClientAdminCommands.cs index bed94a415f..97e8ac863e 100644 --- a/libs/client/GarnetClientAPI/GarnetClientAdminCommands.cs +++ b/libs/client/GarnetClientAPI/GarnetClientAdminCommands.cs @@ -12,9 +12,9 @@ namespace Garnet.client { public sealed partial class GarnetClient { - static readonly Memory SAVE = Encoding.ASCII.GetBytes("$4\r\nSAVE\r\n"); - static readonly Memory INFO = Encoding.ASCII.GetBytes("$4\r\nINFO\r\n"); - static readonly Memory REPLICAOF = Encoding.ASCII.GetBytes("$9\r\nREPLICAOF\r\n"); + static readonly Memory SAVE = "$4\r\nSAVE\r\n"u8.ToArray(); + static readonly Memory INFO = "$4\r\nINFO\r\n"u8.ToArray(); + static readonly Memory REPLICAOF = "$9\r\nREPLICAOF\r\n"u8.ToArray(); /// /// Take a checkpoint of the Garnet instance. diff --git a/libs/client/GarnetClientAPI/GarnetClientClusterCommands.cs b/libs/client/GarnetClientAPI/GarnetClientClusterCommands.cs index 9fc3c495e4..4bb6c3b3c4 100644 --- a/libs/client/GarnetClientAPI/GarnetClientClusterCommands.cs +++ b/libs/client/GarnetClientAPI/GarnetClientClusterCommands.cs @@ -14,8 +14,8 @@ public sealed partial class GarnetClient /// /// CLUSTER resp formatted /// - public static readonly Memory CLUSTER = Encoding.ASCII.GetBytes("$7\r\nCLUSTER\r\n"); - static readonly Memory FAILOVER = Encoding.ASCII.GetBytes("FAILOVER"); + public static readonly Memory CLUSTER = "$7\r\nCLUSTER\r\n"u8.ToArray(); + static readonly Memory FAILOVER = "FAILOVER"u8.ToArray(); /// /// Issue cluster failover command to replica node diff --git a/libs/client/GarnetClientAPI/GarnetClientSortedSetCommands.cs b/libs/client/GarnetClientAPI/GarnetClientSortedSetCommands.cs index 5a5d676d3c..9da77f7698 100644 --- a/libs/client/GarnetClientAPI/GarnetClientSortedSetCommands.cs +++ b/libs/client/GarnetClientAPI/GarnetClientSortedSetCommands.cs @@ -12,9 +12,9 @@ namespace Garnet.client public sealed partial class GarnetClient { - static readonly Memory ZCARD = Encoding.ASCII.GetBytes("$5\r\nZCARD\r\n"); - static readonly Memory ZADD = Encoding.ASCII.GetBytes("$4\r\nZADD\r\n"); - static readonly Memory ZREM = Encoding.ASCII.GetBytes("$4\r\nZREM\r\n"); + static readonly Memory ZCARD = "$5\r\nZCARD\r\n"u8.ToArray(); + static readonly Memory ZADD = "$4\r\nZADD\r\n"u8.ToArray(); + static readonly Memory ZREM = "$4\r\nZREM\r\n"u8.ToArray(); /// /// Adds/Updates a member, score in a SortedSet diff --git a/libs/cluster/Server/GarnetClientExtensions.cs b/libs/cluster/Server/GarnetClientExtensions.cs index 252c00a380..7a88ce025a 100644 --- a/libs/cluster/Server/GarnetClientExtensions.cs +++ b/libs/cluster/Server/GarnetClientExtensions.cs @@ -12,8 +12,8 @@ namespace Garnet.cluster { internal static partial class GarnetClientExtensions { - static readonly Memory GOSSIP = Encoding.ASCII.GetBytes("GOSSIP"); - static readonly Memory WITHMEET = Encoding.ASCII.GetBytes("WITHMEET"); + static readonly Memory GOSSIP = "GOSSIP"u8.ToArray(); + static readonly Memory WITHMEET = "WITHMEET"u8.ToArray(); /// /// Send config diff --git a/libs/cluster/Server/Migration/MigrateSession.cs b/libs/cluster/Server/Migration/MigrateSession.cs index 9f649f09a8..41f48027eb 100644 --- a/libs/cluster/Server/Migration/MigrateSession.cs +++ b/libs/cluster/Server/Migration/MigrateSession.cs @@ -18,9 +18,9 @@ namespace Garnet.cluster /// internal sealed unsafe partial class MigrateSession : IDisposable { - static readonly Memory IMPORTING = Encoding.ASCII.GetBytes("IMPORTING"); - static readonly Memory NODE = Encoding.ASCII.GetBytes("NODE"); - static readonly Memory STABLE = Encoding.ASCII.GetBytes("STABLE"); + static readonly Memory IMPORTING = "IMPORTING"u8.ToArray(); + static readonly Memory NODE = "NODE"u8.ToArray(); + static readonly Memory STABLE = "STABLE"u8.ToArray(); readonly ClusterProvider clusterProvider; readonly LocalServerSession localServerSession; diff --git a/libs/cluster/Session/ClusterCommands.cs b/libs/cluster/Session/ClusterCommands.cs index f0240edbd1..8c12fbc209 100644 --- a/libs/cluster/Session/ClusterCommands.cs +++ b/libs/cluster/Session/ClusterCommands.cs @@ -381,7 +381,7 @@ private bool ProcessClusterBasicCommands(ReadOnlySpan bufSpan, ReadOnlySpa readHead = (int)(ptr - recvBufferPtr); if (clusterProvider.clusterManager.CurrentConfig.NumWorkers > 2) { - var resp = Encoding.ASCII.GetBytes("-ERR The user can assign a config epoch only when the node does not know any other node.\r\n"); + ReadOnlySpan resp = "-ERR The user can assign a config epoch only when the node does not know any other node.\r\n"u8; while (!RespWriteUtils.WriteResponse(resp, ref dcurr, dend)) SendAndReset(); } @@ -565,7 +565,7 @@ public bool ProcessFailoverCommands(ReadOnlySpan bufSpan, ReadOnlySpan resp; if (port != 0) resp = Encoding.ASCII.GetBytes($"-MOVED {slot} {address}:{port}\r\n"); else - resp = Encoding.ASCII.GetBytes("-CLUSTERDOWN Hash slot not served\r\n"); + resp = "-CLUSTERDOWN Hash slot not served\r\n"u8; logger?.LogDebug("SEND: {msg}", Encoding.ASCII.GetString(resp).Replace("\n", "!").Replace("\r", "|")); while (!RespWriteUtils.WriteDirect(resp, ref dcurr, dend)) @@ -43,7 +43,7 @@ private void Redirect(ushort slot, ClusterConfig config) private void WriteClusterSlotVerificationMessage(ClusterConfig config, ClusterSlotVerificationResult vres, ref byte* dcurr, ref byte* dend) { - byte[] resp = default; + ReadOnlySpan resp = default; SlotVerifiedState state = vres.state; ushort slot = vres.slot; string address; @@ -55,17 +55,17 @@ private void WriteClusterSlotVerificationMessage(ClusterConfig config, ClusterSl resp = Encoding.ASCII.GetBytes($"-MOVED {slot} {address}:{port}\r\n"); break; case SlotVerifiedState.MIGRATING: - resp = Encoding.ASCII.GetBytes("-MIGRATING.\r\n"); + resp = "-MIGRATING.\r\n"u8; break; case SlotVerifiedState.CLUSTERDOWN: - resp = Encoding.ASCII.GetBytes("-CLUSTERDOWN Hash slot not served\r\n"); + resp = "-CLUSTERDOWN Hash slot not served\r\n"u8; break; case SlotVerifiedState.ASK: (address, port) = config.AskEndpointFromSlot(slot); resp = Encoding.ASCII.GetBytes($"-ASK {slot} {address}:{port}\r\n"); break; case SlotVerifiedState.CROSSLOT: - resp = Encoding.ASCII.GetBytes($"-CROSSSLOT Keys in request don't hash to the same slot\r\n"); + resp = "-CROSSSLOT Keys in request don't hash to the same slot\r\n"u8; break; default: throw new Exception($"Unknown SlotVerifiedState {state}"); diff --git a/libs/common/Generator.cs b/libs/common/Generator.cs index a6c45fc3b4..3083aa33ac 100644 --- a/libs/common/Generator.cs +++ b/libs/common/Generator.cs @@ -11,7 +11,7 @@ namespace Garnet.common /// public class Generator { - static readonly byte[] hexchars = Encoding.ASCII.GetBytes("0123456789abcdef"); + static ReadOnlySpan hexchars => "0123456789abcdef"u8; /// /// Random hex id diff --git a/libs/common/NumUtils.cs b/libs/common/NumUtils.cs index 5793a07750..ba7750cff6 100644 --- a/libs/common/NumUtils.cs +++ b/libs/common/NumUtils.cs @@ -167,7 +167,7 @@ public static unsafe void IntToBytes(int value, int length, ref byte* result) result += length; } - static readonly byte[] digits = Encoding.ASCII.GetBytes("00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899"); + static ReadOnlySpan digits => "00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899"u8; /// /// Return number of digits in given number diff --git a/libs/common/RespWriteUtils.cs b/libs/common/RespWriteUtils.cs index 6ec13ef720..579b454a4e 100644 --- a/libs/common/RespWriteUtils.cs +++ b/libs/common/RespWriteUtils.cs @@ -151,13 +151,13 @@ public static bool WriteError(byte[] item, ref byte* curr, byte* end) /// /// Write byte array directly /// - public static bool WriteDirect(byte[] item, ref byte* curr, byte* end) + public static bool WriteDirect(ReadOnlySpan item, ref byte* curr, byte* end) { int totalLen = item.Length; if (totalLen > (int)(end - curr)) return false; - new ReadOnlySpan(item).CopyTo(new Span(curr, item.Length)); + item.CopyTo(new Span(curr, item.Length)); curr += item.Length; return true; } @@ -175,44 +175,10 @@ public static bool WriteDirect(ref T item, ref byte* curr, byte* end) where T return true; } - - /// - /// Write byte array directly - /// - public static bool WriteDirect(Memory item, ref byte* curr, byte* end) - { - int totalLen = item.Length; - if (totalLen > (int)(end - curr)) - return false; - - item.Span.CopyTo(new Span(curr, item.Length)); - curr += item.Length; - return true; - } - - /// - /// Write bulk string - /// - public static bool WriteBulkString(byte[] item, ref byte* curr, byte* end) - { - var itemDigits = NumUtils.NumDigits(item.Length); - int totalLen = 1 + itemDigits + 2 + item.Length + 2; - if (totalLen > (int)(end - curr)) - return false; - - *curr++ = (byte)'$'; - NumUtils.IntToBytes(item.Length, itemDigits, ref curr); - WriteNewline(ref curr); - new ReadOnlySpan(item).CopyTo(new Span(curr, item.Length)); - curr += item.Length; - WriteNewline(ref curr); - return true; - } - /// /// Write bulk string /// - public static bool WriteBulkString(Memory item, ref byte* curr, byte* end) + public static bool WriteBulkString(ReadOnlySpan item, ref byte* curr, byte* end) { var itemDigits = NumUtils.NumDigits(item.Length); int totalLen = 1 + itemDigits + 2 + item.Length + 2; @@ -222,7 +188,7 @@ public static bool WriteBulkString(Memory item, ref byte* curr, byte* end) *curr++ = (byte)'$'; NumUtils.IntToBytes(item.Length, itemDigits, ref curr); WriteNewline(ref curr); - item.Span.CopyTo(new Span(curr, item.Length)); + item.CopyTo(new Span(curr, item.Length)); curr += item.Length; WriteNewline(ref curr); return true; diff --git a/libs/server/Objects/Hash/HashObjectImpl.cs b/libs/server/Objects/Hash/HashObjectImpl.cs index 091a082e04..a0a6137189 100644 --- a/libs/server/Objects/Hash/HashObjectImpl.cs +++ b/libs/server/Objects/Hash/HashObjectImpl.cs @@ -430,7 +430,7 @@ private void IncrementIntegerOrFloat(HashOperation op, byte* input, int length, } else { - var errorMessage = Encoding.ASCII.GetBytes("-ERR field value is not a number\r\n"); + ReadOnlySpan errorMessage = "-ERR field value is not a number\r\n"u8; while (!RespWriteUtils.WriteResponse(errorMessage, ref curr, end)) ObjectUtils.ReallocateOutput(ref output, ref isMemory, ref ptr, ref ptrHandle, ref curr, ref end); } @@ -439,7 +439,7 @@ private void IncrementIntegerOrFloat(HashOperation op, byte* input, int length, { if (!Single.TryParse(Encoding.ASCII.GetString(incr), out var resultIncr)) { - var errorMessage = Encoding.ASCII.GetBytes("-ERR field value is not a number\r\n"); + ReadOnlySpan errorMessage = "-ERR field value is not a number\r\n"u8; while (!RespWriteUtils.WriteResponse(errorMessage, ref curr, end)) ObjectUtils.ReallocateOutput(ref output, ref isMemory, ref ptr, ref ptrHandle, ref curr, ref end); } diff --git a/libs/server/Objects/SortedSet/SortedSetObjectImpl.cs b/libs/server/Objects/SortedSet/SortedSetObjectImpl.cs index ad0ac70efd..3c5d5c18bd 100644 --- a/libs/server/Objects/SortedSet/SortedSetObjectImpl.cs +++ b/libs/server/Objects/SortedSet/SortedSetObjectImpl.cs @@ -364,7 +364,7 @@ private void SortedSetRange(byte* input, int length, ref SpanByteAndMemory outpu if (!TryParseParameter(minParamByteArray, out var minValue, out var minExclusive) | !TryParseParameter(maxParamByteArray, out var maxValue, out var maxExclusive)) { - var errorMessage = Encoding.ASCII.GetBytes("-ERR max or min value is not a float value.\r\n"); + ReadOnlySpan errorMessage = "-ERR max or min value is not a float value.\r\n"u8; while (!RespWriteUtils.WriteResponse(errorMessage, ref curr, end)) ObjectUtils.ReallocateOutput(ref output, ref isMemory, ref ptr, ref ptrHandle, ref curr, ref end); countDone = _input->count; @@ -397,7 +397,7 @@ private void SortedSetRange(byte* input, int length, ref SpanByteAndMemory outpu int minIndex = (int)minValue, maxIndex = (int)maxValue; if (options.ValidLimit) { - var errorMessage = Encoding.ASCII.GetBytes("-ERR syntax error, LIMIT is only supported in BYSCORE or BYLEX.\r\n"); + ReadOnlySpan errorMessage = "-ERR syntax error, LIMIT is only supported in BYSCORE or BYLEX.\r\n"u8; while (!RespWriteUtils.WriteResponse(errorMessage, ref curr, end)) ObjectUtils.ReallocateOutput(ref output, ref isMemory, ref ptr, ref ptrHandle, ref curr, ref end); countDone = _input->count; @@ -459,7 +459,7 @@ private void SortedSetRange(byte* input, int length, ref SpanByteAndMemory outpu if (errorCode == int.MaxValue) { - var errorMessage = Encoding.ASCII.GetBytes("-ERR max or min value not valid string range.\r\n"); + ReadOnlySpan errorMessage = "-ERR max or min value not valid string range.\r\n"u8; while (!RespWriteUtils.WriteResponse(errorMessage, ref curr, end)) ObjectUtils.ReallocateOutput(ref output, ref isMemory, ref ptr, ref ptrHandle, ref curr, ref end); countDone = _input->count; diff --git a/libs/server/Resp/AdminCommands.cs b/libs/server/Resp/AdminCommands.cs index 204a55f4b6..97dc34167f 100644 --- a/libs/server/Resp/AdminCommands.cs +++ b/libs/server/Resp/AdminCommands.cs @@ -140,16 +140,9 @@ private bool ProcessAdminCommands(ReadOnlySpan command, ReadOn { var key = GetCommand(bufSpan, out bool success2); if (!success2) return false; - if (CmdStrings.GetConfig(key.ToArray(), out var val)) - { - while (!RespWriteUtils.WriteResponse(new ReadOnlySpan(val), ref dcurr, dend)) - SendAndReset(); - } - else - { - while (!RespWriteUtils.WriteResponse(CmdStrings.RESP_EMPTYLIST, ref dcurr, dend)) + + while (!RespWriteUtils.WriteResponse(CmdStrings.GetConfig(key), ref dcurr, dend)) SendAndReset(); - } } } else if (param.SequenceEqual(CmdStrings.REWRITE) || param.SequenceEqual(CmdStrings.rewrite)) diff --git a/libs/server/Resp/CmdStrings.cs b/libs/server/Resp/CmdStrings.cs index 9c528f649b..47b4f1f64d 100644 --- a/libs/server/Resp/CmdStrings.cs +++ b/libs/server/Resp/CmdStrings.cs @@ -12,25 +12,16 @@ namespace Garnet.server /// static partial class CmdStrings { - /// - /// Config map - /// - static readonly Dictionary configGetMap; - - static CmdStrings() + public static ReadOnlySpan GetConfig(ReadOnlySpan key) { - configGetMap = new Dictionary(new ByteArrayComparer()) - { - [Encoding.ASCII.GetBytes("timeout")] = Encoding.ASCII.GetBytes("*2\r\n$7\r\ntimeout\r\n$1\r\n0\r\n"), - [Encoding.ASCII.GetBytes("save")] = Encoding.ASCII.GetBytes("*2\r\n$4\r\nsave\r\n$0\r\n\r\n"), - [Encoding.ASCII.GetBytes("appendonly")] = Encoding.ASCII.GetBytes("*2\r\n$10\r\nappendonly\r\n$2\r\nno\r\n"), - [Encoding.ASCII.GetBytes("slave-read-only")] = Encoding.ASCII.GetBytes("$3\r\nyes\r\n"), - [Encoding.ASCII.GetBytes("databases")] = Encoding.ASCII.GetBytes("$2\r\n16\r\n"), - }; + if (key.SequenceEqual("timeout"u8)) return "*2\r\n$7\r\ntimeout\r\n$1\r\n0\r\n"u8; + else if (key.SequenceEqual("save"u8)) return "*2\r\n$4\r\nsave\r\n$0\r\n\r\n"u8; + else if (key.SequenceEqual("appendonly"u8)) return "*2\r\n$10\r\nappendonly\r\n$2\r\nno\r\n"u8; + else if (key.SequenceEqual("slave-read-only"u8)) return "$3\r\nyes\r\n"u8; + else if (key.SequenceEqual("databases"u8)) return "$2\r\n16\r\n"u8; + else return RESP_EMPTYLIST; } - public static bool GetConfig(byte[] key, out byte[] value) => configGetMap.TryGetValue(key, out value); - /// /// Request strings /// diff --git a/libs/server/Resp/Objects/ListCommands.cs b/libs/server/Resp/Objects/ListCommands.cs index 1bf518ed3f..66d04c35d4 100644 --- a/libs/server/Resp/Objects/ListCommands.cs +++ b/libs/server/Resp/Objects/ListCommands.cs @@ -557,7 +557,7 @@ private unsafe bool ListInsert(int count, byte* ptr, ref TGarnetApi //TODO: validation for different object type, pending to review if (output.countDone == 0 && output.countDone == 0 && output.bytesDone == 0) { - var errorMessage = Encoding.ASCII.GetBytes("-ERR wrong key type used in LINSERT command.\r\n"); + ReadOnlySpan errorMessage = "-ERR wrong key type used in LINSERT command.\r\n"u8; while (!RespWriteUtils.WriteResponse(errorMessage, ref dcurr, dend)) SendAndReset(); } diff --git a/libs/server/Resp/Objects/SetCommands.cs b/libs/server/Resp/Objects/SetCommands.cs index 53af064c3b..a7c1ec256a 100644 --- a/libs/server/Resp/Objects/SetCommands.cs +++ b/libs/server/Resp/Objects/SetCommands.cs @@ -358,7 +358,7 @@ private unsafe bool SetPop(int count, byte* ptr, ref TGarnetApi stor var canParse = Int32.TryParse(Encoding.ASCII.GetString(countParameterByteArray), out countParameter); if (!canParse || countParameter < 0) { - var errorMessage = Encoding.ASCII.GetBytes("-ERR value is not an integer or out of range\r\n"); + ReadOnlySpan errorMessage = "-ERR value is not an integer or out of range\r\n"u8; while (!RespWriteUtils.WriteResponse(errorMessage, ref dcurr, dend)) SendAndReset(); diff --git a/libs/server/Resp/Objects/SortedSetCommands.cs b/libs/server/Resp/Objects/SortedSetCommands.cs index 0de22f7903..40d6752d23 100644 --- a/libs/server/Resp/Objects/SortedSetCommands.cs +++ b/libs/server/Resp/Objects/SortedSetCommands.cs @@ -23,7 +23,7 @@ internal sealed unsafe partial class RespServerSession : ServerSessionBase /// int zaddAddCount; - static readonly byte[] withscores = Encoding.ASCII.GetBytes("WITHSCORES"); + static ReadOnlySpan withscores => "WITHSCORES"u8; /// /// Adds all the specified members with the specified scores to the sorted set stored at key. @@ -606,7 +606,7 @@ private unsafe bool SortedSetCount(int count, byte* ptr, ref TGarnet if (output.countDone == Int32.MaxValue) { // Error in arguments - var errorMessage = Encoding.ASCII.GetBytes("-ERR max or min value is not a float value.\r\n"); + ReadOnlySpan errorMessage = "-ERR max or min value is not a float value.\r\n"u8; while (!RespWriteUtils.WriteResponse(errorMessage, ref dcurr, dend)) SendAndReset(); } @@ -705,7 +705,7 @@ private unsafe bool SortedSetLengthByValue(int count, byte* ptr, Sor if (output.countDone == Int32.MaxValue) { // Error in arguments - var errorMessage = Encoding.ASCII.GetBytes("-ERR max or min value not in a valid range.\r\n"); + ReadOnlySpan errorMessage = "-ERR max or min value not in a valid range.\r\n"u8; while (!RespWriteUtils.WriteResponse(errorMessage, ref dcurr, dend)) SendAndReset(); } @@ -790,7 +790,7 @@ private unsafe bool SortedSetIncrement(int count, byte* ptr, ref TGa //restore input *inputPtr = save; - byte[] errorMessage = default; + ReadOnlySpan errorMessage = default; switch (status) { @@ -801,7 +801,7 @@ private unsafe bool SortedSetIncrement(int count, byte* ptr, ref TGa var tokens = ReadLeftToken(count - 2, ref ptr); if (tokens < count - 2) return false; - errorMessage = Encoding.ASCII.GetBytes("-ERR wrong key type used in ZINCRBY command.\r\n"); + errorMessage = "-ERR wrong key type used in ZINCRBY command.\r\n"u8; } else { @@ -811,7 +811,7 @@ private unsafe bool SortedSetIncrement(int count, byte* ptr, ref TGa if (objOutputHeader.countDone == Int32.MinValue) return false; else if (objOutputHeader.countDone == Int32.MaxValue) - errorMessage = Encoding.ASCII.GetBytes("-ERR increment value is not valid.\r\n"); + errorMessage = "-ERR increment value is not valid.\r\n"u8; ptr += objOutputHeader.bytesDone; } break; @@ -1043,7 +1043,7 @@ private unsafe bool SortedSetRandomMember(int count, byte* ptr, ref } var paramCount = 0; - ReadOnlySpan withScoresSpan = Encoding.ASCII.GetBytes("WITHSCORES"); + ReadOnlySpan withScoresSpan = "WITHSCORES"u8; Byte[] includeWithScores = default; bool includedCount = false; diff --git a/libs/server/Resp/PubSubCommands.cs b/libs/server/Resp/PubSubCommands.cs index c068d400a5..739a8b4937 100644 --- a/libs/server/Resp/PubSubCommands.cs +++ b/libs/server/Resp/PubSubCommands.cs @@ -93,7 +93,7 @@ private bool NetworkPUBLISH(byte* ptr) if (subscribeBroker == null) { - var resp = Encoding.ASCII.GetBytes("-ERR PUBLISH is disabled, enable it with --pubsub option.\r\n"); + ReadOnlySpan resp = "-ERR PUBLISH is disabled, enable it with --pubsub option.\r\n"u8; while (!RespWriteUtils.WriteResponse(resp, ref dcurr, dend)) SendAndReset(); readHead = (int)(ptr - recvBufferPtr); @@ -151,7 +151,7 @@ private bool NetworkSUBSCRIBE(int count, byte* ptr, byte* dend) if (disabledBroker) { - var resp = Encoding.ASCII.GetBytes("-ERR SUBSCRIBE is disabled, enable it with --pubsub option.\r\n"); + ReadOnlySpan resp = "-ERR SUBSCRIBE is disabled, enable it with --pubsub option.\r\n"u8; while (!RespWriteUtils.WriteResponse(resp, ref dcurr, dend)) SendAndReset(); readHead = (int)(ptr - recvBufferPtr); @@ -203,7 +203,7 @@ private bool NetworkPSUBSCRIBE(int count, byte* ptr, byte* dend) if (disabledBroker) { - var resp = Encoding.ASCII.GetBytes("-ERR SUBSCRIBE is disabled, enable it with --pubsub option.\r\n"); + ReadOnlySpan resp = "-ERR SUBSCRIBE is disabled, enable it with --pubsub option.\r\n"u8; while (!RespWriteUtils.WriteResponse(resp, ref dcurr, dend)) SendAndReset(); readHead = (int)(ptr - recvBufferPtr); @@ -225,7 +225,7 @@ private bool NetworkUNSUBSCRIBE(int count, byte* ptr, byte* dend) { if (subscribeBroker == null) { - var resp = Encoding.ASCII.GetBytes("-ERR UNSUBSCRIBE is disabled, enable it with --pubsub option.\r\n"); + ReadOnlySpan resp = "-ERR UNSUBSCRIBE is disabled, enable it with --pubsub option.\r\n"u8; while (!RespWriteUtils.WriteResponse(resp, ref dcurr, dend)) SendAndReset(); return true; @@ -259,8 +259,7 @@ private bool NetworkUNSUBSCRIBE(int count, byte* ptr, byte* dend) { while (!RespWriteUtils.WriteArrayLength(3, ref dcurr, dend)) SendAndReset(); - byte[] commandLowerBytes = Encoding.ASCII.GetBytes("unsubscribe"); - while (!RespWriteUtils.WriteBulkString(commandLowerBytes, ref dcurr, dend)) + while (!RespWriteUtils.WriteBulkString("unsubscribe"u8, ref dcurr, dend)) SendAndReset(); while (!RespWriteUtils.WriteNull(ref dcurr, dend)) SendAndReset(); @@ -307,7 +306,7 @@ private bool NetworkUNSUBSCRIBE(int count, byte* ptr, byte* dend) if (subscribeBroker == null) { - var resp = Encoding.ASCII.GetBytes("-ERR UNSUBSCRIBE is disabled, enable it with --pubsub option.\r\n"); + ReadOnlySpan resp = "-ERR UNSUBSCRIBE is disabled, enable it with --pubsub option.\r\n"u8; while (!RespWriteUtils.WriteResponse(resp, ref dcurr, dend)) SendAndReset(); } @@ -325,7 +324,7 @@ private bool NetworkPUNSUBSCRIBE(int count, byte* ptr, byte* dend) { if (subscribeBroker == null) { - var resp = Encoding.ASCII.GetBytes("-ERR PUNSUBSCRIBE is disabled, enable it with --pubsub option.\r\n"); + ReadOnlySpan resp = "-ERR PUNSUBSCRIBE is disabled, enable it with --pubsub option.\r\n"u8; while (!RespWriteUtils.WriteResponse(resp, ref dcurr, dend)) SendAndReset(); return true; @@ -394,7 +393,7 @@ private bool NetworkPUNSUBSCRIBE(int count, byte* ptr, byte* dend) if (subscribeBroker == null) { - var resp = Encoding.ASCII.GetBytes("-ERR PUNSUBSCRIBE is disabled, enable it with --pubsub option.\r\n"); + ReadOnlySpan resp = "-ERR PUNSUBSCRIBE is disabled, enable it with --pubsub option.\r\n"u8; while (!RespWriteUtils.WriteResponse(resp, ref dcurr, dend)) SendAndReset(); } diff --git a/libs/server/Storage/Session/ObjectStore/HashOps.cs b/libs/server/Storage/Session/ObjectStore/HashOps.cs index b14ef2e793..690c249417 100644 --- a/libs/server/Storage/Session/ObjectStore/HashOps.cs +++ b/libs/server/Storage/Session/ObjectStore/HashOps.cs @@ -370,7 +370,7 @@ public unsafe GarnetStatus HashRandomField(ArgSlice key, int cou inputLength += tmp.length; //write withvalues - var withValuesBytes = Encoding.ASCII.GetBytes("WITHVALUES"); + ReadOnlySpan withValuesBytes = "WITHVALUES"u8; fixed (byte* withValuesPtr = withValuesBytes) { withValuesArgSlice = new ArgSlice(withValuesPtr, withValuesBytes.Length); diff --git a/libs/server/Storage/Session/ObjectStore/SortedSetOps.cs b/libs/server/Storage/Session/ObjectStore/SortedSetOps.cs index 8543cc7f05..2144d00614 100644 --- a/libs/server/Storage/Session/ObjectStore/SortedSetOps.cs +++ b/libs/server/Storage/Session/ObjectStore/SortedSetOps.cs @@ -439,17 +439,17 @@ public unsafe GarnetStatus SortedSetRange(ArgSlice key, ArgSlice return GarnetStatus.NOTFOUND; } - byte[] operation = default; + ReadOnlySpan operation = default; var sortedOperation = SortedSetOperation.ZRANGE; switch (sortedSetOrderOperation) { case SortedSetOrderOperation.ByScore: sortedOperation = SortedSetOperation.ZRANGEBYSCORE; - operation = Encoding.ASCII.GetBytes("BYSCORE"); + operation = "BYSCORE"u8; break; case SortedSetOrderOperation.ByLex: sortedOperation = SortedSetOperation.ZRANGE; - operation = Encoding.ASCII.GetBytes("BYLEX"); + operation = "BYLEX"u8; break; case SortedSetOrderOperation.ByRank: if (reverse) @@ -484,7 +484,7 @@ public unsafe GarnetStatus SortedSetRange(ArgSlice key, ArgSlice //reverse if (sortedOperation != SortedSetOperation.ZREVRANGE && reverse) { - var reverseBytes = Encoding.ASCII.GetBytes("REV"); + ReadOnlySpan reverseBytes = "REV"u8; fixed (byte* ptrOp = reverseBytes) { tmp = scratchBufferManager.FormatScratchAsResp(0, new ArgSlice { ptr = ptrOp, length = reverseBytes.Length }); @@ -495,7 +495,7 @@ public unsafe GarnetStatus SortedSetRange(ArgSlice key, ArgSlice //limit parameter if (limit != default && (sortedSetOrderOperation == SortedSetOrderOperation.ByScore || sortedSetOrderOperation == SortedSetOrderOperation.ByLex)) { - var limitBytes = Encoding.ASCII.GetBytes("LIMIT"); + ReadOnlySpan limitBytes = "LIMIT"u8; fixed (byte* ptrOp = limitBytes) { tmp = scratchBufferManager.FormatScratchAsResp(0, new ArgSlice { ptr = ptrOp, length = limitBytes.Length });