예제 #1
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);
                }

                if (sibling.PageSize != page.PageSize)
                {
                    // if the current page is compressed (but already opened), we need to
                    // avoid merging it with the right (uncompressed) page
                    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);
            }
        }