Example #1
0
        public bool MovePrev()
        {
            while (true)
            {
                _currentPage.LastSearchPosition--;
                if (_currentPage.LastSearchPosition >= 0)
                {
                    // run out of entries, need to select the next page...
                    while (_currentPage.IsBranch)
                    {
                        _cursor.Push(_currentPage);
                        var node = _currentPage.GetNode(_currentPage.LastSearchPosition);
                        _currentPage = _tx.GetReadOnlyPage(node->PageNumber);
                        _currentPage.LastSearchPosition = _currentPage.NumberOfEntries - 1;
                    }
                    var current = _currentPage.GetNode(_currentPage.LastSearchPosition);
                    if (this.ValidateCurrentKey(current, _currentPage) == false)
                    {
                        return(false);
                    }

                    _currentPage.SetNodeKey(current, ref _currentInternalKey);
                    _currentKey = _currentInternalKey.ToSlice();
                    return(true);                   // there is another entry in this page
                }
                if (_cursor.PageCount == 0)
                {
                    break;
                }
                _currentPage = _cursor.Pop();
            }
            _currentPage = null;
            return(false);
        }
Example #2
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));
        }
Example #3
0
        public Page FindPageFor(Transaction tx, Slice key, Cursor cursor)
        {
            var treeDataInTransaction = tx.GetTreeInformation(this);
            var p = tx.GetReadOnlyPage(treeDataInTransaction.RootPageNumber);

            cursor.Push(p);
            while (p.Flags == (PageFlags.Branch))
            {
                int nodePos;
                if (key.Options == SliceOptions.BeforeAllKeys)
                {
                    p.LastSearchPosition = nodePos = 0;
                }
                else if (key.Options == SliceOptions.AfterAllKeys)
                {
                    p.LastSearchPosition = nodePos = (ushort)(p.NumberOfEntries - 1);
                }
                else
                {
                    if (p.Search(key, _cmp) != null)
                    {
                        nodePos = p.LastSearchPosition;
                        if (p.LastMatch != 0)
                        {
                            nodePos--;
                            p.LastSearchPosition--;
                        }
                    }
                    else
                    {
                        nodePos = (ushort)(p.LastSearchPosition - 1);
                    }
                }

                var node = p.GetNode(nodePos);
                p = tx.GetReadOnlyPage(node->PageNumber);
                cursor.Push(p);
            }

            if (p.IsLeaf == false)
            {
                throw new DataException("Index points to a non leaf page");
            }

            p.NodePositionFor(key, _cmp); // will set the LastSearchPosition

            return(p);
        }
Example #4
0
 public bool MoveNext()
 {
     while (true)
     {
         _currentPage.LastSearchPosition++;
         if (_currentPage.LastSearchPosition < _currentPage.NumberOfEntries)
         {
             // run out of entries, need to select the next page...
             while (_currentPage.IsBranch)
             {
                 _cursor.Push(_currentPage);
                 var node = _currentPage.GetNode(_currentPage.LastSearchPosition);
                 _currentPage = _tx.GetReadOnlyPage(node->PageNumber);
                 _currentPage.LastSearchPosition = 0;
             }
             var current = _currentPage.GetNode(_currentPage.LastSearchPosition);
             if (this.ValidateCurrentKey(current, _cmp) == false)
             {
                 return(false);
             }
             _currentKey.Set(current);
             return(true);                   // there is another entry in this page
         }
         if (_cursor.PageCount == 0)
         {
             break;
         }
         _currentPage = _cursor.Pop();
     }
     _currentPage = null;
     return(false);
 }
        private void RebalanceRoot(Cursor cursor, TreeDataInTransaction txInfo, Page page)
        {
            if (page.NumberOfEntries == 0)
            {
                return; // nothing to do
            }
            if (!page.IsBranch || page.NumberOfEntries > 1)
            {
                return; // cannot do anything here
            }
            // in this case, we have a root pointer with just one pointer, we can just swap it out

            var node = page.GetNode(0);

            Debug.Assert(node->Flags == (NodeFlags.PageRef));

            _tx.ModifyCursor(txInfo, cursor);
            txInfo.State.LeafPages   = 1;
            txInfo.State.BranchPages = 0;
            txInfo.State.Depth       = 1;
            txInfo.State.PageCount   = 1;

            var rootPage = _tx.ModifyPage(_txInfo.Tree, null, node->PageNumber, cursor);

            rootPage.ItemCount    = 1;
            txInfo.RootPageNumber = rootPage.PageNumber;

            Debug.Assert(rootPage.Dirty);

            cursor.Pop();
            cursor.Push(rootPage);

            _tx.FreePage(page.PageNumber);
        }
