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;
                     }
                 }
             }
         }
     }
 }