From de1fa223900e16dbb0f9580fc312ca9478e210d8 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Wed, 22 Jan 2025 20:14:59 -0700 Subject: [PATCH] Adding ObjectStoreOutputFlags to GarnetObjectStoreOutput (#923) * Adding wrongType bool to GarnetObjectStoreOutput * Fixing comments * format * Adding SizeChange to GOSO * small fix * small fix * Fixing broken merge * Reverting sizeChange changes * Added comment in GOSO --- .../Server/Migration/MigrateSessionKeys.cs | 6 +- libs/server/AOF/AofProcessor.cs | 12 ++-- libs/server/Custom/CustomObjectBase.cs | 14 ++-- libs/server/Custom/CustomRespCommands.cs | 32 +++++----- libs/server/Objects/Hash/HashObject.cs | 60 ++++++++--------- .../ItemBroker/CollectionItemBroker.cs | 4 +- libs/server/Objects/List/ListObject.cs | 40 ++++++------ libs/server/Objects/Set/SetObject.cs | 40 ++++++------ .../Objects/SortedSet/SortedSetObject.cs | 64 ++++++++++--------- libs/server/Objects/Types/GarnetObjectBase.cs | 2 +- .../Objects/Types/GarnetObjectStoreOutput.cs | 36 ++++++++++- libs/server/Objects/Types/IGarnetObject.cs | 3 +- libs/server/Resp/Objects/HashCommands.cs | 38 +++++------ libs/server/Resp/Objects/ListCommands.cs | 20 +++--- libs/server/Resp/Objects/SetCommands.cs | 16 ++--- .../Resp/Objects/SharedObjectCommands.cs | 4 +- libs/server/Resp/Objects/SortedSetCommands.cs | 40 ++++++------ .../Resp/Objects/SortedSetGeoCommands.cs | 8 +-- libs/server/Resp/RespCommandsInfo.cs | 2 +- .../Functions/ObjectStore/PrivateMethods.cs | 4 +- .../Functions/ObjectStore/RMWMethods.cs | 61 ++++++++++-------- .../Functions/ObjectStore/ReadMethods.cs | 29 ++++++--- .../Storage/Session/MainStore/MainStoreOps.cs | 30 ++++----- .../Session/ObjectStore/AdvancedOps.cs | 4 +- .../Storage/Session/ObjectStore/Common.cs | 60 ++++++++--------- .../Storage/Session/ObjectStore/HashOps.cs | 10 +-- .../Storage/Session/ObjectStore/ListOps.cs | 8 +-- .../Storage/Session/ObjectStore/SetOps.cs | 20 +++--- .../Session/ObjectStore/SortedSetGeoOps.cs | 6 +- .../Session/ObjectStore/SortedSetOps.cs | 34 +++++----- main/GarnetServer/Extensions/MyDictSet.cs | 1 - playground/GarnetJSON/JsonCommands.cs | 6 +- playground/NoOpModule/DummyObjectNoOpRMW.cs | 1 - playground/NoOpModule/DummyObjectNoOpRead.cs | 1 - test/BDNPerfTests/BDN_Benchmark_Config.json | 18 +++--- test/Garnet.test/RespModuleTests.cs | 2 +- 36 files changed, 398 insertions(+), 338 deletions(-) diff --git a/libs/cluster/Server/Migration/MigrateSessionKeys.cs b/libs/cluster/Server/Migration/MigrateSessionKeys.cs index dbf155c7eb..61942ec69c 100644 --- a/libs/cluster/Server/Migration/MigrateSessionKeys.cs +++ b/libs/cluster/Server/Migration/MigrateSessionKeys.cs @@ -120,11 +120,11 @@ private bool MigrateKeysFromObjectStore() continue; } - if (!ClusterSession.Expired(ref value.garnetObject)) + if (!ClusterSession.Expired(ref value.GarnetObject)) { - var objectData = GarnetObjectSerializer.Serialize(value.garnetObject); + var objectData = GarnetObjectSerializer.Serialize(value.GarnetObject); - if (!WriteOrSendObjectStoreKeyValuePair(key, objectData, value.garnetObject.Expiration)) + if (!WriteOrSendObjectStoreKeyValuePair(key, objectData, value.GarnetObject.Expiration)) return false; } } diff --git a/libs/server/AOF/AofProcessor.cs b/libs/server/AOF/AofProcessor.cs index 94bf35913c..2a916e3689 100644 --- a/libs/server/AOF/AofProcessor.cs +++ b/libs/server/AOF/AofProcessor.cs @@ -344,10 +344,10 @@ static unsafe void ObjectStoreUpsert(BasicContext(ptr + sizeof(AofHeader) + key.TotalSize); var valB = garnetObjectSerializer.Deserialize(value.ToByteArray()); - var output = new GarnetObjectStoreOutput { spanByteAndMemory = new(outputPtr, outputLength) }; + var output = new GarnetObjectStoreOutput { SpanByteAndMemory = new(outputPtr, outputLength) }; basicContext.Upsert(ref keyB, ref valB); - if (!output.spanByteAndMemory.IsSpanByte) - output.spanByteAndMemory.Memory.Dispose(); + if (!output.SpanByteAndMemory.IsSpanByte) + output.SpanByteAndMemory.Memory.Dispose(); } static unsafe void ObjectStoreRMW(BasicContext basicContext, @@ -364,12 +364,12 @@ static unsafe void ObjectStoreRMW(BasicContext basicContext, byte* ptr) diff --git a/libs/server/Custom/CustomObjectBase.cs b/libs/server/Custom/CustomObjectBase.cs index 29f9a6d75b..11c06d70fe 100644 --- a/libs/server/Custom/CustomObjectBase.cs +++ b/libs/server/Custom/CustomObjectBase.cs @@ -68,32 +68,32 @@ public sealed override void DoSerialize(BinaryWriter writer) public abstract override void Dispose(); /// - public sealed override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory output, out long sizeChange, out bool removeKey) + public sealed override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output, out long sizeChange) { sizeChange = 0; - removeKey = false; switch (input.header.cmd) { // Scan Command case RespCommand.COSCAN: - if (ObjectUtils.ReadScanInput(ref input, ref output, out var cursorInput, out var pattern, - out var patternLength, out var limitCount, out bool _, out var error)) + if (ObjectUtils.ReadScanInput(ref input, ref output.SpanByteAndMemory, out var cursorInput, out var pattern, + out var patternLength, out var limitCount, out _, out var error)) { Scan(cursorInput, out var items, out var cursorOutput, count: limitCount, pattern: pattern, patternLength: patternLength); - ObjectUtils.WriteScanOutput(items, cursorOutput, ref output); + ObjectUtils.WriteScanOutput(items, cursorOutput, ref output.SpanByteAndMemory); } else { - ObjectUtils.WriteScanError(error, ref output); + ObjectUtils.WriteScanError(error, ref output.SpanByteAndMemory); } break; default: if ((byte)input.header.type != this.type) { // Indicates an incorrect type of key - output.Length = 0; + output.OutputFlags |= ObjectStoreOutputFlags.WrongType; + output.SpanByteAndMemory.Length = 0; return true; } break; diff --git a/libs/server/Custom/CustomRespCommands.cs b/libs/server/Custom/CustomRespCommands.cs index 6db051fd33..1dd5f5b031 100644 --- a/libs/server/Custom/CustomRespCommands.cs +++ b/libs/server/Custom/CustomRespCommands.cs @@ -142,14 +142,14 @@ private bool TryCustomObjectCommand(GarnetObjectType objType, byte s var header = new RespInputHeader(objType) { SubId = subid }; var input = new ObjectInput(header, ref parseState, startIdx: 1); - var output = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var output = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; GarnetStatus status; if (type == CommandType.ReadModifyWrite) { status = storageApi.RMW_ObjectStore(ref keyBytes, ref input, ref output); - Debug.Assert(!output.spanByteAndMemory.IsSpanByte); + Debug.Assert(!output.SpanByteAndMemory.IsSpanByte); switch (status) { @@ -158,8 +158,8 @@ private bool TryCustomObjectCommand(GarnetObjectType objType, byte s SendAndReset(); break; default: - if (output.spanByteAndMemory.Memory != null) - SendAndReset(output.spanByteAndMemory.Memory, output.spanByteAndMemory.Length); + if (output.SpanByteAndMemory.Memory != null) + SendAndReset(output.SpanByteAndMemory.Memory, output.SpanByteAndMemory.Length); else while (!RespWriteUtils.WriteDirect(CmdStrings.RESP_OK, ref dcurr, dend)) SendAndReset(); @@ -169,19 +169,19 @@ private bool TryCustomObjectCommand(GarnetObjectType objType, byte s else { status = storageApi.Read_ObjectStore(ref keyBytes, ref input, ref output); - Debug.Assert(!output.spanByteAndMemory.IsSpanByte); + Debug.Assert(!output.SpanByteAndMemory.IsSpanByte); switch (status) { case GarnetStatus.OK: - if (output.spanByteAndMemory.Memory != null) - SendAndReset(output.spanByteAndMemory.Memory, output.spanByteAndMemory.Length); + if (output.SpanByteAndMemory.Memory != null) + SendAndReset(output.SpanByteAndMemory.Memory, output.SpanByteAndMemory.Length); else while (!RespWriteUtils.WriteDirect(CmdStrings.RESP_OK, ref dcurr, dend)) SendAndReset(); break; case GarnetStatus.NOTFOUND: - Debug.Assert(output.spanByteAndMemory.Memory == null); + Debug.Assert(output.SpanByteAndMemory.Memory == null); while (!RespWriteUtils.WriteDirect(CmdStrings.RESP_ERRNOTFOUND, ref dcurr, dend)) SendAndReset(); break; @@ -295,12 +295,12 @@ public bool InvokeCustomObjectCommand(ref TGarnetApi storageApi, Cus customCommandParseState.InitializeWithArguments(args); var input = new ObjectInput(header, ref customCommandParseState); - var _output = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var _output = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; GarnetStatus status; if (customObjCommand.type == CommandType.ReadModifyWrite) { status = storageApi.RMW_ObjectStore(ref keyBytes, ref input, ref _output); - Debug.Assert(!_output.spanByteAndMemory.IsSpanByte); + Debug.Assert(!_output.SpanByteAndMemory.IsSpanByte); switch (status) { @@ -308,8 +308,8 @@ public bool InvokeCustomObjectCommand(ref TGarnetApi storageApi, Cus output = scratchBufferManager.CreateArgSlice(CmdStrings.RESP_ERR_WRONG_TYPE); break; default: - if (_output.spanByteAndMemory.Memory != null) - output = scratchBufferManager.FormatScratch(0, _output.spanByteAndMemory.AsReadOnlySpan()); + if (_output.SpanByteAndMemory.Memory != null) + output = scratchBufferManager.FormatScratch(0, _output.SpanByteAndMemory.AsReadOnlySpan()); else output = scratchBufferManager.CreateArgSlice(CmdStrings.RESP_OK); break; @@ -318,18 +318,18 @@ public bool InvokeCustomObjectCommand(ref TGarnetApi storageApi, Cus else { status = storageApi.Read_ObjectStore(ref keyBytes, ref input, ref _output); - Debug.Assert(!_output.spanByteAndMemory.IsSpanByte); + Debug.Assert(!_output.SpanByteAndMemory.IsSpanByte); switch (status) { case GarnetStatus.OK: - if (_output.spanByteAndMemory.Memory != null) - output = scratchBufferManager.FormatScratch(0, _output.spanByteAndMemory.AsReadOnlySpan()); + if (_output.SpanByteAndMemory.Memory != null) + output = scratchBufferManager.FormatScratch(0, _output.SpanByteAndMemory.AsReadOnlySpan()); else output = scratchBufferManager.CreateArgSlice(CmdStrings.RESP_OK); break; case GarnetStatus.NOTFOUND: - Debug.Assert(_output.spanByteAndMemory.Memory == null); + Debug.Assert(_output.SpanByteAndMemory.Memory == null); output = scratchBufferManager.CreateArgSlice(CmdStrings.RESP_ERRNOTFOUND); break; case GarnetStatus.WRONGTYPE: diff --git a/libs/server/Objects/Hash/HashObject.cs b/libs/server/Objects/Hash/HashObject.cs index 8ba8c21b63..215cb1010c 100644 --- a/libs/server/Objects/Hash/HashObject.cs +++ b/libs/server/Objects/Hash/HashObject.cs @@ -155,17 +155,17 @@ public override void Dispose() { } public override GarnetObjectBase Clone() => new HashObject(hash, expirationTimes, expirationQueue, Expiration, Size); /// - public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory output, out long sizeChange, out bool removeKey) + public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output, out long sizeChange) { - removeKey = false; + sizeChange = 0; - fixed (byte* _output = output.SpanByte.AsSpan()) + fixed (byte* outputSpan = output.SpanByteAndMemory.SpanByte.AsSpan()) { if (input.header.type != GarnetObjectType.Hash) { //Indicates when there is an incorrect type - output.Length = 0; - sizeChange = 0; + output.OutputFlags |= ObjectStoreOutputFlags.WrongType; + output.SpanByteAndMemory.Length = 0; return true; } @@ -173,73 +173,73 @@ public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory switch (input.header.HashOp) { case HashOperation.HSET: - HashSet(ref input, _output); + HashSet(ref input, outputSpan); break; case HashOperation.HMSET: - HashSet(ref input, _output); + HashSet(ref input, outputSpan); break; case HashOperation.HGET: - HashGet(ref input, ref output); + HashGet(ref input, ref output.SpanByteAndMemory); break; case HashOperation.HMGET: - HashMultipleGet(ref input, ref output); + HashMultipleGet(ref input, ref output.SpanByteAndMemory); break; case HashOperation.HGETALL: - HashGetAll(ref input, ref output); + HashGetAll(ref input, ref output.SpanByteAndMemory); break; case HashOperation.HDEL: - HashDelete(ref input, _output); + HashDelete(ref input, outputSpan); break; case HashOperation.HLEN: - HashLength(_output); + HashLength(outputSpan); break; case HashOperation.HSTRLEN: - HashStrLength(ref input, _output); + HashStrLength(ref input, outputSpan); break; case HashOperation.HEXISTS: - HashExists(ref input, _output); + HashExists(ref input, outputSpan); break; case HashOperation.HEXPIRE: - HashExpire(ref input, ref output); + HashExpire(ref input, ref output.SpanByteAndMemory); break; case HashOperation.HTTL: - HashTimeToLive(ref input, ref output); + HashTimeToLive(ref input, ref output.SpanByteAndMemory); break; case HashOperation.HPERSIST: - HashPersist(ref input, ref output); + HashPersist(ref input, ref output.SpanByteAndMemory); break; case HashOperation.HKEYS: - HashGetKeysOrValues(ref input, ref output); + HashGetKeysOrValues(ref input, ref output.SpanByteAndMemory); break; case HashOperation.HVALS: - HashGetKeysOrValues(ref input, ref output); + HashGetKeysOrValues(ref input, ref output.SpanByteAndMemory); break; case HashOperation.HINCRBY: - HashIncrement(ref input, ref output); + HashIncrement(ref input, ref output.SpanByteAndMemory); break; case HashOperation.HINCRBYFLOAT: - HashIncrement(ref input, ref output); + HashIncrement(ref input, ref output.SpanByteAndMemory); break; case HashOperation.HSETNX: - HashSet(ref input, _output); + HashSet(ref input, outputSpan); break; case HashOperation.HRANDFIELD: - HashRandomField(ref input, ref output); + HashRandomField(ref input, ref output.SpanByteAndMemory); break; case HashOperation.HCOLLECT: - HashCollect(ref input, _output); + HashCollect(ref input, outputSpan); break; case HashOperation.HSCAN: - if (ObjectUtils.ReadScanInput(ref input, ref output, out var cursorInput, out var pattern, - out var patternLength, out var limitCount, out bool isNoValue, out var error)) + if (ObjectUtils.ReadScanInput(ref input, ref output.SpanByteAndMemory, out var cursorInput, out var pattern, + out var patternLength, out var limitCount, out var isNoValue, out var error)) { Scan(cursorInput, out var items, out var cursorOutput, count: limitCount, pattern: pattern, patternLength: patternLength, isNoValue); - ObjectUtils.WriteScanOutput(items, cursorOutput, ref output); + ObjectUtils.WriteScanOutput(items, cursorOutput, ref output.SpanByteAndMemory); } else { - ObjectUtils.WriteScanError(error, ref output); + ObjectUtils.WriteScanError(error, ref output.SpanByteAndMemory); } break; default: @@ -249,7 +249,9 @@ public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory sizeChange = this.Size - previousSize; } - removeKey = hash.Count == 0; + if (hash.Count == 0) + output.OutputFlags |= ObjectStoreOutputFlags.RemoveKey; + return true; } diff --git a/libs/server/Objects/ItemBroker/CollectionItemBroker.cs b/libs/server/Objects/ItemBroker/CollectionItemBroker.cs index f781d26974..e092f63697 100644 --- a/libs/server/Objects/ItemBroker/CollectionItemBroker.cs +++ b/libs/server/Objects/ItemBroker/CollectionItemBroker.cs @@ -473,12 +473,12 @@ private unsafe bool TryGetResult(byte[] key, StorageSession storageSession, Resp { arrDstKey = dstKey.ToArray(); var dstStatusOp = storageSession.GET(arrDstKey, out var osDstObject, ref objectLockableContext); - if (dstStatusOp != GarnetStatus.NOTFOUND) dstObj = osDstObject.garnetObject; + if (dstStatusOp != GarnetStatus.NOTFOUND) dstObj = osDstObject.GarnetObject; } // Check for type match between the observer and the actual object type // If types match, get next item based on item type - switch (osObject.garnetObject) + switch (osObject.GarnetObject) { case ListObject listObj: currCount = listObj.LnkList.Count; diff --git a/libs/server/Objects/List/ListObject.cs b/libs/server/Objects/List/ListObject.cs index b807548e23..2771b84b25 100644 --- a/libs/server/Objects/List/ListObject.cs +++ b/libs/server/Objects/List/ListObject.cs @@ -128,17 +128,17 @@ public override void Dispose() { } public override GarnetObjectBase Clone() => new ListObject(list, Expiration, Size); /// - public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory output, out long sizeChange, out bool removeKey) + public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output, out long sizeChange) { - fixed (byte* _output = output.SpanByte.AsSpan()) - { - removeKey = false; + sizeChange = 0; + fixed (byte* outputSpan = output.SpanByteAndMemory.SpanByte.AsSpan()) + { if (input.header.type != GarnetObjectType.List) { // Indicates an incorrect type of key - output.Length = 0; - sizeChange = 0; + output.OutputFlags |= ObjectStoreOutputFlags.WrongType; + output.SpanByteAndMemory.Length = 0; return true; } @@ -147,41 +147,41 @@ public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory { case ListOperation.LPUSH: case ListOperation.LPUSHX: - ListPush(ref input, _output, true); + ListPush(ref input, outputSpan, true); break; case ListOperation.LPOP: - ListPop(ref input, ref output, true); + ListPop(ref input, ref output.SpanByteAndMemory, true); break; case ListOperation.RPUSH: case ListOperation.RPUSHX: - ListPush(ref input, _output, false); + ListPush(ref input, outputSpan, false); break; case ListOperation.RPOP: - ListPop(ref input, ref output, false); + ListPop(ref input, ref output.SpanByteAndMemory, false); break; case ListOperation.LLEN: - ListLength(_output); + ListLength(outputSpan); break; case ListOperation.LTRIM: - ListTrim(ref input, _output); + ListTrim(ref input, outputSpan); break; case ListOperation.LRANGE: - ListRange(ref input, ref output); + ListRange(ref input, ref output.SpanByteAndMemory); break; case ListOperation.LINDEX: - ListIndex(ref input, ref output); + ListIndex(ref input, ref output.SpanByteAndMemory); break; case ListOperation.LINSERT: - ListInsert(ref input, _output); + ListInsert(ref input, outputSpan); break; case ListOperation.LREM: - ListRemove(ref input, _output); + ListRemove(ref input, outputSpan); break; case ListOperation.LSET: - ListSet(ref input, ref output); + ListSet(ref input, ref output.SpanByteAndMemory); break; case ListOperation.LPOS: - ListPosition(ref input, ref output); + ListPosition(ref input, ref output.SpanByteAndMemory); break; default: @@ -191,7 +191,9 @@ public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory sizeChange = this.Size - previousSize; } - removeKey = list.Count == 0; + if (list.Count == 0) + output.OutputFlags |= ObjectStoreOutputFlags.RemoveKey; + return true; } diff --git a/libs/server/Objects/Set/SetObject.cs b/libs/server/Objects/Set/SetObject.cs index 1de3662dc6..8c4bd2535c 100644 --- a/libs/server/Objects/Set/SetObject.cs +++ b/libs/server/Objects/Set/SetObject.cs @@ -105,16 +105,17 @@ public override void Dispose() { } public override GarnetObjectBase Clone() => new SetObject(set, Expiration, Size); /// - public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory output, out long sizeChange, out bool removeKey) + public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output, out long sizeChange) { - fixed (byte* _output = output.SpanByte.AsSpan()) + sizeChange = 0; + + fixed (byte* outputSpan = output.SpanByteAndMemory.SpanByte.AsSpan()) { if (input.header.type != GarnetObjectType.Set) { // Indicates an incorrect type of key - output.Length = 0; - sizeChange = 0; - removeKey = false; + output.OutputFlags |= ObjectStoreOutputFlags.WrongType; + output.SpanByteAndMemory.Length = 0; return true; } @@ -122,49 +123,52 @@ public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory switch (input.header.SetOp) { case SetOperation.SADD: - SetAdd(ref input, _output); + SetAdd(ref input, outputSpan); break; case SetOperation.SMEMBERS: - SetMembers(ref output); + SetMembers(ref output.SpanByteAndMemory); break; case SetOperation.SISMEMBER: - SetIsMember(ref input, ref output); + SetIsMember(ref input, ref output.SpanByteAndMemory); break; case SetOperation.SMISMEMBER: - SetMultiIsMember(ref input, ref output); + SetMultiIsMember(ref input, ref output.SpanByteAndMemory); break; case SetOperation.SREM: - SetRemove(ref input, _output); + SetRemove(ref input, outputSpan); break; case SetOperation.SCARD: - SetLength(_output); + SetLength(outputSpan); break; case SetOperation.SPOP: - SetPop(ref input, ref output); + SetPop(ref input, ref output.SpanByteAndMemory); break; case SetOperation.SRANDMEMBER: - SetRandomMember(ref input, ref output); + SetRandomMember(ref input, ref output.SpanByteAndMemory); break; case SetOperation.SSCAN: - if (ObjectUtils.ReadScanInput(ref input, ref output, out var cursorInput, out var pattern, - out var patternLength, out var limitCount, out bool _, out var error)) + if (ObjectUtils.ReadScanInput(ref input, ref output.SpanByteAndMemory, out var cursorInput, out var pattern, + out var patternLength, out var limitCount, out _, out var error)) { Scan(cursorInput, out var items, out var cursorOutput, count: limitCount, pattern: pattern, patternLength: patternLength); - ObjectUtils.WriteScanOutput(items, cursorOutput, ref output); + ObjectUtils.WriteScanOutput(items, cursorOutput, ref output.SpanByteAndMemory); } else { - ObjectUtils.WriteScanError(error, ref output); + ObjectUtils.WriteScanError(error, ref output.SpanByteAndMemory); } break; default: throw new GarnetException($"Unsupported operation {input.header.SetOp} in SetObject.Operate"); } + sizeChange = this.Size - prevSize; } - removeKey = set.Count == 0; + if (set.Count == 0) + output.OutputFlags |= ObjectStoreOutputFlags.RemoveKey; + return true; } diff --git a/libs/server/Objects/SortedSet/SortedSetObject.cs b/libs/server/Objects/SortedSet/SortedSetObject.cs index ab6bf7d4e5..cbfa9dd1a6 100644 --- a/libs/server/Objects/SortedSet/SortedSetObject.cs +++ b/libs/server/Objects/SortedSet/SortedSetObject.cs @@ -212,17 +212,18 @@ public override void Dispose() { } public override GarnetObjectBase Clone() => new SortedSetObject(sortedSet, sortedSetDict, Expiration, Size); /// - public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory output, out long sizeChange, out bool removeKey) + public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output, out long sizeChange) { - fixed (byte* outputSpan = output.SpanByte.AsSpan()) + sizeChange = 0; + + fixed (byte* outputSpan = output.SpanByteAndMemory.SpanByte.AsSpan()) { var header = input.header; if (header.type != GarnetObjectType.SortedSet) { // Indicates an incorrect type of key - output.Length = 0; - sizeChange = 0; - removeKey = false; + output.OutputFlags |= ObjectStoreOutputFlags.WrongType; + output.SpanByteAndMemory.Length = 0; return true; } @@ -231,7 +232,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory switch (op) { case SortedSetOperation.ZADD: - SortedSetAdd(ref input, ref output); + SortedSetAdd(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.ZREM: SortedSetRemove(ref input, outputSpan); @@ -240,94 +241,97 @@ public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory SortedSetLength(outputSpan); break; case SortedSetOperation.ZPOPMAX: - SortedSetPopMinOrMaxCount(ref input, ref output, op); + SortedSetPopMinOrMaxCount(ref input, ref output.SpanByteAndMemory, op); break; case SortedSetOperation.ZSCORE: - SortedSetScore(ref input, ref output); + SortedSetScore(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.ZMSCORE: - SortedSetScores(ref input, ref output); + SortedSetScores(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.ZCOUNT: - SortedSetCount(ref input, ref output); + SortedSetCount(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.ZINCRBY: - SortedSetIncrement(ref input, ref output); + SortedSetIncrement(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.ZRANK: - SortedSetRank(ref input, ref output); + SortedSetRank(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.ZRANGE: case SortedSetOperation.ZRANGESTORE: - SortedSetRange(ref input, ref output); + SortedSetRange(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.ZRANGEBYSCORE: - SortedSetRange(ref input, ref output); + SortedSetRange(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.GEOADD: - GeoAdd(ref input, ref output); + GeoAdd(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.GEOHASH: - GeoHash(ref input, ref output); + GeoHash(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.GEODIST: - GeoDistance(ref input, ref output); + GeoDistance(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.GEOPOS: - GeoPosition(ref input, ref output); + GeoPosition(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.GEOSEARCH: case SortedSetOperation.GEOSEARCHSTORE: - GeoSearch(ref input, ref output); + GeoSearch(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.ZREVRANGE: - SortedSetRange(ref input, ref output); + SortedSetRange(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.ZREVRANGEBYLEX: case SortedSetOperation.ZREVRANGEBYSCORE: - SortedSetRange(ref input, ref output); + SortedSetRange(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.ZREVRANK: - SortedSetRank(ref input, ref output, ascending: false); + SortedSetRank(ref input, ref output.SpanByteAndMemory, ascending: false); break; case SortedSetOperation.ZREMRANGEBYLEX: SortedSetRemoveOrCountRangeByLex(ref input, outputSpan, op); break; case SortedSetOperation.ZREMRANGEBYRANK: - SortedSetRemoveRangeByRank(ref input, ref output); + SortedSetRemoveRangeByRank(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.ZREMRANGEBYSCORE: - SortedSetRemoveRangeByScore(ref input, ref output); + SortedSetRemoveRangeByScore(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.ZLEXCOUNT: SortedSetRemoveOrCountRangeByLex(ref input, outputSpan, op); break; case SortedSetOperation.ZPOPMIN: - SortedSetPopMinOrMaxCount(ref input, ref output, op); + SortedSetPopMinOrMaxCount(ref input, ref output.SpanByteAndMemory, op); break; case SortedSetOperation.ZRANDMEMBER: - SortedSetRandomMember(ref input, ref output); + SortedSetRandomMember(ref input, ref output.SpanByteAndMemory); break; case SortedSetOperation.ZSCAN: - if (ObjectUtils.ReadScanInput(ref input, ref output, out var cursorInput, out var pattern, + if (ObjectUtils.ReadScanInput(ref input, ref output.SpanByteAndMemory, out var cursorInput, out var pattern, out var patternLength, out var limitCount, out var _, out var error)) { Scan(cursorInput, out var items, out var cursorOutput, count: limitCount, pattern: pattern, patternLength: patternLength); - ObjectUtils.WriteScanOutput(items, cursorOutput, ref output); + ObjectUtils.WriteScanOutput(items, cursorOutput, ref output.SpanByteAndMemory); } else { - ObjectUtils.WriteScanError(error, ref output); + ObjectUtils.WriteScanError(error, ref output.SpanByteAndMemory); } break; default: throw new GarnetException($"Unsupported operation {op} in SortedSetObject.Operate"); } + sizeChange = this.Size - prevSize; } - removeKey = sortedSetDict.Count == 0; + if (sortedSetDict.Count == 0) + output.OutputFlags |= ObjectStoreOutputFlags.RemoveKey; + return true; } diff --git a/libs/server/Objects/Types/GarnetObjectBase.cs b/libs/server/Objects/Types/GarnetObjectBase.cs index f792b8ac4d..87bb279f10 100644 --- a/libs/server/Objects/Types/GarnetObjectBase.cs +++ b/libs/server/Objects/Types/GarnetObjectBase.cs @@ -116,7 +116,7 @@ public void CopyUpdate(ref IGarnetObject oldValue, ref IGarnetObject newValue, b public abstract GarnetObjectBase Clone(); /// - public abstract bool Operate(ref ObjectInput input, ref SpanByteAndMemory output, out long sizeChange, out bool removeKey); + public abstract bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output, out long sizeChange); /// public abstract void Dispose(); diff --git a/libs/server/Objects/Types/GarnetObjectStoreOutput.cs b/libs/server/Objects/Types/GarnetObjectStoreOutput.cs index 410047daf8..c6dba3be90 100644 --- a/libs/server/Objects/Types/GarnetObjectStoreOutput.cs +++ b/libs/server/Objects/Types/GarnetObjectStoreOutput.cs @@ -1,24 +1,54 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +using System; using Tsavorite.core; namespace Garnet.server { + /// + /// Flags for object store outputs. + /// + [Flags] + public enum ObjectStoreOutputFlags : byte + { + /// + /// No flags set + /// + None = 0, + + /// + /// Remove key + /// + RemoveKey = 1, + + /// + /// Wrong type of object + /// + WrongType = 1 << 1, + } + /// /// Output type used by Garnet object store. + /// Any field / property added to this struct must be set in the back-end (IFunctions) and used in the front-end (GarnetApi caller). + /// That is in order to justify transferring data in this struct through the Tsavorite storage layer. /// public struct GarnetObjectStoreOutput { /// - /// span byte and memory + /// Span byte and memory /// - public SpanByteAndMemory spanByteAndMemory; + public SpanByteAndMemory SpanByteAndMemory; /// /// Garnet object /// - public IGarnetObject garnetObject; + public IGarnetObject GarnetObject; + + /// + /// Output flags + /// + public ObjectStoreOutputFlags OutputFlags; public void ConvertToHeap() { diff --git a/libs/server/Objects/Types/IGarnetObject.cs b/libs/server/Objects/Types/IGarnetObject.cs index b56cb71785..41ff2f3c3d 100644 --- a/libs/server/Objects/Types/IGarnetObject.cs +++ b/libs/server/Objects/Types/IGarnetObject.cs @@ -34,9 +34,8 @@ public interface IGarnetObject : IDisposable /// /// /// - /// /// - bool Operate(ref ObjectInput input, ref SpanByteAndMemory output, out long sizeChange, out bool removeKey); + bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output, out long sizeChange); /// /// Serializer diff --git a/libs/server/Resp/Objects/HashCommands.cs b/libs/server/Resp/Objects/HashCommands.cs index 58622d2538..1062e68ade 100644 --- a/libs/server/Resp/Objects/HashCommands.cs +++ b/libs/server/Resp/Objects/HashCommands.cs @@ -95,14 +95,14 @@ private bool HashGet(RespCommand command, ref TGarnetApi storageApi) var input = new ObjectInput(header, ref parseState, startIdx: 1); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.HashGet(keyBytes, ref input, ref outputFooter); switch (status) { case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteDirect(CmdStrings.RESP_ERRNOTFOUND, ref dcurr, dend)) @@ -139,14 +139,14 @@ private bool HashGetAll(RespCommand command, ref TGarnetApi storageA var input = new ObjectInput(header, respProtocolVersion); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.HashGetAll(keyBytes, ref input, ref outputFooter); switch (status) { case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteDirect(CmdStrings.RESP_EMPTYLIST, ref dcurr, dend)) @@ -183,14 +183,14 @@ private bool HashGetMultiple(RespCommand command, ref TGarnetApi sto var input = new ObjectInput(header, ref parseState, startIdx: 1); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.HashGetMultiple(keyBytes, ref input, ref outputFooter); switch (status) { case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: // Write an empty array of count - 1 elements with null values. @@ -263,7 +263,7 @@ private bool HashRandomField(RespCommand command, ref TGarnetApi sto var input = new ObjectInput(header, countWithMetadata, seed); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = GarnetStatus.NOTFOUND; @@ -271,14 +271,14 @@ private bool HashRandomField(RespCommand command, ref TGarnetApi sto if (paramCount != 0) { // Prepare GarnetObjectStore output - outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; status = storageApi.HashRandomField(keyBytes, ref input, ref outputFooter); } switch (status) { case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: var respBytes = includedCount ? CmdStrings.RESP_EMPTYLIST : CmdStrings.RESP_ERRNOTFOUND; @@ -496,7 +496,7 @@ private unsafe bool HashKeys(RespCommand command, ref TGarnetApi sto var input = new ObjectInput(header); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = command == RespCommand.HKEYS ? storageApi.HashKeys(keyBytes, ref input, ref outputFooter) @@ -505,7 +505,7 @@ private unsafe bool HashKeys(RespCommand command, ref TGarnetApi sto switch (status) { case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteEmptyArray(ref dcurr, dend)) @@ -554,7 +554,7 @@ private unsafe bool HashIncrement(RespCommand command, ref TGarnetAp var input = new ObjectInput(header, ref parseState, startIdx: 1); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.HashIncrement(keyBytes, ref input, ref outputFooter); @@ -565,7 +565,7 @@ private unsafe bool HashIncrement(RespCommand command, ref TGarnetAp SendAndReset(); break; default: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; } return true; @@ -648,7 +648,7 @@ private unsafe bool HashExpire(RespCommand command, ref TGarnetApi s var header = new RespInputHeader(GarnetObjectType.Hash) { HashOp = HashOperation.HEXPIRE }; var input = new ObjectInput(header, ref fieldsParseState); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.HashExpire(key, expireAt, isMilliseconds, expireOption, ref input, ref outputFooter); @@ -668,7 +668,7 @@ private unsafe bool HashExpire(RespCommand command, ref TGarnetApi s } break; default: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; } @@ -738,7 +738,7 @@ private unsafe bool HashTimeToLive(RespCommand command, ref TGarnetA var header = new RespInputHeader(GarnetObjectType.Hash) { HashOp = HashOperation.HTTL }; var input = new ObjectInput(header, ref fieldsParseState); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.HashTimeToLive(key, isMilliseconds, isTimestamp, ref input, ref outputFooter); @@ -758,7 +758,7 @@ private unsafe bool HashTimeToLive(RespCommand command, ref TGarnetA } break; default: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; } @@ -800,7 +800,7 @@ private unsafe bool HashPersist(ref TGarnetApi storageApi) var header = new RespInputHeader(GarnetObjectType.Hash) { HashOp = HashOperation.HPERSIST }; var input = new ObjectInput(header, ref fieldsParseState); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.HashPersist(key, ref input, ref outputFooter); @@ -820,7 +820,7 @@ private unsafe bool HashPersist(ref TGarnetApi storageApi) } break; default: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; } diff --git a/libs/server/Resp/Objects/ListCommands.cs b/libs/server/Resp/Objects/ListCommands.cs index f7bb079656..89d682da68 100644 --- a/libs/server/Resp/Objects/ListCommands.cs +++ b/libs/server/Resp/Objects/ListCommands.cs @@ -106,7 +106,7 @@ private unsafe bool ListPop(RespCommand command, ref TGarnetApi stor var input = new ObjectInput(header, popCount); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var statusOp = command == RespCommand.LPOP ? storageApi.ListLeftPop(keyBytes, ref input, ref outputFooter) @@ -116,7 +116,7 @@ private unsafe bool ListPop(RespCommand command, ref TGarnetApi stor { case GarnetStatus.OK: //process output - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteDirect(CmdStrings.RESP_ERRNOTFOUND, ref dcurr, dend)) @@ -156,14 +156,14 @@ private unsafe bool ListPosition(ref TGarnetApi storageApi) var input = new ObjectInput(header, ref parseState, startIdx: 1); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var statusOp = storageApi.ListPosition(keyBytes, ref input, ref outputFooter); switch (statusOp) { case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteDirect(CmdStrings.RESP_ERRNOTFOUND, ref dcurr, dend)) @@ -540,7 +540,7 @@ private bool ListRange(ref TGarnetApi storageApi) var input = new ObjectInput(header, start, end); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var statusOp = storageApi.ListRange(keyBytes, ref input, ref outputFooter); @@ -548,7 +548,7 @@ private bool ListRange(ref TGarnetApi storageApi) { case GarnetStatus.OK: //process output - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteDirect(CmdStrings.RESP_EMPTYLIST, ref dcurr, dend)) @@ -594,7 +594,7 @@ private bool ListIndex(ref TGarnetApi storageApi) var input = new ObjectInput(header, index); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var statusOp = storageApi.ListIndex(keyBytes, ref input, ref outputFooter); @@ -604,7 +604,7 @@ private bool ListIndex(ref TGarnetApi storageApi) { case GarnetStatus.OK: //process output - var objOutputHeader = ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + var objOutputHeader = ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); if (objOutputHeader.result1 == -1) error = CmdStrings.RESP_ERRNOTFOUND; break; @@ -879,7 +879,7 @@ public bool ListSet(ref TGarnetApi storageApi) var input = new ObjectInput(header, ref parseState, startIdx: 1); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var statusOp = storageApi.ListSet(keyBytes, ref input, ref outputFooter); @@ -887,7 +887,7 @@ public bool ListSet(ref TGarnetApi storageApi) { case GarnetStatus.OK: //process output - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteError(CmdStrings.RESP_ERR_GENERIC_NOSUCHKEY, ref dcurr, dend)) diff --git a/libs/server/Resp/Objects/SetCommands.cs b/libs/server/Resp/Objects/SetCommands.cs index 40e1f74970..deee98c06a 100644 --- a/libs/server/Resp/Objects/SetCommands.cs +++ b/libs/server/Resp/Objects/SetCommands.cs @@ -418,7 +418,7 @@ private unsafe bool SetMembers(ref TGarnetApi storageApi) var input = new ObjectInput(header); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.SetMembers(keyBytes, ref input, ref outputFooter); @@ -426,7 +426,7 @@ private unsafe bool SetMembers(ref TGarnetApi storageApi) { case GarnetStatus.OK: // Process output - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteEmptyArray(ref dcurr, dend)) @@ -471,7 +471,7 @@ private unsafe bool SetIsMember(RespCommand cmd, ref TGarnetApi stor var input = new ObjectInput(header, ref parseState, startIdx: 1); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.SetIsMember(keyBytes, ref input, ref outputFooter); @@ -479,7 +479,7 @@ private unsafe bool SetIsMember(RespCommand cmd, ref TGarnetApi stor { case GarnetStatus.OK: // Process output - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: if (isSingle) @@ -554,7 +554,7 @@ private unsafe bool SetPop(ref TGarnetApi storageApi) var input = new ObjectInput(header, countParameter); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.SetPop(keyBytes, ref input, ref outputFooter); @@ -562,7 +562,7 @@ private unsafe bool SetPop(ref TGarnetApi storageApi) { case GarnetStatus.OK: // Process output - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteDirect(CmdStrings.RESP_ERRNOTFOUND, ref dcurr, dend)) @@ -673,7 +673,7 @@ private unsafe bool SetRandomMember(ref TGarnetApi storageApi) var input = new ObjectInput(header, countParameter, seed); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.SetRandomMember(keyBytes, ref input, ref outputFooter); @@ -681,7 +681,7 @@ private unsafe bool SetRandomMember(ref TGarnetApi storageApi) { case GarnetStatus.OK: // Process output - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: if (parseState.Count == 2) diff --git a/libs/server/Resp/Objects/SharedObjectCommands.cs b/libs/server/Resp/Objects/SharedObjectCommands.cs index 07b32fe245..d2ad5cbcf2 100644 --- a/libs/server/Resp/Objects/SharedObjectCommands.cs +++ b/libs/server/Resp/Objects/SharedObjectCommands.cs @@ -67,14 +67,14 @@ private unsafe bool ObjectScan(GarnetObjectType objectType, ref TGar } // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.ObjectScan(keyBytes, ref input, ref outputFooter); switch (status) { case GarnetStatus.OK: // Process output - var objOutputHeader = ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + var objOutputHeader = ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); // Validation for partial input reading or error if (objOutputHeader.result1 == int.MinValue) return false; diff --git a/libs/server/Resp/Objects/SortedSetCommands.cs b/libs/server/Resp/Objects/SortedSetCommands.cs index 4402b19c33..136372b9b2 100644 --- a/libs/server/Resp/Objects/SortedSetCommands.cs +++ b/libs/server/Resp/Objects/SortedSetCommands.cs @@ -35,7 +35,7 @@ private unsafe bool SortedSetAdd(ref TGarnetApi storageApi) var header = new RespInputHeader(GarnetObjectType.SortedSet) { SortedSetOp = SortedSetOperation.ZADD }; var input = new ObjectInput(header, ref parseState, startIdx: 1); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.SortedSetAdd(keyBytes, ref input, ref outputFooter); @@ -46,7 +46,7 @@ private unsafe bool SortedSetAdd(ref TGarnetApi storageApi) SendAndReset(); break; default: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; } @@ -173,14 +173,14 @@ private unsafe bool SortedSetRange(RespCommand command, ref TGarnetA var header = new RespInputHeader(GarnetObjectType.SortedSet) { SortedSetOp = op }; var input = new ObjectInput(header, ref parseState, startIdx: 1, arg1: respProtocolVersion); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.SortedSetRange(keyBytes, ref input, ref outputFooter); switch (status) { case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteEmptyArray(ref dcurr, dend)) @@ -252,14 +252,14 @@ private unsafe bool SortedSetScore(ref TGarnetApi storageApi) var input = new ObjectInput(header, ref parseState, startIdx: 1); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.SortedSetScore(keyBytes, ref input, ref outputFooter); switch (status) { case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteDirect(CmdStrings.RESP_ERRNOTFOUND, ref dcurr, dend)) @@ -299,14 +299,14 @@ private unsafe bool SortedSetScores(ref TGarnetApi storageApi) var input = new ObjectInput(header, ref parseState, startIdx: 1); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.SortedSetScores(keyBytes, ref input, ref outputFooter); switch (status) { case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteArrayWithNullElements(parseState.Count - 1, ref dcurr, dend)) @@ -368,14 +368,14 @@ private unsafe bool SortedSetPop(RespCommand command, ref TGarnetApi var input = new ObjectInput(header, popCount); // Prepare output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(SpanByte.FromPinnedPointer(dcurr, (int)(dend - dcurr))) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(SpanByte.FromPinnedPointer(dcurr, (int)(dend - dcurr))) }; var status = storageApi.SortedSetPop(keyBytes, ref input, ref outputFooter); switch (status) { case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteEmptyArray(ref dcurr, dend)) @@ -529,14 +529,14 @@ private unsafe bool SortedSetCount(ref TGarnetApi storageApi) var input = new ObjectInput(header, ref parseState, startIdx: 1); // Prepare output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(SpanByte.FromPinnedPointer(dcurr, (int)(dend - dcurr))) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(SpanByte.FromPinnedPointer(dcurr, (int)(dend - dcurr))) }; var status = storageApi.SortedSetCount(keyBytes, ref input, ref outputFooter); switch (status) { case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend)) @@ -644,7 +644,7 @@ private unsafe bool SortedSetIncrement(ref TGarnetApi storageApi) var input = new ObjectInput(header, ref parseState, startIdx: 1); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.SortedSetIncrement(keyBytes, ref input, ref outputFooter); @@ -652,7 +652,7 @@ private unsafe bool SortedSetIncrement(ref TGarnetApi storageApi) { case GarnetStatus.NOTFOUND: case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.WRONGTYPE: while (!RespWriteUtils.WriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend)) @@ -713,14 +713,14 @@ private unsafe bool SortedSetRank(RespCommand command, ref TGarnetAp var input = new ObjectInput(header, ref parseState, startIdx: 1, arg1: includeWithScore ? 1 : 0); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.SortedSetRank(keyBytes, ref input, ref outputFooter); switch (status) { case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteDirect(CmdStrings.RESP_ERRNOTFOUND, ref dcurr, dend)) @@ -769,14 +769,14 @@ private unsafe bool SortedSetRemoveRange(RespCommand command, ref TG var input = new ObjectInput(header, ref parseState, startIdx: 1); // Prepare GarnetObjectStore output - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.SortedSetRemoveRange(keyBytes, ref input, ref outputFooter); switch (status) { case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: while (!RespWriteUtils.WriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend)) @@ -856,14 +856,14 @@ private unsafe bool SortedSetRandomMember(ref TGarnetApi storageApi) if (paramCount != 0) { // Prepare GarnetObjectStore output - outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; status = storageApi.SortedSetRandomMember(keyBytes, ref input, ref outputFooter); } switch (status) { case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: var respBytes = includedCount ? CmdStrings.RESP_EMPTYLIST : CmdStrings.RESP_ERRNOTFOUND; diff --git a/libs/server/Resp/Objects/SortedSetGeoCommands.cs b/libs/server/Resp/Objects/SortedSetGeoCommands.cs index 2746df4b6b..7be7791bfa 100644 --- a/libs/server/Resp/Objects/SortedSetGeoCommands.cs +++ b/libs/server/Resp/Objects/SortedSetGeoCommands.cs @@ -33,7 +33,7 @@ private unsafe bool GeoAdd(ref TGarnetApi storageApi) var header = new RespInputHeader(GarnetObjectType.SortedSet) { SortedSetOp = SortedSetOperation.GEOADD }; var input = new ObjectInput(header, ref parseState, startIdx: 1); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.GeoAdd(keyBytes, ref input, ref outputFooter); @@ -44,7 +44,7 @@ private unsafe bool GeoAdd(ref TGarnetApi storageApi) SendAndReset(); break; default: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; } @@ -107,14 +107,14 @@ private unsafe bool GeoCommands(RespCommand command, ref TGarnetApi var input = new ObjectInput(header, ref parseState, startIdx: 1); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(dcurr, (int)(dend - dcurr)) }; var status = storageApi.GeoCommands(keyBytes, ref input, ref outputFooter); switch (status) { case GarnetStatus.OK: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; case GarnetStatus.NOTFOUND: switch (op) diff --git a/libs/server/Resp/RespCommandsInfo.cs b/libs/server/Resp/RespCommandsInfo.cs index 0da1797398..0624f75d39 100644 --- a/libs/server/Resp/RespCommandsInfo.cs +++ b/libs/server/Resp/RespCommandsInfo.cs @@ -196,7 +196,7 @@ private static bool TryInitializeRespCommandsInfo(ILogger logger = null) .GroupBy(static t => t.Acl) .ToDictionary( static grp => grp.Key, - static grp => (IReadOnlyList)ImmutableArray.CreateRange(grp.Select(static t => t.CommandInfo)) + static grp => (IReadOnlyList)[.. grp.Select(static t => t.CommandInfo)] ) ); diff --git a/libs/server/Storage/Functions/ObjectStore/PrivateMethods.cs b/libs/server/Storage/Functions/ObjectStore/PrivateMethods.cs index 88f08e9d53..e3740c8068 100644 --- a/libs/server/Storage/Functions/ObjectStore/PrivateMethods.cs +++ b/libs/server/Storage/Functions/ObjectStore/PrivateMethods.cs @@ -122,8 +122,8 @@ static void CopyDefaultResp(ReadOnlySpan resp, ref SpanByteAndMemory dst) static bool EvaluateObjectExpireInPlace(ExpireOption optionType, bool expiryExists, long expiration, ref IGarnetObject value, ref GarnetObjectStoreOutput output) { - Debug.Assert(output.spanByteAndMemory.IsSpanByte, "This code assumes it is called in-place and did not go pending"); - var o = (ObjectOutputHeader*)output.spanByteAndMemory.SpanByte.ToPointer(); + Debug.Assert(output.SpanByteAndMemory.IsSpanByte, "This code assumes it is called in-place and did not go pending"); + var o = (ObjectOutputHeader*)output.SpanByteAndMemory.SpanByte.ToPointer(); if (expiryExists) { switch (optionType) diff --git a/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs b/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs index b8732523a9..d53ade1bfe 100644 --- a/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs +++ b/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs @@ -31,10 +31,10 @@ public bool NeedInitialUpdate(ref byte[] key, ref ObjectInput input, ref GarnetO else { var customObjectCommand = GetCustomObjectCommand(ref input, type); - (IMemoryOwner Memory, int Length) outp = (output.spanByteAndMemory.Memory, 0); + (IMemoryOwner Memory, int Length) outp = (output.SpanByteAndMemory.Memory, 0); var ret = customObjectCommand.NeedInitialUpdate(key, ref input, ref outp); - output.spanByteAndMemory.Memory = outp.Memory; - output.spanByteAndMemory.Length = outp.Length; + output.SpanByteAndMemory.Memory = outp.Memory; + output.SpanByteAndMemory.Length = outp.Length; return ret; } } @@ -47,7 +47,7 @@ public bool InitialUpdater(ref byte[] key, ref ObjectInput input, ref IGarnetObj if ((byte)type < CustomCommandManager.CustomTypeIdStartOffset) { value = GarnetObject.Create(type); - value.Operate(ref input, ref output.spanByteAndMemory, out _, out _); + value.Operate(ref input, ref output, out _); return true; } else @@ -57,10 +57,10 @@ public bool InitialUpdater(ref byte[] key, ref ObjectInput input, ref IGarnetObj var customObjectCommand = GetCustomObjectCommand(ref input, type); value = functionsState.GetCustomObjectFactory((byte)type).Create((byte)type); - (IMemoryOwner Memory, int Length) outp = (output.spanByteAndMemory.Memory, 0); + (IMemoryOwner Memory, int Length) outp = (output.SpanByteAndMemory.Memory, 0); var result = customObjectCommand.InitialUpdater(key, ref input, value, ref outp, ref rmwInfo); - output.spanByteAndMemory.Memory = outp.Memory; - output.spanByteAndMemory.Length = outp.Length; + output.SpanByteAndMemory.Memory = outp.Memory; + output.SpanByteAndMemory.Length = outp.Length; return result; } } @@ -81,7 +81,7 @@ public void PostInitialUpdater(ref byte[] key, ref ObjectInput input, ref IGarne /// public bool InPlaceUpdater(ref byte[] key, ref ObjectInput input, ref IGarnetObject value, ref GarnetObjectStoreOutput output, ref RMWInfo rmwInfo, ref RecordInfo recordInfo) { - if (InPlaceUpdaterWorker(ref key, ref input, ref value, ref output, ref rmwInfo, out long sizeChange)) + if (InPlaceUpdaterWorker(ref key, ref input, ref value, ref output, ref rmwInfo, out var sizeChange)) { if (!rmwInfo.RecordInfo.Modified) functionsState.watchVersionMap.IncrementVersion(rmwInfo.KeyHash); @@ -133,17 +133,19 @@ bool InPlaceUpdaterWorker(ref byte[] key, ref ObjectInput input, ref IGarnetObje if (value.Expiration > 0) { value.Expiration = 0; - CopyDefaultResp(CmdStrings.RESP_RETURN_VAL_1, ref output.spanByteAndMemory); + CopyDefaultResp(CmdStrings.RESP_RETURN_VAL_1, ref output.SpanByteAndMemory); } else - CopyDefaultResp(CmdStrings.RESP_RETURN_VAL_0, ref output.spanByteAndMemory); + CopyDefaultResp(CmdStrings.RESP_RETURN_VAL_0, ref output.SpanByteAndMemory); return true; default: if ((byte)input.header.type < CustomCommandManager.CustomTypeIdStartOffset) { - var operateSuccessful = value.Operate(ref input, ref output.spanByteAndMemory, out sizeChange, - out var removeKey); - if (removeKey) + var operateSuccessful = value.Operate(ref input, ref output, out sizeChange); + if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) + return true; + + if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.RemoveKey)) { rmwInfo.Action = RMWAction.ExpireAndStop; return false; @@ -153,14 +155,17 @@ bool InPlaceUpdaterWorker(ref byte[] key, ref ObjectInput input, ref IGarnetObje } else { - if (IncorrectObjectType(ref input, value, ref output.spanByteAndMemory)) + if (IncorrectObjectType(ref input, value, ref output.SpanByteAndMemory)) + { + output.OutputFlags |= ObjectStoreOutputFlags.WrongType; return true; + } - (IMemoryOwner Memory, int Length) outp = (output.spanByteAndMemory.Memory, 0); + (IMemoryOwner Memory, int Length) outp = (output.SpanByteAndMemory.Memory, 0); var customObjectCommand = GetCustomObjectCommand(ref input, input.header.type); var result = customObjectCommand.Updater(key, ref input, value, ref outp, ref rmwInfo); - output.spanByteAndMemory.Memory = outp.Memory; - output.spanByteAndMemory.Length = outp.Length; + output.SpanByteAndMemory.Memory = outp.Memory; + output.SpanByteAndMemory.Length = outp.Length; return result; //return customObjectCommand.InPlaceUpdateWorker(key, ref input, value, ref output.spanByteAndMemory, ref rmwInfo); } @@ -225,16 +230,19 @@ public bool PostCopyUpdater(ref byte[] key, ref ObjectInput input, ref IGarnetOb if (value.Expiration > 0) { value.Expiration = 0; - CopyDefaultResp(CmdStrings.RESP_RETURN_VAL_1, ref output.spanByteAndMemory); + CopyDefaultResp(CmdStrings.RESP_RETURN_VAL_1, ref output.SpanByteAndMemory); } else - CopyDefaultResp(CmdStrings.RESP_RETURN_VAL_0, ref output.spanByteAndMemory); + CopyDefaultResp(CmdStrings.RESP_RETURN_VAL_0, ref output.SpanByteAndMemory); break; default: if ((byte)input.header.type < CustomCommandManager.CustomTypeIdStartOffset) { - value.Operate(ref input, ref output.spanByteAndMemory, out _, out var removeKey); - if (removeKey) + value.Operate(ref input, ref output, out _); + if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) + return true; + + if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.RemoveKey)) { rmwInfo.Action = RMWAction.ExpireAndStop; return false; @@ -245,14 +253,17 @@ public bool PostCopyUpdater(ref byte[] key, ref ObjectInput input, ref IGarnetOb { // TODO: Update to invoke CopyUpdater of custom object command without creating a new object // using Clone. Currently, expire and persist commands are performed on the new copy of the object. - if (IncorrectObjectType(ref input, value, ref output.spanByteAndMemory)) + if (IncorrectObjectType(ref input, value, ref output.SpanByteAndMemory)) + { + output.OutputFlags |= ObjectStoreOutputFlags.WrongType; return true; + } - (IMemoryOwner Memory, int Length) outp = (output.spanByteAndMemory.Memory, 0); + (IMemoryOwner Memory, int Length) outp = (output.SpanByteAndMemory.Memory, 0); var customObjectCommand = GetCustomObjectCommand(ref input, input.header.type); var result = customObjectCommand.Updater(key, ref input, value, ref outp, ref rmwInfo); - output.spanByteAndMemory.Memory = outp.Memory; - output.spanByteAndMemory.Length = outp.Length; + output.SpanByteAndMemory.Memory = outp.Memory; + output.SpanByteAndMemory.Length = outp.Length; return result; } } diff --git a/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs b/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs index fe03284f59..3f10f18ec6 100644 --- a/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs +++ b/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs @@ -29,39 +29,48 @@ public bool SingleReader(ref byte[] key, ref ObjectInput input, ref IGarnetObjec { case GarnetObjectType.Ttl: var ttlValue = ConvertUtils.SecondsFromDiffUtcNowTicks(value.Expiration > 0 ? value.Expiration : -1); - CopyRespNumber(ttlValue, ref dst.spanByteAndMemory); + CopyRespNumber(ttlValue, ref dst.SpanByteAndMemory); return true; case GarnetObjectType.PTtl: ttlValue = ConvertUtils.MillisecondsFromDiffUtcNowTicks(value.Expiration > 0 ? value.Expiration : -1); - CopyRespNumber(ttlValue, ref dst.spanByteAndMemory); + CopyRespNumber(ttlValue, ref dst.SpanByteAndMemory); return true; case GarnetObjectType.ExpireTime: var expireTime = ConvertUtils.UnixTimeInSecondsFromTicks(value.Expiration > 0 ? value.Expiration : -1); - CopyRespNumber(expireTime, ref dst.spanByteAndMemory); + CopyRespNumber(expireTime, ref dst.SpanByteAndMemory); return true; case GarnetObjectType.PExpireTime: expireTime = ConvertUtils.UnixTimeInMillisecondsFromTicks(value.Expiration > 0 ? value.Expiration : -1); - CopyRespNumber(expireTime, ref dst.spanByteAndMemory); + CopyRespNumber(expireTime, ref dst.SpanByteAndMemory); return true; default: if ((byte)input.header.type < CustomCommandManager.CustomTypeIdStartOffset) - return value.Operate(ref input, ref dst.spanByteAndMemory, out _, out _); + { + var opResult = value.Operate(ref input, ref dst, out _); + if (dst.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) + return true; - if (IncorrectObjectType(ref input, value, ref dst.spanByteAndMemory)) + return opResult; + } + + if (IncorrectObjectType(ref input, value, ref dst.SpanByteAndMemory)) + { + dst.OutputFlags |= ObjectStoreOutputFlags.WrongType; return true; + } - (IMemoryOwner Memory, int Length) outp = (dst.spanByteAndMemory.Memory, 0); + (IMemoryOwner Memory, int Length) outp = (dst.SpanByteAndMemory.Memory, 0); var customObjectCommand = GetCustomObjectCommand(ref input, input.header.type); var result = customObjectCommand.Reader(key, ref input, value, ref outp, ref readInfo); - dst.spanByteAndMemory.Memory = outp.Memory; - dst.spanByteAndMemory.Length = outp.Length; + dst.SpanByteAndMemory.Memory = outp.Memory; + dst.SpanByteAndMemory.Length = outp.Length; return result; } } - dst.garnetObject = value; + dst.GarnetObject = value; return true; } diff --git a/libs/server/Storage/Session/MainStore/MainStoreOps.cs b/libs/server/Storage/Session/MainStore/MainStoreOps.cs index a1ee4e6339..e8712e91ff 100644 --- a/libs/server/Storage/Session/MainStore/MainStoreOps.cs +++ b/libs/server/Storage/Session/MainStore/MainStoreOps.cs @@ -266,7 +266,7 @@ public unsafe GarnetStatus TTL(ref SpanByte key, Store var objInput = new ObjectInput(header); var keyBA = key.ToByteArray(); - var objO = new GarnetObjectStoreOutput { spanByteAndMemory = output }; + var objO = new GarnetObjectStoreOutput { SpanByteAndMemory = output }; var status = objectContext.Read(ref keyBA, ref objInput, ref objO); if (status.IsPending) @@ -274,7 +274,7 @@ public unsafe GarnetStatus TTL(ref SpanByte key, Store if (status.Found) { - output = objO.spanByteAndMemory; + output = objO.SpanByteAndMemory; return GarnetStatus.OK; } } @@ -320,7 +320,7 @@ public unsafe GarnetStatus EXPIRETIME(ref SpanByte key var input = new ObjectInput(header); var keyBA = key.ToByteArray(); - var objO = new GarnetObjectStoreOutput { spanByteAndMemory = output }; + var objO = new GarnetObjectStoreOutput { SpanByteAndMemory = output }; var status = objectContext.Read(ref keyBA, ref input, ref objO); if (status.IsPending) @@ -328,7 +328,7 @@ public unsafe GarnetStatus EXPIRETIME(ref SpanByte key if (status.Found) { - output = objO.spanByteAndMemory; + output = objO.SpanByteAndMemory; return GarnetStatus.OK; } } @@ -726,7 +726,7 @@ private unsafe GarnetStatus RENAME(ArgSlice oldKeySlice, ArgSlice newKeySlice, S if (status == GarnetStatus.OK) { - var valObj = value.garnetObject; + var valObj = value.GarnetObject; byte[] newKeyArray = newKeySlice.ToArray(); returnStatus = GarnetStatus.OK; @@ -868,7 +868,7 @@ public unsafe GarnetStatus EXPIRE(ArgSlice key, ref Ra var objInput = new ObjectInput(header, ref input.parseState, arg1: (int)input.arg1, arg2: expiryAt ? 1 : 0); // Retry on object store - var objOutput = new GarnetObjectStoreOutput { spanByteAndMemory = output }; + var objOutput = new GarnetObjectStoreOutput { SpanByteAndMemory = output }; var keyBytes = key.ToArray(); var status = objectStoreContext.RMW(ref keyBytes, ref objInput, ref objOutput); @@ -876,7 +876,7 @@ public unsafe GarnetStatus EXPIRE(ArgSlice key, ref Ra CompletePendingForObjectStoreSession(ref status, ref objOutput, ref objectStoreContext); if (status.Found) found = true; - output = objOutput.spanByteAndMemory; + output = objOutput.SpanByteAndMemory; } Debug.Assert(output.IsSpanByte); @@ -990,7 +990,7 @@ public unsafe GarnetStatus EXPIRE(ArgSlice key, long e var objInput = new ObjectInput(header, ref parseState, arg1: (byte)expireOption, arg2: expiryAt ? 1 : 0); // Retry on object store - var objOutput = new GarnetObjectStoreOutput { spanByteAndMemory = output }; + var objOutput = new GarnetObjectStoreOutput { SpanByteAndMemory = output }; var keyBytes = key.ToArray(); var status = objectStoreContext.RMW(ref keyBytes, ref objInput, ref objOutput); @@ -998,7 +998,7 @@ public unsafe GarnetStatus EXPIRE(ArgSlice key, long e CompletePendingForObjectStoreSession(ref status, ref objOutput, ref objectStoreContext); if (status.Found) found = true; - output = objOutput.spanByteAndMemory; + output = objOutput.SpanByteAndMemory; } scratchBufferManager.RewindScratchBuffer(ref expirySlice); @@ -1039,7 +1039,7 @@ public unsafe GarnetStatus PERSIST(ArgSlice key, Store var header = new RespInputHeader(GarnetObjectType.Persist); var objInput = new ObjectInput(header); - var objO = new GarnetObjectStoreOutput { spanByteAndMemory = o }; + var objO = new GarnetObjectStoreOutput { SpanByteAndMemory = o }; var _key = key.ToArray(); var _status = objectStoreContext.RMW(ref _key, ref objInput, ref objO); @@ -1155,19 +1155,19 @@ public GarnetStatus GetKeyType(ArgSlice key, out strin status = GET(key.ToArray(), out GarnetObjectStoreOutput output, ref objectContext); if (status == GarnetStatus.OK) { - if ((output.garnetObject as SortedSetObject) != null) + if ((output.GarnetObject as SortedSetObject) != null) { keyType = "zset"; } - else if ((output.garnetObject as ListObject) != null) + else if ((output.GarnetObject as ListObject) != null) { keyType = "list"; } - else if ((output.garnetObject as SetObject) != null) + else if ((output.GarnetObject as SetObject) != null) { keyType = "set"; } - else if ((output.garnetObject as HashObject) != null) + else if ((output.GarnetObject as HashObject) != null) { keyType = "hash"; } @@ -1197,7 +1197,7 @@ public GarnetStatus MemoryUsageForKey(ArgSlice key, ou { memoryUsage = RecordInfo.GetLength() + (2 * IntPtr.Size) + // Log record length Utility.RoundUp(key.SpanByte.Length, IntPtr.Size) + MemoryUtils.ByteArrayOverhead + // Key allocation in heap with overhead - objectValue.garnetObject.Size; // Value allocation in heap + objectValue.GarnetObject.Size; // Value allocation in heap } } else diff --git a/libs/server/Storage/Session/ObjectStore/AdvancedOps.cs b/libs/server/Storage/Session/ObjectStore/AdvancedOps.cs index d7a7cb4d65..123334490c 100644 --- a/libs/server/Storage/Session/ObjectStore/AdvancedOps.cs +++ b/libs/server/Storage/Session/ObjectStore/AdvancedOps.cs @@ -21,7 +21,7 @@ public GarnetStatus RMW_ObjectStore(ref byte[] key, ref ObjectIn if (status.Found) { - if (output.spanByteAndMemory.Length == 0) + if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) return GarnetStatus.WRONGTYPE; return GarnetStatus.OK; @@ -40,7 +40,7 @@ public GarnetStatus Read_ObjectStore(ref byte[] key, ref ObjectI if (status.Found) { - if (output.spanByteAndMemory.Length == 0) + if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) return GarnetStatus.WRONGTYPE; return GarnetStatus.OK; diff --git a/libs/server/Storage/Session/ObjectStore/Common.cs b/libs/server/Storage/Session/ObjectStore/Common.cs index ab00fa79f8..3ca927b497 100644 --- a/libs/server/Storage/Session/ObjectStore/Common.cs +++ b/libs/server/Storage/Session/ObjectStore/Common.cs @@ -26,7 +26,7 @@ unsafe GarnetStatus RMWObjectStoreOperation(byte[] key, ref Obje output = new(); var objStoreOutput = new GarnetObjectStoreOutput { - spanByteAndMemory = + SpanByteAndMemory = new(SpanByte.FromPinnedPointer((byte*)Unsafe.AsPointer(ref output), ObjectOutputHeader.Size)) }; @@ -198,7 +198,7 @@ public unsafe GarnetStatus ObjectScan(GarnetObjectType objectTyp break; } - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var status = ReadObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); scratchBufferManager.RewindScratchBuffer(ref paramsSlice); @@ -227,8 +227,8 @@ unsafe ArgSlice[] ProcessRespArrayOutput(GarnetObjectStoreOutput outputFooter, o byte* element = null; int len = 0; - var outputSpan = outputFooter.spanByteAndMemory.IsSpanByte ? - outputFooter.spanByteAndMemory.SpanByte.AsReadOnlySpan() : outputFooter.spanByteAndMemory.AsMemoryReadOnlySpan(); + var outputSpan = outputFooter.SpanByteAndMemory.IsSpanByte ? + outputFooter.SpanByteAndMemory.SpanByte.AsReadOnlySpan() : outputFooter.SpanByteAndMemory.AsMemoryReadOnlySpan(); try { @@ -289,8 +289,8 @@ unsafe ArgSlice[] ProcessRespArrayOutput(GarnetObjectStoreOutput outputFooter, o } finally { - if (!outputFooter.spanByteAndMemory.IsSpanByte) - outputFooter.spanByteAndMemory.Memory.Dispose(); + if (!outputFooter.SpanByteAndMemory.IsSpanByte) + outputFooter.SpanByteAndMemory.Memory.Dispose(); } return elements; @@ -310,8 +310,8 @@ unsafe int[] ProcessRespIntegerArrayOutput(GarnetObjectStoreOutput outputFooter, // For reading the elements in the outputFooter byte* element = null; - var outputSpan = outputFooter.spanByteAndMemory.IsSpanByte ? - outputFooter.spanByteAndMemory.SpanByte.AsReadOnlySpan() : outputFooter.spanByteAndMemory.AsMemoryReadOnlySpan(); + var outputSpan = outputFooter.SpanByteAndMemory.IsSpanByte ? + outputFooter.SpanByteAndMemory.SpanByte.AsReadOnlySpan() : outputFooter.SpanByteAndMemory.AsMemoryReadOnlySpan(); try { @@ -345,8 +345,8 @@ unsafe int[] ProcessRespIntegerArrayOutput(GarnetObjectStoreOutput outputFooter, } finally { - if (!outputFooter.spanByteAndMemory.IsSpanByte) - outputFooter.spanByteAndMemory.Memory.Dispose(); + if (!outputFooter.SpanByteAndMemory.IsSpanByte) + outputFooter.SpanByteAndMemory.Memory.Dispose(); } return elements; @@ -361,8 +361,8 @@ unsafe int[] ProcessRespIntegerArrayOutput(GarnetObjectStoreOutput outputFooter, error = default; byte* element = null; var len = 0; - var outputSpan = outputFooter.spanByteAndMemory.IsSpanByte ? - outputFooter.spanByteAndMemory.SpanByte.AsReadOnlySpan() : outputFooter.spanByteAndMemory.AsMemoryReadOnlySpan(); + var outputSpan = outputFooter.SpanByteAndMemory.IsSpanByte ? + outputFooter.SpanByteAndMemory.SpanByte.AsReadOnlySpan() : outputFooter.SpanByteAndMemory.AsMemoryReadOnlySpan(); try { @@ -402,8 +402,8 @@ unsafe int[] ProcessRespIntegerArrayOutput(GarnetObjectStoreOutput outputFooter, } finally { - if (!outputFooter.spanByteAndMemory.IsSpanByte) - outputFooter.spanByteAndMemory.Memory.Dispose(); + if (!outputFooter.SpanByteAndMemory.IsSpanByte) + outputFooter.SpanByteAndMemory.Memory.Dispose(); } return result; @@ -420,8 +420,8 @@ unsafe ArgSlice ProcessRespSingleTokenOutput(GarnetObjectStoreOutput outputFoote var len = 0; ArgSlice result; - var outputSpan = outputFooter.spanByteAndMemory.IsSpanByte ? - outputFooter.spanByteAndMemory.SpanByte.AsReadOnlySpan() : outputFooter.spanByteAndMemory.AsMemoryReadOnlySpan(); + var outputSpan = outputFooter.SpanByteAndMemory.IsSpanByte ? + outputFooter.SpanByteAndMemory.SpanByte.AsReadOnlySpan() : outputFooter.SpanByteAndMemory.AsMemoryReadOnlySpan(); try { fixed (byte* outputPtr = outputSpan) @@ -436,8 +436,8 @@ unsafe ArgSlice ProcessRespSingleTokenOutput(GarnetObjectStoreOutput outputFoote } finally { - if (!outputFooter.spanByteAndMemory.IsSpanByte) - outputFooter.spanByteAndMemory.Memory.Dispose(); + if (!outputFooter.SpanByteAndMemory.IsSpanByte) + outputFooter.SpanByteAndMemory.Memory.Dispose(); } return result; @@ -451,8 +451,8 @@ unsafe ArgSlice ProcessRespSingleTokenOutput(GarnetObjectStoreOutput outputFoote /// integer unsafe bool TryProcessRespSimple64IntOutput(GarnetObjectStoreOutput outputFooter, out long value) { - var outputSpan = outputFooter.spanByteAndMemory.IsSpanByte ? - outputFooter.spanByteAndMemory.SpanByte.AsReadOnlySpan() : outputFooter.spanByteAndMemory.AsMemoryReadOnlySpan(); + var outputSpan = outputFooter.SpanByteAndMemory.IsSpanByte ? + outputFooter.SpanByteAndMemory.SpanByte.AsReadOnlySpan() : outputFooter.SpanByteAndMemory.AsMemoryReadOnlySpan(); try { fixed (byte* outputPtr = outputSpan) @@ -465,8 +465,8 @@ unsafe bool TryProcessRespSimple64IntOutput(GarnetObjectStoreOutput outputFooter } finally { - if (!outputFooter.spanByteAndMemory.IsSpanByte) - outputFooter.spanByteAndMemory.Memory.Dispose(); + if (!outputFooter.SpanByteAndMemory.IsSpanByte) + outputFooter.SpanByteAndMemory.Memory.Dispose(); } return true; @@ -490,7 +490,7 @@ unsafe GarnetStatus ReadObjectStoreOperation(byte[] key, ArgSlic ref var _input = ref Unsafe.AsRef(input.ptr); output = new(); - var _output = new GarnetObjectStoreOutput { spanByteAndMemory = new(SpanByte.FromPinnedPointer((byte*)Unsafe.AsPointer(ref output), ObjectOutputHeader.Size)) }; + var _output = new GarnetObjectStoreOutput { SpanByteAndMemory = new(SpanByte.FromPinnedPointer((byte*)Unsafe.AsPointer(ref output), ObjectOutputHeader.Size)) }; // Perform Read on object store var status = objectStoreContext.Read(ref key, ref _input, ref _output); @@ -498,9 +498,10 @@ unsafe GarnetStatus ReadObjectStoreOperation(byte[] key, ArgSlic if (status.IsPending) CompletePendingForObjectStoreSession(ref status, ref _output, ref objectStoreContext); - if (_output.spanByteAndMemory.Length == 0) + if (_output.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) return GarnetStatus.WRONGTYPE; - Debug.Assert(_output.spanByteAndMemory.IsSpanByte); + + Debug.Assert(_output.SpanByteAndMemory.IsSpanByte); if (status.Found && (!status.Record.Created && !status.Record.CopyUpdated && !status.Record.InPlaceUpdated)) return GarnetStatus.OK; @@ -524,7 +525,7 @@ unsafe GarnetStatus ReadObjectStoreOperation(byte[] key, ref Obj ThrowObjectStoreUninitializedException(); output = new(); - var _output = new GarnetObjectStoreOutput { spanByteAndMemory = new(SpanByte.FromPinnedPointer((byte*)Unsafe.AsPointer(ref output), ObjectOutputHeader.Size)) }; + var _output = new GarnetObjectStoreOutput { SpanByteAndMemory = new(SpanByte.FromPinnedPointer((byte*)Unsafe.AsPointer(ref output), ObjectOutputHeader.Size)) }; // Perform Read on object store var status = objectStoreContext.Read(ref key, ref input, ref _output); @@ -532,9 +533,10 @@ unsafe GarnetStatus ReadObjectStoreOperation(byte[] key, ref Obj if (status.IsPending) CompletePendingForObjectStoreSession(ref status, ref _output, ref objectStoreContext); - if (_output.spanByteAndMemory.Length == 0) + if (_output.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) return GarnetStatus.WRONGTYPE; - Debug.Assert(_output.spanByteAndMemory.IsSpanByte); + + Debug.Assert(_output.SpanByteAndMemory.IsSpanByte); if (status.Found && (!status.Record.Created && !status.Record.CopyUpdated && !status.Record.InPlaceUpdated)) return GarnetStatus.OK; @@ -577,7 +579,7 @@ private GarnetStatus CompletePendingAndGetGarnetStatus(Status st if (status.NotFound && !status.Record.Created) return GarnetStatus.NOTFOUND; - if (status.Found && outputFooter.spanByteAndMemory.Length == 0) + if (status.Found && outputFooter.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) return GarnetStatus.WRONGTYPE; return GarnetStatus.OK; diff --git a/libs/server/Storage/Session/ObjectStore/HashOps.cs b/libs/server/Storage/Session/ObjectStore/HashOps.cs index cc59b7acbd..a39b270cfb 100644 --- a/libs/server/Storage/Session/ObjectStore/HashOps.cs +++ b/libs/server/Storage/Session/ObjectStore/HashOps.cs @@ -158,7 +158,7 @@ public unsafe GarnetStatus HashGet(ArgSlice key, ArgSlice field, var header = new RespInputHeader(GarnetObjectType.Hash) { HashOp = HashOperation.HGET }; var input = new ObjectInput(header, ref parseState); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var status = ReadObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); @@ -193,7 +193,7 @@ public unsafe GarnetStatus HashGetMultiple(ArgSlice key, ArgSlic var header = new RespInputHeader(GarnetObjectType.Hash) { HashOp = HashOperation.HMGET }; var input = new ObjectInput(header, ref parseState); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var status = ReadObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); @@ -225,7 +225,7 @@ public unsafe GarnetStatus HashGetAll(ArgSlice key, out ArgSlice var inputArg = 2; // Default RESP protocol version var input = new ObjectInput(header, inputArg); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var status = ReadObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); @@ -317,7 +317,7 @@ public unsafe GarnetStatus HashRandomField(ArgSlice key, out Arg var header = new RespInputHeader(GarnetObjectType.Hash) { HashOp = HashOperation.HRANDFIELD }; var input = new ObjectInput(header, 1 << 2, seed); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var status = ReadObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); @@ -356,7 +356,7 @@ public unsafe GarnetStatus HashRandomField(ArgSlice key, int cou var inputArg = (((count << 1) | 1) << 1) | (withValues ? 1 : 0); var input = new ObjectInput(header, inputArg, seed); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var status = ReadObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); fields = default; diff --git a/libs/server/Storage/Session/ObjectStore/ListOps.cs b/libs/server/Storage/Session/ObjectStore/ListOps.cs index 772c737095..12e7557ae6 100644 --- a/libs/server/Storage/Session/ObjectStore/ListOps.cs +++ b/libs/server/Storage/Session/ObjectStore/ListOps.cs @@ -116,7 +116,7 @@ public unsafe GarnetStatus ListPop(ArgSlice key, int count, List var header = new RespInputHeader(GarnetObjectType.List) { ListOp = lop }; var input = new ObjectInput(header, count); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var status = RMWObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); @@ -237,7 +237,7 @@ public GarnetStatus ListMove(ArgSlice sourceKey, ArgSlice destinationKey, Operat } else if (statusOp == GarnetStatus.OK) { - if (sourceList.garnetObject is not ListObject srcListObject) + if (sourceList.GarnetObject is not ListObject srcListObject) return GarnetStatus.WRONGTYPE; if (srcListObject.LnkList.Count == 0) @@ -252,10 +252,10 @@ public GarnetStatus ListMove(ArgSlice sourceKey, ArgSlice destinationKey, Operat if (statusOp == GarnetStatus.NOTFOUND) { - destinationList.garnetObject = new ListObject(); + destinationList.GarnetObject = new ListObject(); } - if (destinationList.garnetObject is not ListObject listObject) + if (destinationList.GarnetObject is not ListObject listObject) return GarnetStatus.WRONGTYPE; dstListObject = listObject; diff --git a/libs/server/Storage/Session/ObjectStore/SetOps.cs b/libs/server/Storage/Session/ObjectStore/SetOps.cs index a4de11f79b..d0babb27a5 100644 --- a/libs/server/Storage/Session/ObjectStore/SetOps.cs +++ b/libs/server/Storage/Session/ObjectStore/SetOps.cs @@ -187,7 +187,7 @@ internal unsafe GarnetStatus SetMembers(ArgSlice key, out ArgSli var header = new RespInputHeader(GarnetObjectType.Set) { SetOp = SetOperation.SMEMBERS }; var input = new ObjectInput(header); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var status = RMWObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); @@ -237,7 +237,7 @@ internal unsafe GarnetStatus SetPop(ArgSlice key, int count, out var header = new RespInputHeader(GarnetObjectType.Set) { SetOp = SetOperation.SPOP }; var input = new ObjectInput(header, count); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var status = RMWObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); @@ -284,7 +284,7 @@ internal unsafe GarnetStatus SetMove(ArgSlice sourceKey, ArgSlice destinationKey if (srcGetStatus == GarnetStatus.NOTFOUND) return GarnetStatus.NOTFOUND; - if (srcObject.garnetObject is not SetObject srcSetObject) + if (srcObject.GarnetObject is not SetObject srcSetObject) return GarnetStatus.WRONGTYPE; // If the keys are the same, no operation is performed. @@ -297,7 +297,7 @@ internal unsafe GarnetStatus SetMove(ArgSlice sourceKey, ArgSlice destinationKey SetObject dstSetObject; if (dstGetStatus == GarnetStatus.OK) { - if (dstObject.garnetObject is not SetObject tmpDstSetObject) + if (dstObject.GarnetObject is not SetObject tmpDstSetObject) return GarnetStatus.WRONGTYPE; dstSetObject = tmpDstSetObject; @@ -466,7 +466,7 @@ private GarnetStatus SetIntersect(ReadOnlySpan keys, r var status = GET(keys[0].ToArray(), out var first, ref objectContext); if (status == GarnetStatus.OK) { - if (first.garnetObject is not SetObject firstObject) + if (first.GarnetObject is not SetObject firstObject) { output = default; return GarnetStatus.WRONGTYPE; @@ -492,7 +492,7 @@ private GarnetStatus SetIntersect(ReadOnlySpan keys, r status = GET(keys[i].ToArray(), out var next, ref objectContext); if (status == GarnetStatus.OK) { - if (next.garnetObject is not SetObject nextObject) + if (next.GarnetObject is not SetObject nextObject) { output = default; return GarnetStatus.WRONGTYPE; @@ -629,7 +629,7 @@ private GarnetStatus SetUnion(ArgSlice[] keys, ref TObjectContex { if (GET(item.ToArray(), out var currObject, ref objectContext) == GarnetStatus.OK) { - if (currObject.garnetObject is not SetObject setObject) + if (currObject.GarnetObject is not SetObject setObject) { output = default; return GarnetStatus.WRONGTYPE; @@ -736,7 +736,7 @@ public unsafe GarnetStatus SetIsMember(ArgSlice key, ArgSlice[] SetOp = SetOperation.SMISMEMBER, }, ref parseState); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var status = ReadObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectContext, ref outputFooter); if (status == GarnetStatus.OK) @@ -892,7 +892,7 @@ private GarnetStatus SetDiff(ArgSlice[] keys, ref TObjectContext var status = GET(keys[0].ToArray(), out var first, ref objectContext); if (status == GarnetStatus.OK) { - if (first.garnetObject is not SetObject firstObject) + if (first.GarnetObject is not SetObject firstObject) { output = default; return GarnetStatus.WRONGTYPE; @@ -911,7 +911,7 @@ private GarnetStatus SetDiff(ArgSlice[] keys, ref TObjectContext status = GET(keys[i].ToArray(), out var next, ref objectContext); if (status == GarnetStatus.OK) { - if (next.garnetObject is not SetObject nextObject) + if (next.GarnetObject is not SetObject nextObject) { output = default; return GarnetStatus.WRONGTYPE; diff --git a/libs/server/Storage/Session/ObjectStore/SortedSetGeoOps.cs b/libs/server/Storage/Session/ObjectStore/SortedSetGeoOps.cs index 71b01fe6cb..f5be4d08da 100644 --- a/libs/server/Storage/Session/ObjectStore/SortedSetGeoOps.cs +++ b/libs/server/Storage/Session/ObjectStore/SortedSetGeoOps.cs @@ -79,9 +79,9 @@ public unsafe GarnetStatus GeoSearchStore(ArgSlice key, ArgSlice { var sourceKey = key.ToArray(); SpanByteAndMemory searchOutMem = default; - var searchOut = new GarnetObjectStoreOutput { spanByteAndMemory = searchOutMem }; + var searchOut = new GarnetObjectStoreOutput { SpanByteAndMemory = searchOutMem }; var status = GeoCommands(sourceKey, ref input, ref searchOut, ref objectStoreLockableContext); - searchOutMem = searchOut.spanByteAndMemory; + searchOutMem = searchOut.SpanByteAndMemory; if (status == GarnetStatus.WRONGTYPE) { @@ -139,7 +139,7 @@ public unsafe GarnetStatus GeoSearchStore(ArgSlice key, ArgSlice SortedSetOp = SortedSetOperation.ZADD, }, ref parseState); - var zAddOutput = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var zAddOutput = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; RMWObjectStoreOperationWithOutput(destinationKey, ref zAddInput, ref objectStoreLockableContext, ref zAddOutput); while (!RespWriteUtils.WriteInteger(foundItems, ref curr, end)) diff --git a/libs/server/Storage/Session/ObjectStore/SortedSetOps.cs b/libs/server/Storage/Session/ObjectStore/SortedSetOps.cs index 8ac9c4c3cf..b874f07976 100644 --- a/libs/server/Storage/Session/ObjectStore/SortedSetOps.cs +++ b/libs/server/Storage/Session/ObjectStore/SortedSetOps.cs @@ -41,7 +41,7 @@ public unsafe GarnetStatus SortedSetAdd(ArgSlice key, ArgSlice s var header = new RespInputHeader(GarnetObjectType.SortedSet) { SortedSetOp = SortedSetOperation.ZADD }; var input = new ObjectInput(header, ref parseState); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var keyBytes = key.ToArray(); var status = RMWObjectStoreOperationWithOutput(keyBytes, ref input, ref objectStoreContext, ref outputFooter); @@ -84,7 +84,7 @@ public unsafe GarnetStatus SortedSetAdd(ArgSlice key, (ArgSlice var header = new RespInputHeader(GarnetObjectType.SortedSet) { SortedSetOp = SortedSetOperation.ZADD }; var input = new ObjectInput(header, ref parseState); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var keyBytes = key.ToArray(); var status = RMWObjectStoreOperationWithOutput(keyBytes, ref input, ref objectStoreContext, ref outputFooter); @@ -249,7 +249,7 @@ public unsafe GarnetStatus SortedSetRemoveRangeByScore(ArgSlice var header = new RespInputHeader(GarnetObjectType.SortedSet) { SortedSetOp = SortedSetOperation.ZREMRANGEBYSCORE }; var input = new ObjectInput(header, ref parseState); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var status = RMWObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); @@ -310,7 +310,7 @@ public unsafe GarnetStatus SortedSetRemoveRangeByRank(ArgSlice k var header = new RespInputHeader(GarnetObjectType.SortedSet) { SortedSetOp = SortedSetOperation.ZREMRANGEBYRANK }; var input = new ObjectInput(header, ref parseState); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; status = RMWObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); @@ -347,7 +347,7 @@ public unsafe GarnetStatus SortedSetPop(ArgSlice key, int count, var header = new RespInputHeader(GarnetObjectType.SortedSet) { SortedSetOp = op }; var input = new ObjectInput(header, count); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var status = RMWObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); @@ -391,7 +391,7 @@ public unsafe GarnetStatus SortedSetIncrement(ArgSlice key, doub var header = new RespInputHeader(GarnetObjectType.SortedSet) { SortedSetOp = SortedSetOperation.ZINCRBY }; var input = new ObjectInput(header, ref parseState); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var status = RMWObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); @@ -521,7 +521,7 @@ public unsafe GarnetStatus SortedSetRange(ArgSlice key, ArgSlice var inputArg = 2; // Default RESP server protocol version var input = new ObjectInput(header, ref parseState, arg1: inputArg); - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; var status = ReadObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectContext, ref outputFooter); for (var i = arguments.Count - 1; i > 1; i--) @@ -664,7 +664,7 @@ public unsafe GarnetStatus SortedSetRank(ArgSlice key, ArgSlice const int outputContainerSize = 32; // 3 for HEADER + CRLF + 20 for ascii long var outputContainer = stackalloc byte[outputContainerSize]; - var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(outputContainer, outputContainerSize) }; + var outputFooter = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(outputContainer, outputContainerSize) }; var status = ReadObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); @@ -740,9 +740,9 @@ public unsafe GarnetStatus SortedSetRangeStore(ArgSlice dstKey, try { SpanByteAndMemory rangeOutputMem = default; - var rangeOutput = new GarnetObjectStoreOutput() { spanByteAndMemory = rangeOutputMem }; + var rangeOutput = new GarnetObjectStoreOutput() { SpanByteAndMemory = rangeOutputMem }; var status = SortedSetRange(srcKey.ToArray(), ref input, ref rangeOutput, ref objectStoreLockableContext); - rangeOutputMem = rangeOutput.spanByteAndMemory; + rangeOutputMem = rangeOutput.SpanByteAndMemory; if (status == GarnetStatus.WRONGTYPE) { @@ -790,7 +790,7 @@ public unsafe GarnetStatus SortedSetRangeStore(ArgSlice dstKey, SortedSetOp = SortedSetOperation.ZADD, }, ref parseState); - var zAddOutput = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(null) }; + var zAddOutput = new GarnetObjectStoreOutput { SpanByteAndMemory = new SpanByteAndMemory(null) }; RMWObjectStoreOperationWithOutput(destinationKey, ref zAddInput, ref objectStoreLockableContext, ref zAddOutput); itemBroker.HandleCollectionUpdate(destinationKey); } @@ -1105,7 +1105,7 @@ private GarnetStatus SortedSetUnion(ReadOnlySpan keys, var status = GET(keys[0].ToArray(), out var firstObj, ref objectContext); if (status == GarnetStatus.OK) { - if (firstObj.garnetObject is not SortedSetObject firstSortedSet) + if (firstObj.GarnetObject is not SortedSetObject firstSortedSet) { return GarnetStatus.WRONGTYPE; } @@ -1131,7 +1131,7 @@ private GarnetStatus SortedSetUnion(ReadOnlySpan keys, if (status != GarnetStatus.OK) continue; - if (nextObj.garnetObject is not SortedSetObject nextSortedSet) + if (nextObj.GarnetObject is not SortedSetObject nextSortedSet) { pairs = default; return GarnetStatus.WRONGTYPE; @@ -1169,7 +1169,7 @@ private GarnetStatus SortedSetDifference(ReadOnlySpan var statusOp = GET(keys[0].ToArray(), out var firstObj, ref objectContext); if (statusOp == GarnetStatus.OK) { - if (firstObj.garnetObject is not SortedSetObject firstSortedSet) + if (firstObj.GarnetObject is not SortedSetObject firstSortedSet) { return GarnetStatus.WRONGTYPE; } @@ -1187,7 +1187,7 @@ private GarnetStatus SortedSetDifference(ReadOnlySpan if (statusOp != GarnetStatus.OK) continue; - if (nextObj.garnetObject is not SortedSetObject nextSortedSet) + if (nextObj.GarnetObject is not SortedSetObject nextSortedSet) { pairs = default; return GarnetStatus.WRONGTYPE; @@ -1389,7 +1389,7 @@ private GarnetStatus SortedSetIntersection(ReadOnlySpan(ReadOnlySpan key, ref ObjectInput input, IG var valueArg = GetNextArg(ref input, ref offset).ToArray(); _ = ((MyDict)value).Set(keyArg, valueArg); - WriteSimpleString(ref output, "OK"); return true; } } diff --git a/playground/GarnetJSON/JsonCommands.cs b/playground/GarnetJSON/JsonCommands.cs index 6d2e709c0a..7691771af2 100644 --- a/playground/GarnetJSON/JsonCommands.cs +++ b/playground/GarnetJSON/JsonCommands.cs @@ -26,10 +26,10 @@ public override bool Updater(ReadOnlyMemory key, ref ObjectInput input, IG var path = CustomCommandUtils.GetNextArg(ref input, ref offset); var value = CustomCommandUtils.GetNextArg(ref input, ref offset); - if (((JsonObject)jsonObject).TrySet(Encoding.UTF8.GetString(path), Encoding.UTF8.GetString(value), logger)) - WriteSimpleString(ref output, "OK"); - else + if (!((JsonObject)jsonObject).TrySet(Encoding.UTF8.GetString(path), Encoding.UTF8.GetString(value), logger)) + { WriteError(ref output, "ERR Invalid input"); + } return true; } diff --git a/playground/NoOpModule/DummyObjectNoOpRMW.cs b/playground/NoOpModule/DummyObjectNoOpRMW.cs index 53e5f17c1a..8585d166d8 100644 --- a/playground/NoOpModule/DummyObjectNoOpRMW.cs +++ b/playground/NoOpModule/DummyObjectNoOpRMW.cs @@ -20,7 +20,6 @@ public override bool NeedInitialUpdate(ReadOnlyMemory key, ref ObjectInput public override bool Updater(ReadOnlyMemory key, ref ObjectInput input, IGarnetObject value, ref (IMemoryOwner, int) output, ref RMWInfo rmwInfo) { - WriteSimpleString(ref output, "OK"); return true; } } diff --git a/playground/NoOpModule/DummyObjectNoOpRead.cs b/playground/NoOpModule/DummyObjectNoOpRead.cs index 96139d7109..19f2c49663 100644 --- a/playground/NoOpModule/DummyObjectNoOpRead.cs +++ b/playground/NoOpModule/DummyObjectNoOpRead.cs @@ -16,7 +16,6 @@ public class DummyObjectNoOpRead : CustomObjectFunctions public override bool Reader(ReadOnlyMemory key, ref ObjectInput input, IGarnetObject value, ref (IMemoryOwner, int) output, ref ReadInfo readInfo) { - WriteNullBulkString(ref output); return true; } } diff --git a/test/BDNPerfTests/BDN_Benchmark_Config.json b/test/BDNPerfTests/BDN_Benchmark_Config.json index 44ed54865e..b3266f3b4b 100644 --- a/test/BDNPerfTests/BDN_Benchmark_Config.json +++ b/test/BDNPerfTests/BDN_Benchmark_Config.json @@ -261,28 +261,28 @@ "BDN.benchmark.Operations.ModuleOperations.*": { "expected_ModuleNoOpRawStringReadCommand_ACL": 0, "expected_ModuleNoOpRawStringRmwCommand_ACL": 0, - "expected_ModuleNoOpObjRmwCommand_ACL": 8800, - "expected_ModuleNoOpObjReadCommand_ACL": 5600, + "expected_ModuleNoOpObjRmwCommand_ACL": 3200, + "expected_ModuleNoOpObjReadCommand_ACL": 3200, "expected_ModuleNoOpProc_ACL": 0, "expected_ModuleNoOpTxn_ACL": 0, "expected_ModuleJsonGetCommand_ACL": 72800, - "expected_ModuleJsonSetCommand_ACL": 228800, + "expected_ModuleJsonSetCommand_ACL": 223200, "expected_ModuleNoOpRawStringReadCommand_AOF": 0, "expected_ModuleNoOpRawStringRmwCommand_AOF": 0, - "expected_ModuleNoOpObjRmwCommand_AOF": 8800, - "expected_ModuleNoOpObjReadCommand_AOF": 5600, + "expected_ModuleNoOpObjRmwCommand_AOF": 3200, + "expected_ModuleNoOpObjReadCommand_AOF": 3200, "expected_ModuleNoOpProc_AOF": 0, "expected_ModuleNoOpTxn_AOF": 0, "expected_ModuleJsonGetCommand_AOF": 72800, - "expected_ModuleJsonSetCommand_AOF": 228800, + "expected_ModuleJsonSetCommand_AOF": 223200, "expected_ModuleNoOpRawStringReadCommand_None": 0, "expected_ModuleNoOpRawStringRmwCommand_None": 0, - "expected_ModuleNoOpObjRmwCommand_None": 8800, - "expected_ModuleNoOpObjReadCommand_None": 5600, + "expected_ModuleNoOpObjRmwCommand_None": 3200, + "expected_ModuleNoOpObjReadCommand_None": 3200, "expected_ModuleNoOpProc_None": 0, "expected_ModuleNoOpTxn_None": 0, "expected_ModuleJsonGetCommand_None": 72800, - "expected_ModuleJsonSetCommand_None": 228800 + "expected_ModuleJsonSetCommand_None": 223200 }, "BDN.benchmark.Network.RawStringOperations.*": { "expected_Set_None": 0, diff --git a/test/Garnet.test/RespModuleTests.cs b/test/Garnet.test/RespModuleTests.cs index 9cfb898fc7..47a5075b53 100644 --- a/test/Garnet.test/RespModuleTests.cs +++ b/test/Garnet.test/RespModuleTests.cs @@ -343,7 +343,7 @@ public void TestNoOpModule(bool loadFromDll) ClassicAssert.AreEqual("OK", (string)retValue); retValue = db.Execute("NoOpModule.NOOPOBJREAD", objKey); - ClassicAssert.IsNull((string)retValue); + ClassicAssert.AreEqual("OK", (string)retValue); // Test transaction in no-op module retValue = db.Execute("NoOpModule.NOOPTXN");