diff --git a/src/Paprika/Store/DataPage.cs b/src/Paprika/Store/DataPage.cs index 6560c38e..f643b838 100644 --- a/src/Paprika/Store/DataPage.cs +++ b/src/Paprika/Store/DataPage.cs @@ -60,6 +60,14 @@ public Page Set(in NibblePath key, in ReadOnlySpan data, IBatchContext bat return page; } + Page child; + + // Special case: if the key can be flushed down and a child if it was written in this batch, go to it directly + if (TryWriteDownToAlreadyWrittenInThisBatch(key, data, batch)) + { + return page; + } + // No place in map, try flush to leafs first TryFlushDownToExistingChildren(map, batch); @@ -74,7 +82,6 @@ public Page Set(in NibblePath key, in ReadOnlySpan data, IBatchContext bat // Try get the child page ref var address = ref Data.Buckets[nibble]; - Page child; if (address.IsNull) { @@ -98,6 +105,26 @@ public Page Set(in NibblePath key, in ReadOnlySpan data, IBatchContext bat return Set(key, data, batch); } + private bool TryWriteDownToAlreadyWrittenInThisBatch(in NibblePath key, ReadOnlySpan data, IBatchContext batch) + { + if (key.IsEmpty) + return false; + + var addr = Data.Buckets[key.FirstNibble]; + if (addr.IsNull) + return false; + + var child = batch.GetAt(addr); + if (batch.WasWritten(child) == false || child.Header.PageType != PageType.Standard) + return false; + + // The key has a single nibble, the child page was written in this batch and is a standard page. Let's proceed! + Debug.Assert(child.Header.BatchId == batch.BatchId); + var result = new DataPage(child).Set(key, data, batch); + Debug.Assert(result.Equals(child)); + return true; + } + private void TryFlushDownToExistingChildren(in SlottedArray map, IBatchContext batch) { var anyChildren = false;