Example #6
0
        private void RebalanceRoot(Page page)
        {
            if (page.NumberOfEntries == 0)
            {
                return; // nothing to do
            }
            if (!page.IsBranch || page.NumberOfEntries > 1)
            {
                return; // cannot do anything here
            }
            // in this case, we have a root pointer with just one pointer, we can just swap it out

            var node = page.GetNode(0);

            Debug.Assert(node->Flags == (NodeFlags.PageRef));

            var rootPage = _tx.ModifyPage(node->PageNumber, _tree, null);

            _tree.State.RootPageNumber = rootPage.PageNumber;
            _tree.State.Depth--;

            Debug.Assert(rootPage.Dirty);

            _cursor.Pop();
            _cursor.Push(rootPage);

            _tree.FreePage(page);
        }
Example #7
0
        public bool MovePrev()
        {
            if (_disposed)
            {
                throw new ObjectDisposedException("TreeIterator " + _tree.Name);
            }
            while (true)
            {
                _currentPage.LastSearchPosition--;
                if (_currentPage.LastSearchPosition >= 0)
                {
                    // run out of entries, need to select the next page...
                    while (_currentPage.IsBranch)
                    {
                        _cursor.Push(_currentPage);
                        var node = _currentPage.GetNode(_currentPage.LastSearchPosition);

                        _currentPage = _tx.GetReadOnlyPage(node->PageNumber);
                        _currentPage.LastSearchPosition = _currentPage.NumberOfEntries - 1;

                        if (_prefetch && _currentPage.IsLeaf)
                        {
                            MaybePrefetchOverflowPages(_currentPage);
                        }
                    }
                    var current = _currentPage.GetNode(_currentPage.LastSearchPosition);
                    if (this.ValidateCurrentKey(current, _currentPage) == false)
                    {
                        return(false);
                    }

                    _currentPage.SetNodeKey(current, ref _currentInternalKey);
                    _currentKey = _currentInternalKey.ToSlice();
                    return(true);// there is another entry in this page
                }
                if (_cursor.PageCount == 0)
                {
                    break;
                }
                _currentPage = _cursor.Pop();
            }
            _currentPage = null;
            return(false);
        }
Example #8
0
        private Page SearchForPage(MemorySlice key, out Lazy <Cursor> cursor, out NodeHeader *node)
        {
            var p = _tx.GetReadOnlyPage(State.RootPageNumber);
            var c = new Cursor();

            c.Push(p);

            bool rightmostPage = true;
            bool leftmostPage  = true;

            while ((p.Flags & PageFlags.Branch) == PageFlags.Branch)
            {
                int nodePos;
                if (key.Options == SliceOptions.BeforeAllKeys)
                {
                    p.LastSearchPosition = nodePos = 0;
                    rightmostPage        = false;
                }
                else if (key.Options == SliceOptions.AfterAllKeys)
                {
                    p.LastSearchPosition = nodePos = (ushort)(p.NumberOfEntries - 1);
                    leftmostPage         = false;
                }
                else
                {
                    if (p.Search(key) != null)
                    {
                        nodePos = p.LastSearchPosition;
                        if (p.LastMatch != 0)
                        {
                            nodePos--;
                            p.LastSearchPosition--;
                        }

                        if (nodePos != 0)
                        {
                            leftmostPage = false;
                        }

                        rightmostPage = false;
                    }
                    else
                    {
                        nodePos = (ushort)(p.LastSearchPosition - 1);

                        leftmostPage = false;
                    }
                }

                var pageNode = p.GetNode(nodePos);
                p = _tx.GetReadOnlyPage(pageNode->PageNumber);
                Debug.Assert(pageNode->PageNumber == p.PageNumber,
                             string.Format("Requested Page: #{0}. Got Page: #{1}", pageNode->PageNumber, p.PageNumber));

                c.Push(p);
            }

            if (p.IsLeaf == false)
            {
                throw new DataException("Index points to a non leaf page");
            }

            node = p.Search(key); // will set the LastSearchPosition

            AddToRecentlyFoundPages(c, p, leftmostPage, rightmostPage);

            cursor = new Lazy <Cursor>(() => c);
            return(p);
        }
