public Page Execute(Page page) { _tree.ClearRecentFoundPages(); if (_cursor.PageCount <= 1) // the root page { RebalanceRoot(page); return(null); } var parentPage = _tx.ModifyPage(_cursor.ParentPage.PageNumber, _tree, _cursor.ParentPage); _cursor.Update(_cursor.Pages.First.Next, parentPage); if (page.NumberOfEntries == 0) // empty page, just delete it and fixup parent { // need to change the implicit left page if (parentPage.LastSearchPosition == 0 && parentPage.NumberOfEntries > 2) { var newImplicit = parentPage.GetNode(1)->PageNumber; parentPage.RemoveNode(0); parentPage.ChangeImplicitRefPageNode(newImplicit); } else // will be set to rights by the next rebalance call { parentPage.RemoveNode(parentPage.LastSearchPositionOrLastEntry); } _tree.FreePage(page); _cursor.Pop(); return(parentPage); } if (page.IsBranch && page.NumberOfEntries == 1) { RemoveBranchWithOneEntry(page, parentPage); _cursor.Pop(); return(parentPage); } var minKeys = page.IsBranch ? 2 : 1; if ((page.UseMoreSizeThan(_tx.DataPager.PageMinSpace)) && page.NumberOfEntries >= minKeys) { return(null); // above space/keys thresholds } Debug.Assert(parentPage.NumberOfEntries >= 2); // if we have less than 2 entries in the parent, the tree is invalid var sibling = SetupMoveOrMerge(page, parentPage); Debug.Assert(sibling.PageNumber != page.PageNumber); if (page.Flags != sibling.Flags) { return(null); } minKeys = sibling.IsBranch ? 2 : 1; // branch must have at least 2 keys if (sibling.UseMoreSizeThan(_tx.DataPager.PageMinSpace) && sibling.NumberOfEntries > minKeys) { _cursor.Pop(); // neighbor is over the min size and has enough key, can move just one key to the current page if (page.IsBranch) { MoveBranchNode(parentPage, sibling, page); } else { MoveLeafNode(parentPage, sibling, page); } return(parentPage); } if (page.LastSearchPosition == 0) // this is the right page, merge left { if (TryMergePages(parentPage, sibling, page) == false) { return(null); } } else // this is the left page, merge right { if (TryMergePages(parentPage, page, sibling) == false) { return(null); } } _cursor.Pop(); return(parentPage); }
public byte *Execute() { Page rightPage = _tree.NewPage(_page.Flags, 1); if (_cursor.PageCount == 0) // we need to do a root split { Page newRootPage = _tree.NewPage(_tree.KeysPrefixing ? PageFlags.Branch | PageFlags.KeysPrefixed : PageFlags.Branch, 1); _cursor.Push(newRootPage); _treeState.RootPageNumber = newRootPage.PageNumber; _treeState.Depth++; // now add implicit left page newRootPage.AddPageRefNode(0, _tree.KeysPrefixing ? (MemorySlice)PrefixedSlice.BeforeAllKeys : Slice.BeforeAllKeys, _page.PageNumber); _parentPage = newRootPage; _parentPage.LastSearchPosition++; } else { // we already popped the page, so the current one on the stack is the parent of the page if (_tree.Name == Constants.FreeSpaceTreeName) { // a special case for FreeSpaceTree because the allocation of a new page called above // can cause a delete of a free space section resulting in a run of the tree rebalancer // and here the parent page that exists in cursor can be outdated _parentPage = _tx.ModifyPage(_cursor.CurrentPage.PageNumber, _tree, null); // pass _null_ to make sure we'll get the most updated parent page _parentPage.LastSearchPosition = _cursor.CurrentPage.LastSearchPosition; _parentPage.LastMatch = _cursor.CurrentPage.LastMatch; } else { _parentPage = _tx.ModifyPage(_cursor.CurrentPage.PageNumber, _tree, _cursor.CurrentPage); } _cursor.Update(_cursor.Pages.First, _parentPage); } if (_page.IsLeaf) { _tree.ClearRecentFoundPages(); } if (_tree.Name == Constants.FreeSpaceTreeName) { // we need to refresh the LastSearchPosition of the split page which is used by the free space handling // because the allocation of a new page called above could remove some sections // from the page that is being split _page.NodePositionFor(_newKey); } if (_page.LastSearchPosition >= _page.NumberOfEntries) { // when we get a split at the end of the page, we take that as a hint that the user is doing // sequential inserts, at that point, we are going to keep the current page as is and create a new // page, this will allow us to do minimal amount of work to get the best density Page branchOfSeparator; byte *pos; if (_page.IsBranch) { if (_page.NumberOfEntries > 2) { // here we steal the last entry from the current page so we maintain the implicit null left entry NodeHeader *node = _page.GetNode(_page.NumberOfEntries - 1); Debug.Assert(node->Flags == NodeFlags.PageRef); rightPage.AddPageRefNode(0, _tree.KeysPrefixing ? (MemorySlice)PrefixedSlice.BeforeAllKeys : Slice.BeforeAllKeys, node->PageNumber); pos = AddNodeToPage(rightPage, 1); var separatorKey = _page.GetNodeKey(node); AddSeparatorToParentPage(rightPage.PageNumber, separatorKey, out branchOfSeparator); _page.RemoveNode(_page.NumberOfEntries - 1); } else { _tree.FreePage(rightPage); // return the unnecessary right page pos = AddSeparatorToParentPage(_pageNumber, _newKey, out branchOfSeparator); if (_cursor.CurrentPage.PageNumber != branchOfSeparator.PageNumber) { _cursor.Push(branchOfSeparator); } return(pos); } } else { AddSeparatorToParentPage(rightPage.PageNumber, _newKey, out branchOfSeparator); pos = AddNodeToPage(rightPage, 0); } _cursor.Push(rightPage); return(pos); } return(SplitPageInHalf(rightPage)); }
public byte *Execute() { using (_tree.IsFreeSpaceTree ? _tx.Environment.FreeSpaceHandling.Disable() : null) { Page rightPage = _tree.NewPage(_page.Flags, 1); if (_cursor.PageCount == 0) // we need to do a root split { Page newRootPage = _tree.NewPage(_tree.KeysPrefixing ? PageFlags.Branch | PageFlags.KeysPrefixed : PageFlags.Branch, 1); _cursor.Push(newRootPage); _tree.State.RootPageNumber = newRootPage.PageNumber; _tree.State.Depth++; // now add implicit left page newRootPage.AddPageRefNode(0, _tree.KeysPrefixing ? (MemorySlice)PrefixedSlice.BeforeAllKeys : Slice.BeforeAllKeys, _page.PageNumber); _parentPage = newRootPage; _parentPage.LastSearchPosition++; } else { // we already popped the page, so the current one on the stack is the parent of the page _parentPage = _tx.ModifyPage(_cursor.CurrentPage.PageNumber, _tree, _cursor.CurrentPage); _cursor.Update(_cursor.Pages.First, _parentPage); } if (_page.IsLeaf) { _tree.ClearRecentFoundPages(); } if (_page.LastSearchPosition >= _page.NumberOfEntries) { // when we get a split at the end of the page, we take that as a hint that the user is doing // sequential inserts, at that point, we are going to keep the current page as is and create a new // page, this will allow us to do minimal amount of work to get the best density Page branchOfSeparator; byte *pos; if (_page.IsBranch) { if (_page.NumberOfEntries > 2) { // here we steal the last entry from the current page so we maintain the implicit null left entry NodeHeader *node = _page.GetNode(_page.NumberOfEntries - 1); Debug.Assert(node->Flags == NodeFlags.PageRef); rightPage.AddPageRefNode(0, _tree.KeysPrefixing ? (MemorySlice)PrefixedSlice.BeforeAllKeys : Slice.BeforeAllKeys, node->PageNumber); pos = AddNodeToPage(rightPage, 1); var separatorKey = _page.GetNodeKey(node); AddSeparatorToParentPage(rightPage.PageNumber, separatorKey, out branchOfSeparator); _page.RemoveNode(_page.NumberOfEntries - 1); } else { _tree.FreePage(rightPage); // return the unnecessary right page pos = AddSeparatorToParentPage(_pageNumber, _newKey, out branchOfSeparator); if (_cursor.CurrentPage.PageNumber != branchOfSeparator.PageNumber) { _cursor.Push(branchOfSeparator); } return(pos); } } else { AddSeparatorToParentPage(rightPage.PageNumber, _newKey, out branchOfSeparator); pos = AddNodeToPage(rightPage, 0); } _cursor.Push(rightPage); return(pos); } return(SplitPageInHalf(rightPage)); } }
public Page Execute(Cursor cursor, Page page) { _tx.ClearRecentFoundPages(_tree); if (cursor.PageCount <= 1) // the root page { RebalanceRoot(cursor, page); return null; } var parentPage = _tx.ModifyPage(cursor.ParentPage.PageNumber, cursor.ParentPage); cursor.Update(cursor.Pages.First.Next, parentPage); if (page.NumberOfEntries == 0) // empty page, just delete it and fixup parent { // need to delete the implicit left page, shift right if (parentPage.LastSearchPosition == 0 && parentPage.NumberOfEntries > 2) { var newImplicit = parentPage.GetNode(1)->PageNumber; parentPage.RemoveNode(0); parentPage.RemoveNode(0); parentPage.AddPageRefNode(0, Slice.Empty, newImplicit); } else // will be set to rights by the next rebalance call { parentPage.RemoveNode(parentPage.LastSearchPositionOrLastEntry); } _tx.FreePage(page.PageNumber); cursor.Pop(); return parentPage; } var minKeys = page.IsBranch ? 2 : 1; if ((page.UseMoreSizeThan(_tx.DataPager.PageMinSpace)) && page.NumberOfEntries >= minKeys) return null; // above space/keys thresholds Debug.Assert(parentPage.NumberOfEntries >= 2); // if we have less than 2 entries in the parent, the tree is invalid var sibling = SetupMoveOrMerge(cursor, page, parentPage); Debug.Assert(sibling.PageNumber != page.PageNumber); minKeys = sibling.IsBranch ? 2 : 1; // branch must have at least 2 keys if (sibling.UseMoreSizeThan(_tx.DataPager.PageMinSpace) && sibling.NumberOfEntries > minKeys) { // neighbor is over the min size and has enough key, can move just one key to the current page if (page.IsBranch) { MoveBranchNode(parentPage, sibling, page); } else MoveLeafNode(parentPage, sibling, page); cursor.Pop(); return parentPage; } if (page.LastSearchPosition == 0) // this is the right page, merge left { if (!HasEnoughSpaceToCopyNodes(sibling, page)) return null; MergePages(parentPage, sibling, page); } else // this is the left page, merge right { if (!HasEnoughSpaceToCopyNodes(page, sibling)) return null; MergePages(parentPage, page, sibling); } cursor.Pop(); return parentPage; }
public byte *Execute() { Page rightPage = Tree.NewPage(_tx, _page.Flags, 1); _treeState.RecordNewPage(_page, 1); rightPage.Flags = _page.Flags; if (_cursor.PageCount == 0) // we need to do a root split { Page newRootPage = Tree.NewPage(_tx, PageFlags.Branch, 1); _cursor.Push(newRootPage); _treeState.RootPageNumber = newRootPage.PageNumber; _treeState.Depth++; _treeState.RecordNewPage(newRootPage, 1); // now add implicit left page newRootPage.AddPageRefNode(0, Slice.BeforeAllKeys, _page.PageNumber); _parentPage = newRootPage; _parentPage.LastSearchPosition++; } else { // we already popped the page, so the current one on the stack is what the parent of the page _parentPage = _tx.ModifyPage(_cursor.CurrentPage.PageNumber, _cursor.CurrentPage); _cursor.Update(_cursor.Pages.First, _parentPage); } if (_page.IsLeaf) { _tx.ClearRecentFoundPages(_tree); } if (_page.LastSearchPosition >= _page.NumberOfEntries) { // when we get a split at the end of the page, we take that as a hint that the user is doing // sequential inserts, at that point, we are going to keep the current page as is and create a new // page, this will allow us to do minimal amount of work to get the best density byte *pos; if (_page.IsBranch) { // here we steal the last entry from the current page so we maintain the implicit null left entry NodeHeader *node = _page.GetNode(_page.NumberOfEntries - 1); Debug.Assert(node->Flags == NodeFlags.PageRef); rightPage.AddPageRefNode(0, Slice.Empty, node->PageNumber); pos = AddNodeToPage(rightPage, 1); AddSeparatorToParentPage(rightPage, new Slice(node)); _page.RemoveNode(_page.NumberOfEntries - 1); } else { AddSeparatorToParentPage(rightPage, _newKey); pos = AddNodeToPage(rightPage, 0); } _cursor.Push(rightPage); return(pos); } return(SplitPageInHalf(rightPage)); }