Skip to content

Commit ce9a6db

Browse files
authored
Fix: snapshot checkpoint flush corner case (#1413)
* Fix: snapshot checkpoint flush corner case * nit * Ensure serialization completion before nullifying. Introduce a loop to check `serializationState` and ensure that any concurrent serialization of `oldValue` is completed before setting it to `null` and returning. This prevents concurrent modification of the shallow-copied object contents. * misc bugfixes * update version
1 parent 9626fdf commit ce9a6db

File tree

9 files changed

+33
-6
lines changed

9 files changed

+33
-6
lines changed

Version.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<!-- VersionPrefix property for builds and packages -->
33
<PropertyGroup>
4-
<VersionPrefix>1.0.86</VersionPrefix>
4+
<VersionPrefix>1.0.87</VersionPrefix>
55
</PropertyGroup>
66
</Project>

benchmark/Resp.benchmark/ReqGen.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,12 @@ private void RandomString()
305305
if (numericValue)
306306
{
307307
for (int i = 0; i < valueBuffer.Length; i++)
308-
valueBuffer[i] = ascii_digits[valueRandomGen.Next(ascii_digits.Length)];
308+
{
309+
if (i == 0)
310+
valueBuffer[i] = ascii_digits[1 + valueRandomGen.Next(ascii_digits.Length - 1)];
311+
else
312+
valueBuffer[i] = ascii_digits[valueRandomGen.Next(ascii_digits.Length)];
313+
}
309314
}
310315
else
311316
{

benchmark/Resp.benchmark/ReqGenUtils.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ private bool WriteKey(ref byte* curr, byte* vend, out byte[] keyData)
364364
else
365365
key = Start + keyIndex++;
366366

367-
keyData = Encoding.ASCII.GetBytes(key.ToString().PadLeft(keyLen, numericValue ? '0' : 'X'));
367+
keyData = Encoding.ASCII.GetBytes(key.ToString().PadLeft(keyLen, numericValue ? '1' : 'X'));
368368
return WriteStringBytes(ref curr, vend, keyData);
369369
}
370370

libs/host/Configuration/Options.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ internal sealed class Options : ICloneable
146146
public bool? ObjectStoreCopyReadsToTail { get; set; }
147147

148148
[LogDirValidation(false, false)]
149-
[Option('l', "logdir", Required = false, HelpText = "Storage directory for tiered records (hybrid log), if storage tiering (--storage) is enabled. Uses current directory if unspecified.")]
149+
[Option('l', "logdir", Required = false, HelpText = "Storage directory for tiered records (hybrid log), if storage tiering (--storage-tier) is enabled. Uses current directory if unspecified.")]
150150
public string LogDir { get; set; }
151151

152152
[CheckpointDirValidation(false, false)]

libs/server/Objects/Types/GarnetObjectBase.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,17 @@ public void CopyUpdate(ref IGarnetObject oldValue, ref IGarnetObject newValue, b
8686
// since the new version of the object is already created.
8787
if (!isInNewVersion)
8888
{
89+
// Wait for any concurrent ongoing serialization of oldValue to complete
90+
while (true)
91+
{
92+
if (serializationState == (int)SerializationPhase.REST && MakeTransition(SerializationPhase.REST, SerializationPhase.SERIALIZED))
93+
break;
94+
95+
if (serializationState >= (int)SerializationPhase.SERIALIZED)
96+
break;
97+
98+
_ = Thread.Yield();
99+
}
89100
oldValue = null;
90101
return;
91102
}

libs/server/Storage/Functions/MainStore/PrivateMethods.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@ static void TryCopyUpdateNumber(ref SpanByte oldValue, ref SpanByte newValue, re
532532
// Move to tail of the log even when oldValue is alphanumeric
533533
// We have already paid the cost of bringing from disk so we are treating as a regular access and bring it into memory
534534
oldValue.CopyTo(ref newValue);
535+
output.SpanByte.AsSpan()[0] = (byte)OperationError.INVALID_TYPE;
535536
return;
536537
}
537538

libs/server/Storage/Functions/MainStore/VarLenInputMethods.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,11 @@ public int GetRMWModifiedValueLength(ref SpanByte t, ref RawStringInput input)
144144
case RespCommand.INCRBY:
145145
var incrByValue = input.header.cmd == RespCommand.INCRBY ? input.arg1 : 1;
146146

147-
var curr = NumUtils.ReadInt64(t.AsSpan(functionsState.etagState.etagOffsetForVarlen));
147+
if (!NumUtils.TryReadInt64(t.AsSpan(functionsState.etagState.etagOffsetForVarlen), out var curr))
148+
{
149+
// Return enough space to copy over old value
150+
return sizeof(int) + t.Length + functionsState.etagState.etagOffsetForVarlen;
151+
}
148152
var next = curr + incrByValue;
149153

150154
var ndigits = NumUtils.CountDigits(next, out var isNegative);

libs/storage/Tsavorite/cs/src/core/Index/Checkpointing/SnapshotCheckpointSMTask.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ public override void GlobalBeforeEnteringState(SystemState next, StateMachineDri
4646
// If we are using a NullDevice then storage tier is not enabled and FlushedUntilAddress may be ReadOnlyAddress; get all records in memory.
4747
store._hybridLogCheckpoint.info.snapshotStartFlushedLogicalAddress = store.hlogBase.IsNullDevice ? store.hlogBase.HeadAddress : store.hlogBase.FlushedUntilAddress;
4848

49+
if (store._hybridLogCheckpoint.info.finalLogicalAddress <= store._hybridLogCheckpoint.info.snapshotStartFlushedLogicalAddress)
50+
{
51+
// Nothing to flush because the flushed region already contains everything up to finalLogicalAddress.
52+
break;
53+
}
54+
4955
long startPage = store.hlogBase.GetPage(store._hybridLogCheckpoint.info.snapshotStartFlushedLogicalAddress);
5056
long endPage = store.hlogBase.GetPage(store._hybridLogCheckpoint.info.finalLogicalAddress);
5157
if (store._hybridLogCheckpoint.info.finalLogicalAddress >

playground/ClusterStress/ReqGenForCluster.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ private byte[] GetClusterKeyInterleaved()
199199

200200
string keyStr = "{" + key.ToString() + "}";
201201
currKeyInSlot++;
202-
return Encoding.ASCII.GetBytes(keyStr.PadRight(keyLen, numericValue ? '0' : 'X'));
202+
return Encoding.ASCII.GetBytes(keyStr.PadRight(keyLen, numericValue ? '1' : 'X'));
203203
}
204204

205205
}

0 commit comments

Comments
 (0)