From a78b12b5258d7fa1d5b1756b2ee08f366850c3e1 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Fri, 17 Jan 2025 18:45:57 -0700 Subject: [PATCH 1/9] Adding wrongType bool to GarnetObjectStoreOutput --- libs/server/Custom/CustomObjectBase.cs | 4 ++- libs/server/Objects/Hash/HashObject.cs | 4 ++- libs/server/Objects/List/ListObject.cs | 5 +++- libs/server/Objects/Set/SetObject.cs | 4 ++- .../Objects/SortedSet/SortedSetObject.cs | 5 +++- libs/server/Objects/Types/GarnetObjectBase.cs | 2 +- .../Objects/Types/GarnetObjectStoreOutput.cs | 5 ++++ libs/server/Objects/Types/IGarnetObject.cs | 3 ++- .../Functions/ObjectStore/RMWMethods.cs | 26 ++++++++++++++++--- .../Functions/ObjectStore/ReadMethods.cs | 14 +++++++++- .../Session/ObjectStore/AdvancedOps.cs | 4 +-- .../Storage/Session/ObjectStore/Common.cs | 6 ++--- 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 +- 18 files changed, 79 insertions(+), 32 deletions(-) diff --git a/libs/server/Custom/CustomObjectBase.cs b/libs/server/Custom/CustomObjectBase.cs index 29f9a6d75b..05a1d79f6e 100644 --- a/libs/server/Custom/CustomObjectBase.cs +++ b/libs/server/Custom/CustomObjectBase.cs @@ -68,10 +68,11 @@ 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 SpanByteAndMemory output, out long sizeChange, out bool removeKey, out bool wrongType) { sizeChange = 0; removeKey = false; + wrongType = false; switch (input.header.cmd) { @@ -93,6 +94,7 @@ public sealed override unsafe bool Operate(ref ObjectInput input, ref SpanByteAn if ((byte)input.header.type != this.type) { // Indicates an incorrect type of key + wrongType = true; output.Length = 0; return true; } diff --git a/libs/server/Objects/Hash/HashObject.cs b/libs/server/Objects/Hash/HashObject.cs index bfa3a8b410..369e330705 100644 --- a/libs/server/Objects/Hash/HashObject.cs +++ b/libs/server/Objects/Hash/HashObject.cs @@ -108,15 +108,17 @@ public override void Dispose() { } public override GarnetObjectBase Clone() => new HashObject(hash, 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 SpanByteAndMemory output, out long sizeChange, out bool removeKey, out bool wrongType) { removeKey = false; + wrongType = false; fixed (byte* _output = output.SpanByte.AsSpan()) { if (input.header.type != GarnetObjectType.Hash) { //Indicates when there is an incorrect type + wrongType = true; output.Length = 0; sizeChange = 0; return true; diff --git a/libs/server/Objects/List/ListObject.cs b/libs/server/Objects/List/ListObject.cs index b807548e23..989f3a2477 100644 --- a/libs/server/Objects/List/ListObject.cs +++ b/libs/server/Objects/List/ListObject.cs @@ -128,8 +128,10 @@ 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 SpanByteAndMemory output, out long sizeChange, out bool removeKey, out bool wrongType) { + wrongType = false; + fixed (byte* _output = output.SpanByte.AsSpan()) { removeKey = false; @@ -137,6 +139,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory if (input.header.type != GarnetObjectType.List) { // Indicates an incorrect type of key + wrongType = true; output.Length = 0; sizeChange = 0; return true; diff --git a/libs/server/Objects/Set/SetObject.cs b/libs/server/Objects/Set/SetObject.cs index 1de3662dc6..845b95688e 100644 --- a/libs/server/Objects/Set/SetObject.cs +++ b/libs/server/Objects/Set/SetObject.cs @@ -105,13 +105,15 @@ 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 SpanByteAndMemory output, out long sizeChange, out bool removeKey, out bool wrongType) { + wrongType = false; fixed (byte* _output = output.SpanByte.AsSpan()) { if (input.header.type != GarnetObjectType.Set) { // Indicates an incorrect type of key + wrongType = true; output.Length = 0; sizeChange = 0; removeKey = false; diff --git a/libs/server/Objects/SortedSet/SortedSetObject.cs b/libs/server/Objects/SortedSet/SortedSetObject.cs index ab6bf7d4e5..e0d16f959b 100644 --- a/libs/server/Objects/SortedSet/SortedSetObject.cs +++ b/libs/server/Objects/SortedSet/SortedSetObject.cs @@ -212,14 +212,17 @@ 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 SpanByteAndMemory output, out long sizeChange, out bool removeKey, out bool wrongType) { + wrongType = false; + fixed (byte* outputSpan = output.SpanByte.AsSpan()) { var header = input.header; if (header.type != GarnetObjectType.SortedSet) { // Indicates an incorrect type of key + wrongType = true; output.Length = 0; sizeChange = 0; removeKey = false; diff --git a/libs/server/Objects/Types/GarnetObjectBase.cs b/libs/server/Objects/Types/GarnetObjectBase.cs index f792b8ac4d..101c1a8abb 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 SpanByteAndMemory output, out long sizeChange, out bool removeKey, out bool wrongType); /// public abstract void Dispose(); diff --git a/libs/server/Objects/Types/GarnetObjectStoreOutput.cs b/libs/server/Objects/Types/GarnetObjectStoreOutput.cs index 410047daf8..08dad1be97 100644 --- a/libs/server/Objects/Types/GarnetObjectStoreOutput.cs +++ b/libs/server/Objects/Types/GarnetObjectStoreOutput.cs @@ -20,6 +20,11 @@ public struct GarnetObjectStoreOutput /// public IGarnetObject garnetObject; + /// + /// True if an operation was attempted on the wrong type of object + /// + public bool wrongType; + public void ConvertToHeap() { // Does not convert to heap when going pending, because we immediately complete pending operations for object store. diff --git a/libs/server/Objects/Types/IGarnetObject.cs b/libs/server/Objects/Types/IGarnetObject.cs index b56cb71785..f08019b490 100644 --- a/libs/server/Objects/Types/IGarnetObject.cs +++ b/libs/server/Objects/Types/IGarnetObject.cs @@ -35,8 +35,9 @@ public interface IGarnetObject : IDisposable /// /// /// + /// /// - bool Operate(ref ObjectInput input, ref SpanByteAndMemory output, out long sizeChange, out bool removeKey); + bool Operate(ref ObjectInput input, ref SpanByteAndMemory output, out long sizeChange, out bool removeKey, out bool wrongType); /// /// Serializer diff --git a/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs b/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs index b8732523a9..98083369ad 100644 --- a/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs +++ b/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs @@ -47,7 +47,11 @@ 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.spanByteAndMemory, out _, out _, out var wrongType); + if (wrongType) + { + output.wrongType = true; + } return true; } else @@ -142,7 +146,12 @@ bool InPlaceUpdaterWorker(ref byte[] key, ref ObjectInput input, ref IGarnetObje if ((byte)input.header.type < CustomCommandManager.CustomTypeIdStartOffset) { var operateSuccessful = value.Operate(ref input, ref output.spanByteAndMemory, out sizeChange, - out var removeKey); + out var removeKey, out var wrongType); + if (wrongType) + { + output.wrongType = true; + return true; + } if (removeKey) { rmwInfo.Action = RMWAction.ExpireAndStop; @@ -154,7 +163,10 @@ bool InPlaceUpdaterWorker(ref byte[] key, ref ObjectInput input, ref IGarnetObje else { if (IncorrectObjectType(ref input, value, ref output.spanByteAndMemory)) + { + output.wrongType = true; return true; + } (IMemoryOwner Memory, int Length) outp = (output.spanByteAndMemory.Memory, 0); var customObjectCommand = GetCustomObjectCommand(ref input, input.header.type); @@ -233,7 +245,12 @@ public bool PostCopyUpdater(ref byte[] key, ref ObjectInput input, ref IGarnetOb default: if ((byte)input.header.type < CustomCommandManager.CustomTypeIdStartOffset) { - value.Operate(ref input, ref output.spanByteAndMemory, out _, out var removeKey); + value.Operate(ref input, ref output.spanByteAndMemory, out _, out var removeKey, out var wrongType); + if (wrongType) + { + output.wrongType = true; + return true; + } if (removeKey) { rmwInfo.Action = RMWAction.ExpireAndStop; @@ -246,7 +263,10 @@ 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)) + { + output.wrongType = true; return true; + } (IMemoryOwner Memory, int Length) outp = (output.spanByteAndMemory.Memory, 0); var customObjectCommand = GetCustomObjectCommand(ref input, input.header.type); diff --git a/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs b/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs index fe03284f59..8792b661c1 100644 --- a/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs +++ b/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs @@ -47,10 +47,22 @@ public bool SingleReader(ref byte[] key, ref ObjectInput input, ref IGarnetObjec 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.spanByteAndMemory, out _, out _, + out var wrongType); + if (wrongType) + { + dst.wrongType = true; + return true; + } + return opResult; + } if (IncorrectObjectType(ref input, value, ref dst.spanByteAndMemory)) + { + dst.wrongType = true; return true; + } (IMemoryOwner Memory, int Length) outp = (dst.spanByteAndMemory.Memory, 0); var customObjectCommand = GetCustomObjectCommand(ref input, input.header.type); diff --git a/libs/server/Storage/Session/ObjectStore/AdvancedOps.cs b/libs/server/Storage/Session/ObjectStore/AdvancedOps.cs index d7a7cb4d65..509ea63510 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.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.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..4ede94e872 100644 --- a/libs/server/Storage/Session/ObjectStore/Common.cs +++ b/libs/server/Storage/Session/ObjectStore/Common.cs @@ -498,7 +498,7 @@ unsafe GarnetStatus ReadObjectStoreOperation(byte[] key, ArgSlic if (status.IsPending) CompletePendingForObjectStoreSession(ref status, ref _output, ref objectStoreContext); - if (_output.spanByteAndMemory.Length == 0) + if (_output.wrongType) return GarnetStatus.WRONGTYPE; Debug.Assert(_output.spanByteAndMemory.IsSpanByte); @@ -532,7 +532,7 @@ unsafe GarnetStatus ReadObjectStoreOperation(byte[] key, ref Obj if (status.IsPending) CompletePendingForObjectStoreSession(ref status, ref _output, ref objectStoreContext); - if (_output.spanByteAndMemory.Length == 0) + if (_output.wrongType) return GarnetStatus.WRONGTYPE; Debug.Assert(_output.spanByteAndMemory.IsSpanByte); @@ -577,7 +577,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.wrongType) return GarnetStatus.WRONGTYPE; return GarnetStatus.OK; diff --git a/main/GarnetServer/Extensions/MyDictSet.cs b/main/GarnetServer/Extensions/MyDictSet.cs index 471eddae56..4be36ca223 100644 --- a/main/GarnetServer/Extensions/MyDictSet.cs +++ b/main/GarnetServer/Extensions/MyDictSet.cs @@ -22,7 +22,6 @@ public override bool Updater(ReadOnlyMemory 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"); From b686aad329efa238efb62e9546ad44acaae58af3 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Tue, 21 Jan 2025 11:56:11 -0700 Subject: [PATCH 2/9] Fixing comments --- .../Server/Migration/MigrateSessionKeys.cs | 6 +- libs/server/AOF/AofProcessor.cs | 12 ++-- libs/server/Custom/CustomObjectBase.cs | 18 ++--- libs/server/Custom/CustomRespCommands.cs | 32 ++++----- libs/server/Objects/Hash/HashObject.cs | 57 +++++++--------- .../ItemBroker/CollectionItemBroker.cs | 4 +- libs/server/Objects/List/ListObject.cs | 43 ++++++------ libs/server/Objects/Set/SetObject.cs | 40 ++++++----- .../Objects/SortedSet/SortedSetObject.cs | 65 +++++++++--------- libs/server/Objects/Types/GarnetObjectBase.cs | 2 +- .../Objects/Types/GarnetObjectStoreOutput.cs | 33 +++++++-- libs/server/Objects/Types/IGarnetObject.cs | 5 +- libs/server/Resp/Objects/HashCommands.cs | 26 +++---- 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 +-- .../Functions/ObjectStore/PrivateMethods.cs | 4 +- .../Functions/ObjectStore/RMWMethods.cs | 67 ++++++++----------- .../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 +++++----- 29 files changed, 347 insertions(+), 356 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 05a1d79f6e..294ca09035 100644 --- a/libs/server/Custom/CustomObjectBase.cs +++ b/libs/server/Custom/CustomObjectBase.cs @@ -68,34 +68,30 @@ 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, out bool wrongType) + public sealed override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output) { - sizeChange = 0; - removeKey = false; - wrongType = 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 - wrongType = true; - 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 369e330705..9eef81f6fd 100644 --- a/libs/server/Objects/Hash/HashObject.cs +++ b/libs/server/Objects/Hash/HashObject.cs @@ -108,91 +108,86 @@ public override void Dispose() { } public override GarnetObjectBase Clone() => new HashObject(hash, Expiration, Size); /// - public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory output, out long sizeChange, out bool removeKey, out bool wrongType) + public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output) { - removeKey = false; - wrongType = false; - - 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 - wrongType = true; - output.Length = 0; - sizeChange = 0; + output.OutputFlags |= ObjectStoreOutputFlags.WrongType; + output.SpanByteAndMemory.Length = 0; return true; } - var previousSize = this.Size; 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.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.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: throw new GarnetException($"Unsupported operation {input.header.HashOp} in HashObject.Operate"); } - - 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 82a2158b07..8ff946fedd 100644 --- a/libs/server/Objects/ItemBroker/CollectionItemBroker.cs +++ b/libs/server/Objects/ItemBroker/CollectionItemBroker.cs @@ -462,12 +462,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 989f3a2477..3b17948139 100644 --- a/libs/server/Objects/List/ListObject.cs +++ b/libs/server/Objects/List/ListObject.cs @@ -128,20 +128,15 @@ 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, out bool wrongType) + public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output) { - wrongType = false; - - fixed (byte* _output = output.SpanByte.AsSpan()) + fixed (byte* outputSpan = output.SpanByteAndMemory.SpanByte.AsSpan()) { - removeKey = false; - if (input.header.type != GarnetObjectType.List) { // Indicates an incorrect type of key - wrongType = true; - output.Length = 0; - sizeChange = 0; + output.OutputFlags |= ObjectStoreOutputFlags.WrongType; + output.SpanByteAndMemory.Length = 0; return true; } @@ -150,51 +145,51 @@ 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: throw new GarnetException($"Unsupported operation {input.header.ListOp} in ListObject.Operate"); } - - 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 845b95688e..828a11005e 100644 --- a/libs/server/Objects/Set/SetObject.cs +++ b/libs/server/Objects/Set/SetObject.cs @@ -105,18 +105,15 @@ 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, out bool wrongType) + public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output) { - wrongType = false; - fixed (byte* _output = output.SpanByte.AsSpan()) + fixed (byte* outputSpan = output.SpanByteAndMemory.SpanByte.AsSpan()) { if (input.header.type != GarnetObjectType.Set) { // Indicates an incorrect type of key - wrongType = true; - output.Length = 0; - sizeChange = 0; - removeKey = false; + output.OutputFlags |= ObjectStoreOutputFlags.WrongType; + output.SpanByteAndMemory.Length = 0; return true; } @@ -124,49 +121,50 @@ 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 e0d16f959b..41cc09aa78 100644 --- a/libs/server/Objects/SortedSet/SortedSetObject.cs +++ b/libs/server/Objects/SortedSet/SortedSetObject.cs @@ -212,20 +212,16 @@ 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, out bool wrongType) + public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output) { - wrongType = false; - - fixed (byte* outputSpan = output.SpanByte.AsSpan()) + fixed (byte* outputSpan = output.SpanByteAndMemory.SpanByte.AsSpan()) { var header = input.header; if (header.type != GarnetObjectType.SortedSet) { // Indicates an incorrect type of key - wrongType = true; - output.Length = 0; - sizeChange = 0; - removeKey = false; + output.OutputFlags |= ObjectStoreOutputFlags.WrongType; + output.SpanByteAndMemory.Length = 0; return true; } @@ -234,7 +230,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); @@ -243,94 +239,95 @@ 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 101c1a8abb..79398821db 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, out bool wrongType); + public abstract bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output); /// public abstract void Dispose(); diff --git a/libs/server/Objects/Types/GarnetObjectStoreOutput.cs b/libs/server/Objects/Types/GarnetObjectStoreOutput.cs index 08dad1be97..69b0f6133e 100644 --- a/libs/server/Objects/Types/GarnetObjectStoreOutput.cs +++ b/libs/server/Objects/Types/GarnetObjectStoreOutput.cs @@ -1,29 +1,52 @@ // 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. /// 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; /// - /// True if an operation was attempted on the wrong type of object + /// Output flags /// - public bool wrongType; + public ObjectStoreOutputFlags OutputFlags; public void ConvertToHeap() { diff --git a/libs/server/Objects/Types/IGarnetObject.cs b/libs/server/Objects/Types/IGarnetObject.cs index f08019b490..e0938d03bc 100644 --- a/libs/server/Objects/Types/IGarnetObject.cs +++ b/libs/server/Objects/Types/IGarnetObject.cs @@ -33,11 +33,8 @@ public interface IGarnetObject : IDisposable /// /// /// - /// - /// - /// /// - bool Operate(ref ObjectInput input, ref SpanByteAndMemory output, out long sizeChange, out bool removeKey, out bool wrongType); + bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output); /// /// Serializer diff --git a/libs/server/Resp/Objects/HashCommands.cs b/libs/server/Resp/Objects/HashCommands.cs index 818ae9bc9f..d5e40ad42d 100644 --- a/libs/server/Resp/Objects/HashCommands.cs +++ b/libs/server/Resp/Objects/HashCommands.cs @@ -94,14 +94,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)) @@ -138,14 +138,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)) @@ -182,14 +182,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. @@ -262,7 +262,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; @@ -270,14 +270,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; @@ -495,7 +495,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) @@ -504,7 +504,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)) @@ -553,7 +553,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); @@ -564,7 +564,7 @@ private unsafe bool HashIncrement(RespCommand command, ref TGarnetAp SendAndReset(); break; default: - ProcessOutputWithHeader(outputFooter.spanByteAndMemory); + ProcessOutputWithHeader(outputFooter.SpanByteAndMemory); break; } return true; diff --git a/libs/server/Resp/Objects/ListCommands.cs b/libs/server/Resp/Objects/ListCommands.cs index a1cf1087cc..8f15ce7de2 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 4aa313d4cc..85f041b7d2 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/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 98083369ad..b43aebc915 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,11 +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 _, out var wrongType); - if (wrongType) - { - output.wrongType = true; - } + value.Operate(ref input, ref output); return true; } else @@ -61,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; } } @@ -137,22 +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, out var wrongType); - if (wrongType) - { - output.wrongType = true; + var operateSuccessful = value.Operate(ref input, ref output); + if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) return true; - } - if (removeKey) + + if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.RemoveKey)) { rmwInfo.Action = RMWAction.ExpireAndStop; return false; @@ -162,17 +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.wrongType = true; + 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); } @@ -237,21 +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, out var wrongType); - if (wrongType) - { - output.wrongType = true; + value.Operate(ref input, ref output); + if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) return true; - } - if (removeKey) + + if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.RemoveKey)) { rmwInfo.Action = RMWAction.ExpireAndStop; return false; @@ -262,17 +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.wrongType = true; + 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 8792b661c1..a628140f5d 100644 --- a/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs +++ b/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs @@ -29,51 +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) { - var opResult = value.Operate(ref input, ref dst.spanByteAndMemory, out _, out _, - out var wrongType); - if (wrongType) - { - dst.wrongType = true; + var opResult = value.Operate(ref input, ref dst); + if (dst.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) return true; - } + return opResult; } - if (IncorrectObjectType(ref input, value, ref dst.spanByteAndMemory)) + if (IncorrectObjectType(ref input, value, ref dst.SpanByteAndMemory)) { - dst.wrongType = true; + 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 509ea63510..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.wrongType) + 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.wrongType) + 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 4ede94e872..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.wrongType) + 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.wrongType) + 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.wrongType) + 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 aa61cee47e..fc54c90268 100644 --- a/libs/server/Storage/Session/ObjectStore/HashOps.cs +++ b/libs/server/Storage/Session/ObjectStore/HashOps.cs @@ -155,7 +155,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); @@ -190,7 +190,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); @@ -222,7 +222,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); @@ -314,7 +314,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); @@ -353,7 +353,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 a2840d4b82..c398504ba0 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 status = RMWObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); @@ -82,7 +82,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 status = RMWObjectStoreOperationWithOutput(key.ToArray(), ref input, ref objectStoreContext, ref outputFooter); @@ -245,7 +245,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); @@ -306,7 +306,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); @@ -343,7 +343,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); @@ -387,7 +387,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); @@ -517,7 +517,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--) @@ -658,7 +658,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); @@ -730,9 +730,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) { @@ -780,7 +780,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); } } @@ -1091,7 +1091,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; } @@ -1117,7 +1117,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; @@ -1155,7 +1155,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; } @@ -1173,7 +1173,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; @@ -1372,7 +1372,7 @@ private GarnetStatus SortedSetIntersection(ReadOnlySpan(ReadOnlySpan Date: Tue, 21 Jan 2025 11:59:22 -0700 Subject: [PATCH 3/9] format --- libs/server/Objects/List/ListObject.cs | 2 +- libs/server/Objects/Set/SetObject.cs | 2 +- libs/server/Objects/SortedSet/SortedSetObject.cs | 2 +- libs/server/Objects/Types/GarnetObjectStoreOutput.cs | 2 +- libs/server/Resp/RespCommandsInfo.cs | 2 +- libs/server/Storage/Functions/ObjectStore/RMWMethods.cs | 4 ++-- libs/server/Storage/Functions/ObjectStore/ReadMethods.cs | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libs/server/Objects/List/ListObject.cs b/libs/server/Objects/List/ListObject.cs index 3b17948139..4be2a8862c 100644 --- a/libs/server/Objects/List/ListObject.cs +++ b/libs/server/Objects/List/ListObject.cs @@ -189,7 +189,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore 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 828a11005e..bf77f0e361 100644 --- a/libs/server/Objects/Set/SetObject.cs +++ b/libs/server/Objects/Set/SetObject.cs @@ -164,7 +164,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore 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 41cc09aa78..66a63a6b1a 100644 --- a/libs/server/Objects/SortedSet/SortedSetObject.cs +++ b/libs/server/Objects/SortedSet/SortedSetObject.cs @@ -327,7 +327,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore if (sortedSetDict.Count == 0) output.OutputFlags |= ObjectStoreOutputFlags.RemoveKey; - + return true; } diff --git a/libs/server/Objects/Types/GarnetObjectStoreOutput.cs b/libs/server/Objects/Types/GarnetObjectStoreOutput.cs index 69b0f6133e..7c4891dae0 100644 --- a/libs/server/Objects/Types/GarnetObjectStoreOutput.cs +++ b/libs/server/Objects/Types/GarnetObjectStoreOutput.cs @@ -21,7 +21,7 @@ public enum ObjectStoreOutputFlags : byte /// Remove key /// RemoveKey = 1, - + /// /// Wrong type of object /// 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/RMWMethods.cs b/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs index b43aebc915..667fcfed75 100644 --- a/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs +++ b/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs @@ -144,7 +144,7 @@ bool InPlaceUpdaterWorker(ref byte[] key, ref ObjectInput input, ref IGarnetObje var operateSuccessful = value.Operate(ref input, ref output); if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) return true; - + if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.RemoveKey)) { rmwInfo.Action = RMWAction.ExpireAndStop; @@ -241,7 +241,7 @@ public bool PostCopyUpdater(ref byte[] key, ref ObjectInput input, ref IGarnetOb value.Operate(ref input, ref output); if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) return true; - + if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.RemoveKey)) { rmwInfo.Action = RMWAction.ExpireAndStop; diff --git a/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs b/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs index a628140f5d..e787f239a9 100644 --- a/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs +++ b/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs @@ -51,7 +51,7 @@ public bool SingleReader(ref byte[] key, ref ObjectInput input, ref IGarnetObjec var opResult = value.Operate(ref input, ref dst); if (dst.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) return true; - + return opResult; } From 20d7749f40625cb46a7699036d424ff4ba55a1c6 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Tue, 21 Jan 2025 15:18:07 -0700 Subject: [PATCH 4/9] Adding SizeChange to GOSO --- libs/server/Custom/CustomObjectBase.cs | 2 ++ libs/server/Objects/Hash/HashObject.cs | 6 ++++++ libs/server/Objects/List/ListObject.cs | 3 +++ libs/server/Objects/Set/SetObject.cs | 3 +++ libs/server/Objects/SortedSet/SortedSetObject.cs | 3 +++ libs/server/Objects/Types/GarnetObjectStoreOutput.cs | 5 +++++ libs/server/Storage/Functions/ObjectStore/RMWMethods.cs | 8 +++----- 7 files changed, 25 insertions(+), 5 deletions(-) diff --git a/libs/server/Custom/CustomObjectBase.cs b/libs/server/Custom/CustomObjectBase.cs index 294ca09035..5974bb4666 100644 --- a/libs/server/Custom/CustomObjectBase.cs +++ b/libs/server/Custom/CustomObjectBase.cs @@ -70,6 +70,8 @@ public sealed override void DoSerialize(BinaryWriter writer) /// public sealed override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output) { + output.SizeChange = 0; + switch (input.header.cmd) { // Scan Command diff --git a/libs/server/Objects/Hash/HashObject.cs b/libs/server/Objects/Hash/HashObject.cs index 9eef81f6fd..3529464323 100644 --- a/libs/server/Objects/Hash/HashObject.cs +++ b/libs/server/Objects/Hash/HashObject.cs @@ -110,6 +110,8 @@ public override void Dispose() { } /// public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output) { + output.SizeChange = 0; + fixed (byte* outputSpan = output.SpanByteAndMemory.SpanByte.AsSpan()) { if (input.header.type != GarnetObjectType.Hash) @@ -117,9 +119,11 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore //Indicates when there is an incorrect type output.OutputFlags |= ObjectStoreOutputFlags.WrongType; output.SpanByteAndMemory.Length = 0; + output.SizeChange = 0; return true; } + var previousSize = this.Size; switch (input.header.HashOp) { case HashOperation.HSET: @@ -183,6 +187,8 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore default: throw new GarnetException($"Unsupported operation {input.header.HashOp} in HashObject.Operate"); } + + output.SizeChange = this.Size - previousSize; } if (hash.Count == 0) diff --git a/libs/server/Objects/List/ListObject.cs b/libs/server/Objects/List/ListObject.cs index 4be2a8862c..39ae6db1cc 100644 --- a/libs/server/Objects/List/ListObject.cs +++ b/libs/server/Objects/List/ListObject.cs @@ -137,6 +137,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore // Indicates an incorrect type of key output.OutputFlags |= ObjectStoreOutputFlags.WrongType; output.SpanByteAndMemory.Length = 0; + output.SizeChange = 0; return true; } @@ -185,6 +186,8 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore default: throw new GarnetException($"Unsupported operation {input.header.ListOp} in ListObject.Operate"); } + + output.SizeChange = this.Size - previousSize; } if (list.Count == 0) diff --git a/libs/server/Objects/Set/SetObject.cs b/libs/server/Objects/Set/SetObject.cs index bf77f0e361..8985fec1cb 100644 --- a/libs/server/Objects/Set/SetObject.cs +++ b/libs/server/Objects/Set/SetObject.cs @@ -114,6 +114,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore // Indicates an incorrect type of key output.OutputFlags |= ObjectStoreOutputFlags.WrongType; output.SpanByteAndMemory.Length = 0; + output.SizeChange = 0; return true; } @@ -160,6 +161,8 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore default: throw new GarnetException($"Unsupported operation {input.header.SetOp} in SetObject.Operate"); } + + output.SizeChange = this.Size - prevSize; } if (set.Count == 0) diff --git a/libs/server/Objects/SortedSet/SortedSetObject.cs b/libs/server/Objects/SortedSet/SortedSetObject.cs index 66a63a6b1a..73f2bcf5ed 100644 --- a/libs/server/Objects/SortedSet/SortedSetObject.cs +++ b/libs/server/Objects/SortedSet/SortedSetObject.cs @@ -222,6 +222,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore // Indicates an incorrect type of key output.OutputFlags |= ObjectStoreOutputFlags.WrongType; output.SpanByteAndMemory.Length = 0; + output.SizeChange = 0; return true; } @@ -323,6 +324,8 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore default: throw new GarnetException($"Unsupported operation {op} in SortedSetObject.Operate"); } + + output.SizeChange = this.Size - prevSize; } if (sortedSetDict.Count == 0) diff --git a/libs/server/Objects/Types/GarnetObjectStoreOutput.cs b/libs/server/Objects/Types/GarnetObjectStoreOutput.cs index 7c4891dae0..ace7b2e80e 100644 --- a/libs/server/Objects/Types/GarnetObjectStoreOutput.cs +++ b/libs/server/Objects/Types/GarnetObjectStoreOutput.cs @@ -48,6 +48,11 @@ public struct GarnetObjectStoreOutput /// public ObjectStoreOutputFlags OutputFlags; + /// + /// Object size change + /// + public long SizeChange; + public void ConvertToHeap() { // Does not convert to heap when going pending, because we immediately complete pending operations for object store. diff --git a/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs b/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs index 667fcfed75..a33dac43f6 100644 --- a/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs +++ b/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs @@ -81,21 +81,19 @@ 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)) { if (!rmwInfo.RecordInfo.Modified) functionsState.watchVersionMap.IncrementVersion(rmwInfo.KeyHash); if (functionsState.appendOnlyFile != null) WriteLogRMW(ref key, ref input, rmwInfo.Version, rmwInfo.SessionID); - functionsState.objectStoreSizeTracker?.AddTrackedSize(sizeChange); + functionsState.objectStoreSizeTracker?.AddTrackedSize(output.SizeChange); return true; } return false; } - bool InPlaceUpdaterWorker(ref byte[] key, ref ObjectInput input, ref IGarnetObject value, ref GarnetObjectStoreOutput output, ref RMWInfo rmwInfo, out long sizeChange) + bool InPlaceUpdaterWorker(ref byte[] key, ref ObjectInput input, ref IGarnetObject value, ref GarnetObjectStoreOutput output, ref RMWInfo rmwInfo) { - sizeChange = 0; - // Expired data if (value.Expiration > 0 && input.header.CheckExpiry(value.Expiration)) { From 9c7b90954f2590ad7166aaae08a8cdbb409ed13b Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Tue, 21 Jan 2025 15:20:03 -0700 Subject: [PATCH 5/9] small fix --- libs/server/Objects/Hash/HashObject.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/server/Objects/Hash/HashObject.cs b/libs/server/Objects/Hash/HashObject.cs index 3529464323..8def8560fe 100644 --- a/libs/server/Objects/Hash/HashObject.cs +++ b/libs/server/Objects/Hash/HashObject.cs @@ -119,7 +119,6 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore //Indicates when there is an incorrect type output.OutputFlags |= ObjectStoreOutputFlags.WrongType; output.SpanByteAndMemory.Length = 0; - output.SizeChange = 0; return true; } From 8be5b0a8db18d02587bf34c03ea37d2f3f6e8444 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Tue, 21 Jan 2025 15:23:44 -0700 Subject: [PATCH 6/9] small fix --- libs/server/Objects/List/ListObject.cs | 3 ++- libs/server/Objects/Set/SetObject.cs | 3 ++- libs/server/Objects/SortedSet/SortedSetObject.cs | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libs/server/Objects/List/ListObject.cs b/libs/server/Objects/List/ListObject.cs index 39ae6db1cc..ea091392fe 100644 --- a/libs/server/Objects/List/ListObject.cs +++ b/libs/server/Objects/List/ListObject.cs @@ -130,6 +130,8 @@ public override void Dispose() { } /// public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output) { + output.SizeChange = 0; + fixed (byte* outputSpan = output.SpanByteAndMemory.SpanByte.AsSpan()) { if (input.header.type != GarnetObjectType.List) @@ -137,7 +139,6 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore // Indicates an incorrect type of key output.OutputFlags |= ObjectStoreOutputFlags.WrongType; output.SpanByteAndMemory.Length = 0; - output.SizeChange = 0; return true; } diff --git a/libs/server/Objects/Set/SetObject.cs b/libs/server/Objects/Set/SetObject.cs index 8985fec1cb..8f697b9407 100644 --- a/libs/server/Objects/Set/SetObject.cs +++ b/libs/server/Objects/Set/SetObject.cs @@ -107,6 +107,8 @@ public override void Dispose() { } /// public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output) { + output.SizeChange = 0; + fixed (byte* outputSpan = output.SpanByteAndMemory.SpanByte.AsSpan()) { if (input.header.type != GarnetObjectType.Set) @@ -114,7 +116,6 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore // Indicates an incorrect type of key output.OutputFlags |= ObjectStoreOutputFlags.WrongType; output.SpanByteAndMemory.Length = 0; - output.SizeChange = 0; return true; } diff --git a/libs/server/Objects/SortedSet/SortedSetObject.cs b/libs/server/Objects/SortedSet/SortedSetObject.cs index 73f2bcf5ed..73427bd2ec 100644 --- a/libs/server/Objects/SortedSet/SortedSetObject.cs +++ b/libs/server/Objects/SortedSet/SortedSetObject.cs @@ -214,6 +214,8 @@ public override void Dispose() { } /// public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output) { + output.SizeChange = 0; + fixed (byte* outputSpan = output.SpanByteAndMemory.SpanByte.AsSpan()) { var header = input.header; @@ -222,7 +224,6 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore // Indicates an incorrect type of key output.OutputFlags |= ObjectStoreOutputFlags.WrongType; output.SpanByteAndMemory.Length = 0; - output.SizeChange = 0; return true; } From 0a18f4a12594c93ba8aee1c7f4d23fecff915729 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Tue, 21 Jan 2025 16:12:56 -0700 Subject: [PATCH 7/9] Fixing broken merge --- libs/server/Objects/Hash/HashObject.cs | 8 ++++---- libs/server/Resp/Objects/HashCommands.cs | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libs/server/Objects/Hash/HashObject.cs b/libs/server/Objects/Hash/HashObject.cs index 2fafd39440..5f0629f415 100644 --- a/libs/server/Objects/Hash/HashObject.cs +++ b/libs/server/Objects/Hash/HashObject.cs @@ -200,13 +200,13 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore 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.SpanByteAndMemory); @@ -227,7 +227,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore 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.SpanByteAndMemory, out var cursorInput, out var pattern, diff --git a/libs/server/Resp/Objects/HashCommands.cs b/libs/server/Resp/Objects/HashCommands.cs index 3f731b37eb..1062e68ade 100644 --- a/libs/server/Resp/Objects/HashCommands.cs +++ b/libs/server/Resp/Objects/HashCommands.cs @@ -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; } From 79d060dd7f4efd8930ee2677b93a8b8a60c7b211 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Wed, 22 Jan 2025 15:00:52 -0700 Subject: [PATCH 8/9] Reverting sizeChange changes --- libs/server/Custom/CustomObjectBase.cs | 4 ++-- libs/server/Objects/Hash/HashObject.cs | 6 +++--- libs/server/Objects/List/ListObject.cs | 6 +++--- libs/server/Objects/Set/SetObject.cs | 6 +++--- libs/server/Objects/SortedSet/SortedSetObject.cs | 6 +++--- libs/server/Objects/Types/GarnetObjectBase.cs | 2 +- .../Objects/Types/GarnetObjectStoreOutput.cs | 5 ----- libs/server/Objects/Types/IGarnetObject.cs | 3 ++- .../Storage/Functions/ObjectStore/RMWMethods.cs | 14 ++++++++------ .../Storage/Functions/ObjectStore/ReadMethods.cs | 2 +- 10 files changed, 26 insertions(+), 28 deletions(-) diff --git a/libs/server/Custom/CustomObjectBase.cs b/libs/server/Custom/CustomObjectBase.cs index 5974bb4666..11c06d70fe 100644 --- a/libs/server/Custom/CustomObjectBase.cs +++ b/libs/server/Custom/CustomObjectBase.cs @@ -68,9 +68,9 @@ public sealed override void DoSerialize(BinaryWriter writer) public abstract override void Dispose(); /// - public sealed override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output) + public sealed override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output, out long sizeChange) { - output.SizeChange = 0; + sizeChange = 0; switch (input.header.cmd) { diff --git a/libs/server/Objects/Hash/HashObject.cs b/libs/server/Objects/Hash/HashObject.cs index 5f0629f415..215cb1010c 100644 --- a/libs/server/Objects/Hash/HashObject.cs +++ b/libs/server/Objects/Hash/HashObject.cs @@ -155,9 +155,9 @@ public override void Dispose() { } public override GarnetObjectBase Clone() => new HashObject(hash, expirationTimes, expirationQueue, Expiration, Size); /// - public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output) + public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output, out long sizeChange) { - output.SizeChange = 0; + sizeChange = 0; fixed (byte* outputSpan = output.SpanByteAndMemory.SpanByte.AsSpan()) { @@ -246,7 +246,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore throw new GarnetException($"Unsupported operation {input.header.HashOp} in HashObject.Operate"); } - output.SizeChange = this.Size - previousSize; + sizeChange = this.Size - previousSize; } if (hash.Count == 0) diff --git a/libs/server/Objects/List/ListObject.cs b/libs/server/Objects/List/ListObject.cs index ea091392fe..2771b84b25 100644 --- a/libs/server/Objects/List/ListObject.cs +++ b/libs/server/Objects/List/ListObject.cs @@ -128,9 +128,9 @@ public override void Dispose() { } public override GarnetObjectBase Clone() => new ListObject(list, Expiration, Size); /// - public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output) + public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output, out long sizeChange) { - output.SizeChange = 0; + sizeChange = 0; fixed (byte* outputSpan = output.SpanByteAndMemory.SpanByte.AsSpan()) { @@ -188,7 +188,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore throw new GarnetException($"Unsupported operation {input.header.ListOp} in ListObject.Operate"); } - output.SizeChange = this.Size - previousSize; + sizeChange = this.Size - previousSize; } if (list.Count == 0) diff --git a/libs/server/Objects/Set/SetObject.cs b/libs/server/Objects/Set/SetObject.cs index 8f697b9407..8c4bd2535c 100644 --- a/libs/server/Objects/Set/SetObject.cs +++ b/libs/server/Objects/Set/SetObject.cs @@ -105,9 +105,9 @@ public override void Dispose() { } public override GarnetObjectBase Clone() => new SetObject(set, Expiration, Size); /// - public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output) + public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output, out long sizeChange) { - output.SizeChange = 0; + sizeChange = 0; fixed (byte* outputSpan = output.SpanByteAndMemory.SpanByte.AsSpan()) { @@ -163,7 +163,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore throw new GarnetException($"Unsupported operation {input.header.SetOp} in SetObject.Operate"); } - output.SizeChange = this.Size - prevSize; + sizeChange = this.Size - prevSize; } if (set.Count == 0) diff --git a/libs/server/Objects/SortedSet/SortedSetObject.cs b/libs/server/Objects/SortedSet/SortedSetObject.cs index 73427bd2ec..cbfa9dd1a6 100644 --- a/libs/server/Objects/SortedSet/SortedSetObject.cs +++ b/libs/server/Objects/SortedSet/SortedSetObject.cs @@ -212,9 +212,9 @@ public override void Dispose() { } public override GarnetObjectBase Clone() => new SortedSetObject(sortedSet, sortedSetDict, Expiration, Size); /// - public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output) + public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output, out long sizeChange) { - output.SizeChange = 0; + sizeChange = 0; fixed (byte* outputSpan = output.SpanByteAndMemory.SpanByte.AsSpan()) { @@ -326,7 +326,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref GarnetObjectStore throw new GarnetException($"Unsupported operation {op} in SortedSetObject.Operate"); } - output.SizeChange = this.Size - prevSize; + sizeChange = this.Size - prevSize; } if (sortedSetDict.Count == 0) diff --git a/libs/server/Objects/Types/GarnetObjectBase.cs b/libs/server/Objects/Types/GarnetObjectBase.cs index 79398821db..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 GarnetObjectStoreOutput output); + 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 ace7b2e80e..7c4891dae0 100644 --- a/libs/server/Objects/Types/GarnetObjectStoreOutput.cs +++ b/libs/server/Objects/Types/GarnetObjectStoreOutput.cs @@ -48,11 +48,6 @@ public struct GarnetObjectStoreOutput /// public ObjectStoreOutputFlags OutputFlags; - /// - /// Object size change - /// - public long SizeChange; - public void ConvertToHeap() { // Does not convert to heap when going pending, because we immediately complete pending operations for object store. diff --git a/libs/server/Objects/Types/IGarnetObject.cs b/libs/server/Objects/Types/IGarnetObject.cs index e0938d03bc..41ff2f3c3d 100644 --- a/libs/server/Objects/Types/IGarnetObject.cs +++ b/libs/server/Objects/Types/IGarnetObject.cs @@ -33,8 +33,9 @@ public interface IGarnetObject : IDisposable /// /// /// + /// /// - bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output); + bool Operate(ref ObjectInput input, ref GarnetObjectStoreOutput output, out long sizeChange); /// /// Serializer diff --git a/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs b/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs index a33dac43f6..d53ade1bfe 100644 --- a/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs +++ b/libs/server/Storage/Functions/ObjectStore/RMWMethods.cs @@ -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); + value.Operate(ref input, ref output, out _); return true; } else @@ -81,19 +81,21 @@ 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)) + if (InPlaceUpdaterWorker(ref key, ref input, ref value, ref output, ref rmwInfo, out var sizeChange)) { if (!rmwInfo.RecordInfo.Modified) functionsState.watchVersionMap.IncrementVersion(rmwInfo.KeyHash); if (functionsState.appendOnlyFile != null) WriteLogRMW(ref key, ref input, rmwInfo.Version, rmwInfo.SessionID); - functionsState.objectStoreSizeTracker?.AddTrackedSize(output.SizeChange); + functionsState.objectStoreSizeTracker?.AddTrackedSize(sizeChange); return true; } return false; } - bool InPlaceUpdaterWorker(ref byte[] key, ref ObjectInput input, ref IGarnetObject value, ref GarnetObjectStoreOutput output, ref RMWInfo rmwInfo) + bool InPlaceUpdaterWorker(ref byte[] key, ref ObjectInput input, ref IGarnetObject value, ref GarnetObjectStoreOutput output, ref RMWInfo rmwInfo, out long sizeChange) { + sizeChange = 0; + // Expired data if (value.Expiration > 0 && input.header.CheckExpiry(value.Expiration)) { @@ -139,7 +141,7 @@ bool InPlaceUpdaterWorker(ref byte[] key, ref ObjectInput input, ref IGarnetObje default: if ((byte)input.header.type < CustomCommandManager.CustomTypeIdStartOffset) { - var operateSuccessful = value.Operate(ref input, ref output); + var operateSuccessful = value.Operate(ref input, ref output, out sizeChange); if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) return true; @@ -236,7 +238,7 @@ public bool PostCopyUpdater(ref byte[] key, ref ObjectInput input, ref IGarnetOb default: if ((byte)input.header.type < CustomCommandManager.CustomTypeIdStartOffset) { - value.Operate(ref input, ref output); + value.Operate(ref input, ref output, out _); if (output.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) return true; diff --git a/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs b/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs index e787f239a9..3f10f18ec6 100644 --- a/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs +++ b/libs/server/Storage/Functions/ObjectStore/ReadMethods.cs @@ -48,7 +48,7 @@ public bool SingleReader(ref byte[] key, ref ObjectInput input, ref IGarnetObjec default: if ((byte)input.header.type < CustomCommandManager.CustomTypeIdStartOffset) { - var opResult = value.Operate(ref input, ref dst); + var opResult = value.Operate(ref input, ref dst, out _); if (dst.OutputFlags.HasFlag(ObjectStoreOutputFlags.WrongType)) return true; From 5036a985a0f133757721fb9ac4906a502fbfb452 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Wed, 22 Jan 2025 18:56:00 -0700 Subject: [PATCH 9/9] Added comment in GOSO --- libs/server/Objects/Types/GarnetObjectStoreOutput.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/server/Objects/Types/GarnetObjectStoreOutput.cs b/libs/server/Objects/Types/GarnetObjectStoreOutput.cs index 7c4891dae0..c6dba3be90 100644 --- a/libs/server/Objects/Types/GarnetObjectStoreOutput.cs +++ b/libs/server/Objects/Types/GarnetObjectStoreOutput.cs @@ -30,6 +30,8 @@ public enum ObjectStoreOutputFlags : byte /// /// 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 {