From 8fdc2dede0ee5e3afe0092c6bfc1ae3c0e072a94 Mon Sep 17 00:00:00 2001 From: Kevin Montrose Date: Mon, 1 Jun 2026 16:37:43 -0400 Subject: [PATCH 1/2] DeleteAfterDropArg is dead so remove it; VADDAppendLogArg can trigger CU now that we don't hide it in a separate namespace, so prevent it from clobbering the index by actually copying the index value over --- libs/server/Resp/Vector/VectorManager.cs | 4 ++-- .../Storage/Functions/MainStore/RMWMethods.cs | 24 ++++++++----------- .../Functions/MainStore/VarLenInputMethods.cs | 6 +++++ 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/libs/server/Resp/Vector/VectorManager.cs b/libs/server/Resp/Vector/VectorManager.cs index 6e8b34da4c0..92cd60e33ee 100644 --- a/libs/server/Resp/Vector/VectorManager.cs +++ b/libs/server/Resp/Vector/VectorManager.cs @@ -40,8 +40,8 @@ public sealed partial class VectorManager : IDisposable internal const int IndexSizeBytes = Index.Size; internal const long VADDAppendLogArg = long.MinValue; - internal const long DeleteAfterDropArg = VADDAppendLogArg + 1; - internal const long RecreateIndexArg = DeleteAfterDropArg + 1; + // DeleteAfterDropArg used to be here + internal const long RecreateIndexArg = VADDAppendLogArg + 2; internal const long VREMAppendLogArg = RecreateIndexArg + 1; internal const long MigrateElementKeyLogArg = VREMAppendLogArg + 1; internal const long MigrateIndexKeyLogArg = MigrateElementKeyLogArg + 1; diff --git a/libs/server/Storage/Functions/MainStore/RMWMethods.cs b/libs/server/Storage/Functions/MainStore/RMWMethods.cs index 38e9619640c..f29e30d3acc 100644 --- a/libs/server/Storage/Functions/MainStore/RMWMethods.cs +++ b/libs/server/Storage/Functions/MainStore/RMWMethods.cs @@ -811,20 +811,15 @@ private readonly IPUResult InPlaceUpdaterWorker(ref LogRecord logRecord, ref Str case RespCommand.VADD: // Adding to an existing VectorSet is modeled as a read operations // - // However, we do synthesize some (pointless) writes to implement replication - // and a "make me delete=able"-update during drop. + // However, we do synthesize some (pointless) writes to implement replication (which we ignore here). // // Another "not quite write" is the recreate an index write operation // that occurs if we're adding to an index that was restored from disk // or a primary node. - // Handle "make me delete-able" - if (input.arg1 == VectorManager.DeleteAfterDropArg) - { - logRecord.ValueSpan.Clear(); - } - else if (input.arg1 == VectorManager.RecreateIndexArg) + if (input.arg1 == VectorManager.RecreateIndexArg) { + // Recreate index var newIndexPtr = MemoryMarshal.Read(input.parseState.GetArgSliceByRef(11).Span); functionsState.vectorManager.RecreateIndex(newIndexPtr, logRecord.ValueSpan); @@ -1326,19 +1321,20 @@ public readonly bool CopyUpdater(in TSourceLogRecord srcLogRec break; case RespCommand.VADD: - // Handle "make me delete-able" - if (input.arg1 == VectorManager.DeleteAfterDropArg) - { - dstLogRecord.ValueSpan.Clear(); - } - else if (input.arg1 == VectorManager.RecreateIndexArg) + if (input.arg1 == VectorManager.RecreateIndexArg) { + // Recreate index var newIndexPtr = MemoryMarshal.Read(input.parseState.GetArgSliceByRef(11).Span); oldValue.CopyTo(dstLogRecord.ValueSpan); functionsState.vectorManager.RecreateIndex(newIndexPtr, dstLogRecord.ValueSpan); } + else if (input.arg1 == VectorManager.VADDAppendLogArg) + { + // VADD has triggered a CU of the index key - we want to do nothing but we have to copy to prevent corruption + oldValue.CopyTo(dstLogRecord.ValueSpan); + } break; diff --git a/libs/server/Storage/Functions/MainStore/VarLenInputMethods.cs b/libs/server/Storage/Functions/MainStore/VarLenInputMethods.cs index db28a191a53..f639636ec4e 100644 --- a/libs/server/Storage/Functions/MainStore/VarLenInputMethods.cs +++ b/libs/server/Storage/Functions/MainStore/VarLenInputMethods.cs @@ -361,6 +361,12 @@ public RecordFieldInfo GetRMWModifiedFieldInfo(in TSourceLogRe case RespCommand.VADD: case RespCommand.VREM: + if (input.arg1 == VectorManager.VADDAppendLogArg) + { + // During replication we might trigger a CU, in which case... make sure there's space for the index we'll copy over + fieldInfo.ValueSize = VectorManager.IndexSize; + } + return fieldInfo; default: From dea2d9223c298db2248ae72cb10649c9820e0a83 Mon Sep 17 00:00:00 2001 From: Kevin Montrose Date: Mon, 1 Jun 2026 17:44:13 -0400 Subject: [PATCH 2/2] VREM replication has the same potential issue --- libs/server/Storage/Functions/MainStore/RMWMethods.cs | 2 +- libs/server/Storage/Functions/MainStore/VarLenInputMethods.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/server/Storage/Functions/MainStore/RMWMethods.cs b/libs/server/Storage/Functions/MainStore/RMWMethods.cs index f29e30d3acc..0114e754611 100644 --- a/libs/server/Storage/Functions/MainStore/RMWMethods.cs +++ b/libs/server/Storage/Functions/MainStore/RMWMethods.cs @@ -1330,7 +1330,7 @@ public readonly bool CopyUpdater(in TSourceLogRecord srcLogRec functionsState.vectorManager.RecreateIndex(newIndexPtr, dstLogRecord.ValueSpan); } - else if (input.arg1 == VectorManager.VADDAppendLogArg) + else if (input.arg1 is VectorManager.VADDAppendLogArg or VectorManager.VREMAppendLogArg) { // VADD has triggered a CU of the index key - we want to do nothing but we have to copy to prevent corruption oldValue.CopyTo(dstLogRecord.ValueSpan); diff --git a/libs/server/Storage/Functions/MainStore/VarLenInputMethods.cs b/libs/server/Storage/Functions/MainStore/VarLenInputMethods.cs index f639636ec4e..eb83556fd75 100644 --- a/libs/server/Storage/Functions/MainStore/VarLenInputMethods.cs +++ b/libs/server/Storage/Functions/MainStore/VarLenInputMethods.cs @@ -361,7 +361,7 @@ public RecordFieldInfo GetRMWModifiedFieldInfo(in TSourceLogRe case RespCommand.VADD: case RespCommand.VREM: - if (input.arg1 == VectorManager.VADDAppendLogArg) + if (input.arg1 is VectorManager.VADDAppendLogArg or VectorManager.VREMAppendLogArg) { // During replication we might trigger a CU, in which case... make sure there's space for the index we'll copy over fieldInfo.ValueSize = VectorManager.IndexSize;