Example #9
0
	    private bool TryUseRecentTransactionPage(Transaction tx, Slice key, out Lazy<Cursor> cursor, out Page page)
		{
			page = null;
			cursor = null;

			var recentPages = tx.GetRecentlyFoundPages(this);

			if (recentPages == null)
				return false;

			var foundPage = recentPages.Find(key);

			if (foundPage == null)
				return false;

			var lastFoundPageNumber = foundPage.Number;
			page = tx.GetReadOnlyPage(lastFoundPageNumber);

			if (page.IsLeaf == false)
				throw new DataException("Index points to a non leaf page");

			page.NodePositionFor(key, _cmp); // will set the LastSearchPosition

			var cursorPath = foundPage.CursorPath;
			var pageCopy = page;
			cursor = new Lazy<Cursor>(() =>
			{
				var c = new Cursor();
				foreach (var p in cursorPath)
				{
					if (p == lastFoundPageNumber)
						c.Push(pageCopy);
					else
					{
						var cursorPage = tx.GetReadOnlyPage(p);
						if (key.Options == SliceOptions.BeforeAllKeys)
						{
							cursorPage.LastSearchPosition = 0;
						}
						else if (key.Options == SliceOptions.AfterAllKeys)
						{
							cursorPage.LastSearchPosition = (ushort)(cursorPage.NumberOfEntries - 1);
						}
						else if (cursorPage.Search(key, _cmp) != null)
						{
							if (cursorPage.LastMatch != 0)
							{
								cursorPage.LastSearchPosition--;
							}
						}

						c.Push(cursorPage);
					}
				}

				return c;
			});

			return true;
		}
Example #10
0
	    private Page SearchForPage(Transaction tx, Slice key, ref Lazy<Cursor> cursor)
	    {
	        var p = tx.GetReadOnlyPage(State.RootPageNumber);
	        var c = new Cursor();
	        c.Push(p);

	        bool rightmostPage = true;
	        bool leftmostPage = true;

	        while (p.Flags == (PageFlags.Branch))
	        {
	            int nodePos;
	            if (key.Options == SliceOptions.BeforeAllKeys)
	            {
	                p.LastSearchPosition = nodePos = 0;
	                rightmostPage = false;
	            }
	            else if (key.Options == SliceOptions.AfterAllKeys)
	            {
	                p.LastSearchPosition = nodePos = (ushort) (p.NumberOfEntries - 1);
	                leftmostPage = false;
	            }
	            else
	            {
	                if (p.Search(key, _cmp) != null)
	                {
	                    nodePos = p.LastSearchPosition;
	                    if (p.LastMatch != 0)
	                    {
	                        nodePos--;
	                        p.LastSearchPosition--;
	                    }

	                    if (nodePos != 0)
	                        leftmostPage = false;

	                    rightmostPage = false;
	                }
	                else
	                {
	                    nodePos = (ushort) (p.LastSearchPosition - 1);

	                    leftmostPage = false;
	                }
	            }

	            var node = p.GetNode(nodePos);
	            p = tx.GetReadOnlyPage(node->PageNumber);
	            Debug.Assert(node->PageNumber == p.PageNumber,
	                string.Format("Requested Page: #{0}. Got Page: #{1}", node->PageNumber, p.PageNumber));

	            c.Push(p);
	        }

	        if (p.IsLeaf == false)
	            throw new DataException("Index points to a non leaf page");

	        p.Search(key, _cmp); // will set the LastSearchPosition

	        AddToRecentlyFoundPages(tx, c, p, leftmostPage, rightmostPage);

	        cursor = new Lazy<Cursor>(() => c);
	        return p;
	    }
