Beispiel #1
0
        public byte *Execute()
        {
            var rightPage = Tree.NewPage(_tx, _page.Flags, 1);

            _txInfo.RecordNewPage(_page, 1);
            rightPage.Flags = _page.Flags;
            if (_cursor.PageCount == 0) // we need to do a root split
            {
                var newRootPage = Tree.NewPage(_tx, PageFlags.Branch, 1);
                _cursor.Push(newRootPage);
                _txInfo.RootPageNumber = newRootPage.PageNumber;
                _txInfo.State.Depth++;
                _txInfo.RecordNewPage(newRootPage, 1);

                // now add implicit left page
                newRootPage.AddNode(0, Slice.BeforeAllKeys, -1, _page.PageNumber);
                _parentPage = newRootPage;
                _parentPage.LastSearchPosition++;
                _parentPage.ItemCount = _page.ItemCount;
            }
            else
            {
                // we already popped the page, so the current one on the stack is what the parent of the page
                _parentPage = _cursor.CurrentPage;
            }

            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
                    var node = _page.GetNode(_page.NumberOfEntries - 1);
                    Debug.Assert(node->Flags == NodeFlags.PageRef);
                    var itemsMoved = _tx.Pager.Get(_tx, node->PageNumber).ItemCount;
                    rightPage.AddNode(0, Slice.Empty, -1, node->PageNumber);
                    pos = rightPage.AddNode(1, _newKey, _len, _pageNumber);
                    rightPage.ItemCount = itemsMoved;

                    AddSeperatorToParentPage(rightPage, new Slice(node));

                    _page.RemoveNode(_page.NumberOfEntries - 1);
                    _page.ItemCount -= itemsMoved;
                }
                else
                {
                    AddSeperatorToParentPage(rightPage, _newKey);
                    pos = rightPage.AddNode(0, _newKey, _len, _pageNumber);
                }
                _cursor.Push(rightPage);
                IncrementItemCountIfNecessary();
                return(pos);
            }

            return(SplitPageInHalf(rightPage));
        }
Beispiel #2
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));
        }
Beispiel #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));
            }
        }
        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));
        }