void CreateBTreeParentFromTwoChildren(Sector leftSector, Sector rightSector, byte[] middleKeyData, int middleKeyLen, int middleKeyOfs, int middleKeyLenInSector) { Sector parentSector = _owner.NewSector(); parentSector.Type = SectorType.BTreeParent; var entrySize = BTreeParentIterator.CalcEntrySize(middleKeyLen); parentSector.SetLengthWithRound(BTreeParentIterator.HeaderSize + BTreeParentIterator.HeaderForEntry + entrySize); BTreeParentIterator.SetCountToSectorData(parentSector.Data, 1); int ofs = 2; SectorPtr.Pack(parentSector.Data, ofs, leftSector.ToSectorPtr()); ofs += KeyValueDB.PtrDownSize; PackUnpack.PackUInt64LE(parentSector.Data, ofs, CalcKeysInSector(leftSector)); ofs += 8; PackUnpack.PackUInt16LE(parentSector.Data, ofs, (ushort)entrySize); ofs += 2; PackUnpack.PackUInt32LE(parentSector.Data, ofs, (uint)middleKeyLen); ofs += 4; SectorPtr.Pack(parentSector.Data, ofs, rightSector.ToSectorPtr()); ofs += KeyValueDB.PtrDownSize; PackUnpack.PackUInt64LE(parentSector.Data, ofs, CalcKeysInSector(rightSector)); ofs += 8; Array.Copy(middleKeyData, middleKeyOfs, parentSector.Data, ofs, middleKeyLenInSector); _owner.NewState.RootBTree.Ptr = parentSector.Position; _owner.NewState.RootBTreeLevels++; leftSector.Parent = parentSector; rightSector.Parent = parentSector; _currentKeySectorParents.Insert(0, parentSector); _owner.PublishSector(parentSector, false); _owner.TruncateSectorCache(true, 0); }
void AddToBTreeParent(Sector leftSector, Sector rightSector, byte[] middleKeyData, int middleKeyLen, int middleKeyOfs, int middleKeyLenInSector) { var parentSector = leftSector.Parent; var iter = new BTreeParentIterator(parentSector.Data); int additionalLengthNeeded = BTreeParentIterator.HeaderForEntry + BTreeParentIterator.CalcEntrySize(middleKeyLen); int leftIndexInParent = iter.FindChildByPos(leftSector.Position); bool splitting = true; if (!KeyValueDB.ShouldSplitBTreeParent(iter.TotalLength, additionalLengthNeeded, iter.Count + 1)) { parentSector = _owner.ResizeSectorWithUpdatePositionNoWriteTruncate( parentSector, iter.TotalLength + additionalLengthNeeded, parentSector.Parent, _currentKeySectorParents); splitting = false; } var mergedData = new byte[iter.TotalLength + additionalLengthNeeded]; BTreeParentIterator.SetCountToSectorData(mergedData, iter.Count + 1); int ofs; int splitOfs = iter.OffsetOfIndex(leftIndexInParent); if (leftIndexInParent == 0) { SectorPtr.Pack(mergedData, BTreeParentIterator.FirstChildSectorPtrOffset, leftSector.ToSectorPtr()); PackUnpack.PackUInt64LE(mergedData, BTreeParentIterator.FirstChildSectorPtrOffset + KeyValueDB.PtrDownSize, CalcKeysInSector(leftSector)); ofs = BTreeParentIterator.HeaderSize + BTreeParentIterator.HeaderForEntry * (iter.Count + 1); } else { Array.Copy(iter.Data, BTreeParentIterator.FirstChildSectorPtrOffset, mergedData, BTreeParentIterator.FirstChildSectorPtrOffset, KeyValueDB.PtrDownSize + 8); ofs = BTreeParentIterator.HeaderSize + BTreeParentIterator.HeaderForEntry * (iter.Count + 1); int splitOfsPrev = iter.OffsetOfIndex(leftIndexInParent - 1); Array.Copy(iter.Data, iter.FirstOffset, mergedData, ofs, splitOfsPrev - iter.FirstOffset); ofs += splitOfsPrev - iter.FirstOffset; Array.Copy(iter.Data, splitOfsPrev, mergedData, ofs, 4 + KeyValueDB.PtrDownSize); ofs += 4 + KeyValueDB.PtrDownSize; PackUnpack.PackUInt64LE(mergedData, ofs, CalcKeysInSector(leftSector)); ofs += 8; splitOfsPrev += 4 + KeyValueDB.PtrDownSize + 8; Array.Copy(iter.Data, splitOfsPrev, mergedData, ofs, splitOfs - splitOfsPrev); ofs += splitOfs - splitOfsPrev; } PackUnpack.PackInt32LE(mergedData, ofs, middleKeyLen); ofs += 4; SectorPtr.Pack(mergedData, ofs, rightSector.ToSectorPtr()); ofs += KeyValueDB.PtrDownSize; PackUnpack.PackUInt64LE(mergedData, ofs, CalcKeysInSector(rightSector)); ofs += 8; Array.Copy(middleKeyData, middleKeyOfs, mergedData, ofs, middleKeyLenInSector); ofs += middleKeyLenInSector; Array.Copy(iter.Data, splitOfs, mergedData, ofs, iter.TotalLength - splitOfs); BTreeParentIterator.RecalculateHeader(mergedData, iter.Count + 1); if (!splitting) { Array.Copy(mergedData, parentSector.Data, mergedData.Length); leftSector.Parent = parentSector; rightSector.Parent = parentSector; IncrementChildCountInBTreeParents(parentSector); _owner.FixChildrenParentPointers(parentSector); } else { iter = new BTreeParentIterator(mergedData); int middleoffset = mergedData.Length / 2; iter.MoveFirst(); int splitIndex = 0; int currentPos = iter.FirstOffset; while (currentPos < middleoffset) { currentPos += iter.CurrentEntrySize; splitIndex++; iter.MoveNext(); } Sector leftParentSector = null; Sector rightParentSector = null; try { rightParentSector = _owner.NewSector(); rightParentSector.Type = SectorType.BTreeParent; var rightCount = iter.Count - splitIndex - 1; var rightFirstOffset = BTreeParentIterator.HeaderSize + rightCount * BTreeParentIterator.HeaderForEntry; rightParentSector.SetLengthWithRound(rightFirstOffset + mergedData.Length - iter.NextEntryOffset); BTreeParentIterator.SetCountToSectorData(rightParentSector.Data, rightCount); rightParentSector.Parent = parentSector.Parent; var leftFirstOffset = BTreeParentIterator.HeaderSize + splitIndex * BTreeParentIterator.HeaderForEntry; leftParentSector = _owner.ResizeSectorWithUpdatePosition(parentSector, leftFirstOffset + currentPos - iter.FirstOffset, parentSector.Parent, _currentKeySectorParents); BTreeParentIterator.SetCountToSectorData(leftParentSector.Data, splitIndex); leftSector.Parent = leftParentSector; rightSector.Parent = leftParentSector; Array.Copy(mergedData, BTreeParentIterator.FirstChildSectorPtrOffset, leftParentSector.Data, BTreeParentIterator.FirstChildSectorPtrOffset, KeyValueDB.PtrDownSize + 8 + BTreeParentIterator.HeaderForEntry * splitIndex); Array.Copy(mergedData, iter.FirstOffset, leftParentSector.Data, leftFirstOffset, currentPos - iter.FirstOffset); Array.Copy(mergedData, iter.ChildSectorPtrOffset, rightParentSector.Data, BTreeParentIterator.FirstChildSectorPtrOffset, KeyValueDB.PtrDownSize + 8); Array.Copy(mergedData, iter.NextEntryOffset, rightParentSector.Data, rightFirstOffset, iter.TotalLength - iter.NextEntryOffset); BTreeParentIterator.RecalculateHeader(rightParentSector.Data, rightCount); _owner.FixChildrenParentPointers(leftParentSector); _owner.PublishSector(rightParentSector, true); Interlocked.Increment(ref leftParentSector.ChildrenInCache); Interlocked.Increment(ref rightParentSector.ChildrenInCache); try { _owner.TruncateSectorCache(true, 0); int keyLenInSector = iter.KeyLenInline + (iter.HasKeySectorPtr ? KeyValueDB.PtrDownSize : 0); if (leftParentSector.Parent == null) { CreateBTreeParentFromTwoChildren(leftParentSector, rightParentSector, iter.Data, iter.KeyLen, iter.KeyOffset, keyLenInSector); } else { AddToBTreeParent(leftParentSector, rightParentSector, iter.Data, iter.KeyLen, iter.KeyOffset, keyLenInSector); } } finally { Interlocked.Decrement(ref leftParentSector.ChildrenInCache); Interlocked.Decrement(ref rightParentSector.ChildrenInCache); } } finally { if (leftSector.Parent == rightParentSector) { for (int i = 0; i < _currentKeySectorParents.Count; i++) { if (_currentKeySectorParents[i] == leftParentSector) { _currentKeySectorParents[i] = rightParentSector; break; } } } } } }