Example #11
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));
            }
        }
Example #12
0
        private bool TryUseRecentTransactionPage(Slice key, out Lazy <Cursor> cursor, out Page page)
        {
            page   = null;
            cursor = null;

            var recentPages = _tx.GetRecentlyFoundPages(this);

            if (recentPages == null)
            {
                return(false);
            }

            var foundPage = recentPages.Find(key);

            if (foundPage == null)
            {
                return(false);
            }

            var lastFoundPageNumber = foundPage.Number;

            page = _tx.GetReadOnlyPage(lastFoundPageNumber);

            if (page.IsLeaf == false)
            {
                throw new DataException("Index points to a non leaf page");
            }

            page.NodePositionFor(key);             // will set the LastSearchPosition

            var cursorPath = foundPage.CursorPath;
            var pageCopy   = page;

            cursor = new Lazy <Cursor>(() =>
            {
                var c = new Cursor();
                foreach (var p in cursorPath)
                {
                    if (p == lastFoundPageNumber)
                    {
                        c.Push(pageCopy);
                    }
                    else
                    {
                        var cursorPage = _tx.GetReadOnlyPage(p);
                        if (key.Options == SliceOptions.BeforeAllKeys)
                        {
                            cursorPage.LastSearchPosition = 0;
                        }
                        else if (key.Options == SliceOptions.AfterAllKeys)
                        {
                            cursorPage.LastSearchPosition = (ushort)(cursorPage.NumberOfEntries - 1);
                        }
                        else if (cursorPage.Search(key) != null)
                        {
                            if (cursorPage.LastMatch != 0)
                            {
                                cursorPage.LastSearchPosition--;
                            }
                        }

                        c.Push(cursorPage);
                    }
                }

                return(c);
            });

            return(true);
        }
Example #13
0
        private void RebalanceRoot(Cursor cursor, Page page)
        {
            if (page.NumberOfEntries == 0)
                return; // nothing to do 
            if (!page.IsBranch || page.NumberOfEntries > 1)
            {
                return; // cannot do anything here
            }
            // in this case, we have a root pointer with just one pointer, we can just swap it out

            var node = page.GetNode(0);
            Debug.Assert(node->Flags == (NodeFlags.PageRef));

            _tree.State.LeafPages = 1;
			_tree.State.BranchPages = 0;
			_tree.State.Depth = 1;
			_tree.State.PageCount = 1;

			var rootPage = _tx.ModifyPage(node->PageNumber, null);
			_tree.State.RootPageNumber = rootPage.PageNumber;

            Debug.Assert(rootPage.Dirty);

            cursor.Pop();
            cursor.Push(rootPage);

            _tx.FreePage(page.PageNumber);
        }
