Example #1
0
        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));
        }
Example #2
0
        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);
        }
Example #3
0
        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));
            }
        }