Esempio n. 1
0
        public byte *Execute()
        {
            using (DisableFreeSpaceUsageIfSplittingRootTree())
            {
                TreePage rightPage = _tree.NewPage(_page.TreeFlags, _page.PageNumber);

                if (_cursor.PageCount == 0) // we need to do a root split
                {
                    TreePage newRootPage = _tree.NewPage(TreePageFlags.Branch, _page.PageNumber);
                    _cursor.Push(newRootPage);
                    _tree.State.RootPageNumber = newRootPage.PageNumber;
                    _tree.State.Depth++;

                    // now add implicit left page
                    newRootPage.AddPageRefNode(0, Slices.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 = _tree.ModifyPage(_cursor.CurrentPage);

                    _cursor.Update(_cursor.Pages, _parentPage);
                }

                if (_page.IsLeaf)
                {
                    _tree.ClearPagesCache();
                }

                if (_page.IsCompressed)
                {
                    _pageDecompressed = _tree.DecompressPage(_page);
                    _pageDecompressed.Search(_tx, _newKey);
                    if (_pageDecompressed.LastMatch == 0)
                    {
                        // we are going to insert the value in a bit, but it might have
                        // been in the compressed portion and not removed by the calling
                        // code
                        _tree.RemoveLeafNode(_pageDecompressed);
                    }
                    _page = _pageDecompressed;
                }

                using (_pageDecompressed)
                {
                    if (_page.LastSearchPosition >= _page.NumberOfEntries)
                    {
                        var pos = OptimizedOnlyMoveNewValueToTheRightPage(rightPage);
                        RecompressPageIfNeeded(wasModified: false);

                        return(pos);
                    }

                    return(SplitPageInHalf(rightPage));
                }
            }
        }
Esempio n. 2
0
        public byte *Execute()
        {
            using (DisableFreeSpaceUsageIfSplittingRootTree())
            {
                TreePage rightPage = _tree.NewPage(_page.TreeFlags, 1);

                if (_cursor.PageCount == 0) // we need to do a root split
                {
                    TreePage newRootPage = _tree.NewPage(TreePageFlags.Branch, 1);
                    _cursor.Push(newRootPage);
                    _tree.State.RootPageNumber = newRootPage.PageNumber;
                    _tree.State.Depth++;

                    // now add implicit left page
                    newRootPage.AddPageRefNode(0, Slices.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 = _tree.ModifyPage(_cursor.CurrentPage);

                    _cursor.Update(_cursor.Pages.First, _parentPage);
                }

                if (_page.IsLeaf)
                {
                    _tree.ClearPagesCache();
                }

                if (_page.IsCompressed)
                {
                    _pageDecompressed = _tree.DecompressPage(_page);
                    _pageDecompressed.Search(_tx, _newKey);
                    _page = _pageDecompressed;
                }

                using (_pageDecompressed)
                {
                    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

                        TreePage 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

                                TreeNodeHeader *node = _page.GetNode(_page.NumberOfEntries - 1);
                                Debug.Assert(node->Flags == TreeNodeFlags.PageRef);
                                rightPage.AddPageRefNode(0, Slices.BeforeAllKeys, node->PageNumber);
                                pos = AddNodeToPage(rightPage, 1);

                                Slice separatorKey;
                                using (TreeNodeHeader.ToSlicePtr(_tx.Allocator, node, out separatorKey))
                                {
                                    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));
                }
            }
        }
Esempio n. 3
0
        public TreePage Execute(TreePage page)
        {
            using (DisableFreeSpaceUsageIfSplittingRootTree())
            {
                _tree.ClearPagesCache();
                if (_cursor.PageCount <= 1) // the root page
                {
                    RebalanceRoot(page);
                    return(null);
                }

                _cursor.Pop();

                var parentPage = _tree.ModifyPage(_cursor.CurrentPage);
                _cursor.Update(_cursor.Pages, 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);

                    return(parentPage);
                }

                if (page.IsBranch && page.NumberOfEntries == 1)
                {
                    RemoveBranchWithOneEntry(page, parentPage);

                    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.TreeFlags != sibling.TreeFlags)
                {
                    return(null);
                }

                if (sibling.IsCompressed)
                {
                    return(null);
                }

                Debug.Assert(page.IsCompressed == false);

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

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

                return(parentPage);
            }
        }