Example #14
0
        public byte *AddSeparator(MemorySlice separator, long pageRefNumber, int?nodePos = null)
        {
            var originalLastSearchPositionOfParent = _parentPage.LastSearchPosition;

            if (nodePos == null)
            {
                nodePos = _parentPage.NodePositionFor(separator); // select the appropriate place for this
            }
            var separatorKeyToInsert = _parentPage.PrepareKeyToInsert(separator, nodePos.Value);

            if (_parentPage.HasSpaceFor(_tx, SizeOf.BranchEntry(separatorKeyToInsert) + Constants.NodeOffsetSize + SizeOf.NewPrefix(separatorKeyToInsert)) == false)
            {
                var pageSplitter = new PageSplitter(_tx, _tree, separator, -1, pageRefNumber, NodeFlags.PageRef, 0, _cursor, _tree.State);

                var posToInsert = pageSplitter.Execute();

                ParentOfAddedPageRef = _cursor.CurrentPage;

                var adjustParentPageOnCursor = true;

                for (int i = 0; i < _cursor.CurrentPage.NumberOfEntries; i++)
                {
                    if (_cursor.CurrentPage.GetNode(i)->PageNumber == _currentPage.PageNumber)
                    {
                        adjustParentPageOnCursor = false;
                        _cursor.CurrentPage.LastSearchPosition = i;
                        break;
                    }
                }

                if (adjustParentPageOnCursor)
                {
                    // the above page split has modified the cursor that its first page points to the parent of the leaf where 'separatorKey' was inserted
                    // and it doesn't have the reference to _page, we need to ensure that the actual parent is first at the cursor

                    _cursor.Pop();
                    _cursor.Push(_parentPage);

                    EnsureValidLastSearchPosition(_parentPage, _currentPage.PageNumber, originalLastSearchPositionOfParent);
                }
#if VALIDATE
                Debug.Assert(_cursor.CurrentPage.GetNode(_cursor.CurrentPage.LastSearchPosition)->PageNumber == _currentPage.PageNumber,
                             "The parent page is not referencing a page which is being split");

                var parentToValidate = ParentOfAddedPageRef;
                Debug.Assert(Enumerable.Range(0, parentToValidate.NumberOfEntries).Any(i => parentToValidate.GetNode(i)->PageNumber == pageRefNumber),
                             "The parent page of a page reference isn't referencing it");
#endif


                return(posToInsert);
            }

            ParentOfAddedPageRef = _parentPage;

            var pos = _parentPage.AddPageRefNode(nodePos.Value, separatorKeyToInsert, pageRefNumber);

            EnsureValidLastSearchPosition(_parentPage, _currentPage.PageNumber, originalLastSearchPositionOfParent);

            return(pos);
        }
Example #15
0
        private bool TryUseRecentTransactionPage(MemorySlice key, out Lazy <Cursor> cursor, out Page page, out NodeHeader *node)
        {
            node   = null;
            page   = null;
            cursor = null;

            var recentPages = RecentlyFoundPages;

            if (recentPages == null)
            {
                return(false);
            }

            var foundPage = recentPages.Find(key);

            if (foundPage == null)
            {
                return(false);
            }

            var lastFoundPageNumber = foundPage.Number;

            if (foundPage.Page != null)
            {
                // we can't share the same instance, Page instance may be modified by
                // concurrently run iterators
                page = new Page(foundPage.Page.Base, foundPage.Page.Source, foundPage.Page.PageSize);
            }
            else
            {
                page = _tx.GetReadOnlyPage(lastFoundPageNumber);
            }

            if (page.IsLeaf == false)
            {
                throw new DataException("Index points to a non leaf page");
            }

            node = page.Search(key); // will set the LastSearchPosition

            var cursorPath = foundPage.CursorPath;
            var pageCopy   = page;

            cursor = new Lazy <Cursor>(() =>
            {
                var c = new Cursor();
                foreach (var p in cursorPath)
                {
                    if (p == lastFoundPageNumber)
                    {
                        c.Push(pageCopy);
                    }
                    else
                    {
                        var cursorPage = _tx.GetReadOnlyPage(p);
                        if (key.Options == SliceOptions.BeforeAllKeys)
                        {
                            cursorPage.LastSearchPosition = 0;
                        }
                        else if (key.Options == SliceOptions.AfterAllKeys)
                        {
                            cursorPage.LastSearchPosition = (ushort)(cursorPage.NumberOfEntries - 1);
                        }
                        else if (cursorPage.Search(key) != null)
                        {
                            if (cursorPage.LastMatch != 0)
                            {
                                cursorPage.LastSearchPosition--;
                            }
                        }

                        c.Push(cursorPage);
                    }
                }

                return(c);
            });

            return(true);
        }
Example #16
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));
        }
        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));
        }