예제 #1
0
        private void MoveBranchNode(Page parentPage, Page from, Page to)
        {
            Debug.Assert(from.IsBranch);
            var originalFromKeyStart = GetActualKey(from, from.LastSearchPositionOrLastEntry);

            to.EnsureHasSpaceFor(_tx, originalFromKeyStart, -1);

            var  fromNode = from.GetNode(from.LastSearchPosition);
            long pageNum  = fromNode->PageNumber;

            if (to.LastSearchPosition == 0)
            {
                // cannot add to left implicit side, adjust by moving the left node
                // to the right by one, then adding the new one as the left

                var implicitLeftKey = GetActualKey(to, 0);
                var leftPageNumber  = to.GetNode(0)->PageNumber;
                to.AddPageRefNode(1, implicitLeftKey, leftPageNumber);
                to.AddPageRefNode(0, Slice.BeforeAllKeys, pageNum);
                to.RemoveNode(1);
            }
            else
            {
                to.AddPageRefNode(to.LastSearchPosition, originalFromKeyStart, pageNum);
            }

            if (from.LastSearchPositionOrLastEntry == 0)
            {
                // cannot just remove the left node, need to adjust those
                var rightPageNumber = from.GetNode(1)->PageNumber;
                from.RemoveNode(0); // remove the original implicit node
                from.RemoveNode(0); // remove the next node that we now turned into implicit
                from.EnsureHasSpaceFor(_tx, Slice.BeforeAllKeys, -1);
                from.AddPageRefNode(0, Slice.BeforeAllKeys, rightPageNumber);
                Debug.Assert(from.NumberOfEntries >= 2);
            }
            else
            {
                from.RemoveNode(from.LastSearchPositionOrLastEntry);
            }

            var pos = parentPage.LastSearchPositionOrLastEntry;

            parentPage.RemoveNode(pos);
            var newKey     = GetActualKey(to, 0); // get the next smallest key it has now
            var pageNumber = to.PageNumber;

            if (parentPage.GetNode(0)->PageNumber == to.PageNumber)
            {
                pageNumber = from.PageNumber;
                newKey     = GetActualKey(from, 0);
            }
            parentPage.EnsureHasSpaceFor(_tx, newKey, -1);
            parentPage.AddPageRefNode(pos, newKey, pageNumber);
        }
예제 #2
0
        private byte *AddSeparatorToParentPage(long pageNumber, MemorySlice seperatorKey, bool toRight, out Page parent)
        {
            var pos = _parentPage.NodePositionFor(seperatorKey); // select the appropriate place for this

            var separatorKeyToInsert = _parentPage.PrepareKeyToInsert(seperatorKey, pos);

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

                var posToInsert = pageSplitter.Execute();

                if (toRight == false && _cursor.CurrentPage.PageNumber != _parentPage.PageNumber)
                {
                    // _newKey being added to _page wasn't meant to be inserted to a newly created right page
                    // however the above page split has modified the cursor that its first page is a parent page for the right page containing separator key
                    // we need to ensure that the current _parentPage is first at the cursor

                    parent = _cursor.Pop();
                    _cursor.Push(_parentPage);
                }
                else
                {
                    parent = _parentPage;
                }

                return(posToInsert);
            }

            parent = _parentPage;

            return(_parentPage.AddPageRefNode(pos, separatorKeyToInsert, pageNumber));
        }
예제 #3
0
        private void MoveLeafNode(Page parentPage, Page from, Page to)
        {
            Debug.Assert(from.IsBranch == false);
            var originalFromKeyStart = GetActualKey(from, from.LastSearchPositionOrLastEntry);

            var   fromNode = from.GetNode(from.LastSearchPosition);
            byte *val      = @from.Base + @from.KeysOffsets[@from.LastSearchPosition] + Constants.NodeHeaderSize + originalFromKeyStart.Size;

            var nodeVersion = fromNode->Version;             // every time new node is allocated the version is increased, but in this case we do not want to increase it

            if (nodeVersion > 0)
            {
                nodeVersion -= 1;
            }

            byte *dataPos;

            switch (fromNode->Flags)
            {
            case NodeFlags.PageRef:
                to.EnsureHasSpaceFor(_tx, originalFromKeyStart, -1);
                dataPos = to.AddPageRefNode(to.LastSearchPosition, originalFromKeyStart, fromNode->PageNumber);
                break;

            case NodeFlags.Data:
                to.EnsureHasSpaceFor(_tx, originalFromKeyStart, fromNode->DataSize);
                dataPos = to.AddDataNode(to.LastSearchPosition, originalFromKeyStart, fromNode->DataSize, nodeVersion);
                break;

            case NodeFlags.MultiValuePageRef:
                to.EnsureHasSpaceFor(_tx, originalFromKeyStart, fromNode->DataSize);
                dataPos = to.AddMultiValueNode(to.LastSearchPosition, originalFromKeyStart, fromNode->DataSize, nodeVersion);
                break;

            default:
                throw new NotSupportedException("Invalid node type to move: " + fromNode->Flags);
            }

            if (dataPos != null)
            {
                NativeMethods.memcpy(dataPos, val, fromNode->DataSize);
            }

            from.RemoveNode(from.LastSearchPositionOrLastEntry);

            var pos = parentPage.LastSearchPositionOrLastEntry;

            parentPage.RemoveNode(pos);

            var newKey     = GetActualKey(to, 0); // get the next smallest key it has now
            var pageNumber = to.PageNumber;

            if (parentPage.GetNode(0)->PageNumber == to.PageNumber)
            {
                pageNumber = from.PageNumber;
                newKey     = GetActualKey(from, 0);
            }
            parentPage.EnsureHasSpaceFor(_tx, newKey, -1);
            parentPage.AddPageRefNode(pos, newKey, pageNumber);
        }
예제 #4
0
 private void AddSeparatorToParentPage(Page rightPage, Slice seperatorKey)
 {
     if (_parentPage.HasSpaceFor(_tx, SizeOf.BranchEntry(seperatorKey) + Constants.NodeOffsetSize) == false)
     {
         var pageSplitter = new PageSplitter(_tx, _tree, seperatorKey, -1, rightPage.PageNumber, NodeFlags.PageRef,
                                             0, _cursor, _treeState);
         pageSplitter.Execute();
     }
     else
     {
         _parentPage.NodePositionFor(seperatorKey); // select the appropriate place for this
         _parentPage.AddPageRefNode(_parentPage.LastSearchPosition, seperatorKey, rightPage.PageNumber);
     }
 }
예제 #5
0
        private void AddSeparatorToParentPage(Page parentPage, long pageNumber, MemorySlice seperatorKey, int separatorKeyPosition)
        {
            var separatorKeyToInsert = parentPage.PrepareKeyToInsert(seperatorKey, separatorKeyPosition);

            if (parentPage.HasSpaceFor(_tx, SizeOf.BranchEntry(separatorKeyToInsert) + Constants.NodeOffsetSize + SizeOf.NewPrefix(separatorKeyToInsert)) == false)
            {
                var pageSplitter = new PageSplitter(_tx, _tree, seperatorKey, -1, pageNumber, NodeFlags.PageRef,
                                                    0, _cursor, _tree.State);
                pageSplitter.Execute();
            }
            else
            {
                parentPage.AddPageRefNode(separatorKeyPosition, separatorKeyToInsert, pageNumber);
            }
        }
예제 #6
0
        private byte *AddSeparatorToParentPage(long pageNumber, MemorySlice seperatorKey)
        {
            var pos = _parentPage.NodePositionFor(seperatorKey);             // select the appropriate place for this

            var separatorKeyToInsert = _parentPage.PrepareKeyToInsert(seperatorKey, pos);

            if (_parentPage.HasSpaceFor(_tx, SizeOf.BranchEntry(separatorKeyToInsert) + Constants.NodeOffsetSize + SizeOf.NewPrefix(separatorKeyToInsert)) == false)
            {
                var pageSplitter = new PageSplitter(_tx, _tree, seperatorKey, -1, pageNumber, NodeFlags.PageRef,
                                                    0, _cursor, _treeState);
                return(pageSplitter.Execute());
            }

            return(_parentPage.AddPageRefNode(pos, separatorKeyToInsert, pageNumber));
        }
예제 #7
0
        private byte *AddNodeToPage(Page page, int index)
        {
            switch (_nodeType)
            {
            case NodeFlags.PageRef:
                return(page.AddPageRefNode(index, _newKey, _pageNumber));

            case NodeFlags.Data:
                return(page.AddDataNode(index, _newKey, _len, _nodeVersion));

            case NodeFlags.MultiValuePageRef:
                return(page.AddMultiValueNode(index, _newKey, _len, _nodeVersion));

            default:
                throw new NotSupportedException("Unknown node type");
            }
        }
예제 #8
0
파일: PageSplitter.cs 프로젝트: mow/ravendb
        private byte *AddNodeToPage(Page page, int index, MemorySlice alreadyPreparedNewKey = null)
        {
            var newKeyToInsert = alreadyPreparedNewKey ?? page.PrepareKeyToInsert(_newKey, index);

            switch (_nodeType)
            {
            case NodeFlags.PageRef:
                return(page.AddPageRefNode(index, newKeyToInsert, _pageNumber));

            case NodeFlags.Data:
                return(page.AddDataNode(index, newKeyToInsert, _len, _nodeVersion));

            case NodeFlags.MultiValuePageRef:
                return(page.AddMultiValueNode(index, newKeyToInsert, _len, _nodeVersion));

            default:
                throw new NotSupportedException("Unknown node type");
            }
        }
예제 #9
0
        private void MoveLeafNode(Page parentPage, Page from, Page to)
        {
            Debug.Assert(from.IsBranch == false);
            var originalFromKeyStart = GetActualKey(from, from.LastSearchPositionOrLastEntry);

            var fromNode = from.GetNode(from.LastSearchPosition);
			byte* val = @from.Base + @from.KeysOffsets[@from.LastSearchPosition] + Constants.NodeHeaderSize + originalFromKeyStart.Size;

			var nodeVersion = fromNode->Version; // every time new node is allocated the version is increased, but in this case we do not want to increase it
			if (nodeVersion > 0)
				nodeVersion -= 1;

	        var prefixedOriginalFromKey = to.PrepareKeyToInsert(originalFromKeyStart, to.LastSearchPosition);

	        byte* dataPos;
	        var fromDataSize = fromNode->DataSize;
	        switch (fromNode->Flags)
	        {
				case NodeFlags.PageRef:
					to.EnsureHasSpaceFor(_tx, prefixedOriginalFromKey, -1);
					dataPos = to.AddPageRefNode(to.LastSearchPosition, prefixedOriginalFromKey, fromNode->PageNumber);
					break;
				case NodeFlags.Data:
					to.EnsureHasSpaceFor(_tx, prefixedOriginalFromKey, fromDataSize);
					dataPos = to.AddDataNode(to.LastSearchPosition, prefixedOriginalFromKey, fromDataSize, nodeVersion);
					break;
				case NodeFlags.MultiValuePageRef:
					to.EnsureHasSpaceFor(_tx, prefixedOriginalFromKey, fromDataSize);
					dataPos = to.AddMultiValueNode(to.LastSearchPosition, prefixedOriginalFromKey, fromDataSize, nodeVersion);
					break;
				default:
			        throw new NotSupportedException("Invalid node type to move: " + fromNode->Flags);
	        }
			
			if(dataPos != null && fromDataSize > 0)
                Memory.Copy(dataPos, val, fromDataSize);
            
            from.RemoveNode(from.LastSearchPositionOrLastEntry);

            var pos = parentPage.LastSearchPositionOrLastEntry;
            parentPage.RemoveNode(pos);

            var newSeparatorKey = GetActualKey(to, 0); // get the next smallest key it has now
            var pageNumber = to.PageNumber;
            if (parentPage.GetNode(0)->PageNumber == to.PageNumber)
            {
                pageNumber = from.PageNumber;
                newSeparatorKey = GetActualKey(from, 0);
            }

			AddSeparatorToParentPage(parentPage, pageNumber, newSeparatorKey, pos);
        }
예제 #10
0
파일: PageSplitter.cs 프로젝트: mow/ravendb
        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));
        }
예제 #11
0
        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));
        }
예제 #12
0
        private void MoveBranchNode(Page parentPage, Page from, Page to)
        {
            Debug.Assert(from.IsBranch);
            var originalFromKeyStart = GetActualKey(from, from.LastSearchPositionOrLastEntry);

            to.EnsureHasSpaceFor(_tx, originalFromKeyStart, -1);

            var fromNode = from.GetNode(from.LastSearchPosition);
            long pageNum = fromNode->PageNumber;

            if (to.LastSearchPosition == 0)
            {
                // cannot add to left implicit side, adjust by moving the left node
                // to the right by one, then adding the new one as the left

                var implicitLeftKey = GetActualKey(to, 0);
                var leftPageNumber = to.GetNode(0)->PageNumber;
                to.AddPageRefNode(1, implicitLeftKey, leftPageNumber);
                to.AddPageRefNode(0, Slice.BeforeAllKeys, pageNum);
                to.RemoveNode(1);
            }
            else
            {
				to.AddPageRefNode(to.LastSearchPosition, originalFromKeyStart, pageNum);
            }

            if (from.LastSearchPositionOrLastEntry == 0)
            {
                // cannot just remove the left node, need to adjust those
                var rightPageNumber = from.GetNode(1)->PageNumber;
                from.RemoveNode(0); // remove the original implicit node
                from.RemoveNode(0); // remove the next node that we now turned into implicit
                from.EnsureHasSpaceFor(_tx, Slice.BeforeAllKeys, -1);
                from.AddPageRefNode(0, Slice.BeforeAllKeys, rightPageNumber);
                Debug.Assert(from.NumberOfEntries >= 2);
            }
            else
            {
                from.RemoveNode(from.LastSearchPositionOrLastEntry);
            }

            var pos = parentPage.LastSearchPositionOrLastEntry;
            parentPage.RemoveNode(pos);
            var newKey = GetActualKey(to, 0); // get the next smallest key it has now
            var pageNumber = to.PageNumber;
            if (parentPage.GetNode(0)->PageNumber == to.PageNumber)
            {
                pageNumber = from.PageNumber;
                newKey = GetActualKey(from, 0);
            }
            parentPage.EnsureHasSpaceFor(_tx, newKey, -1);
			parentPage.AddPageRefNode(pos, newKey, pageNumber);
        }
예제 #13
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);
        }
예제 #14
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));
            }
        }
예제 #15
0
		private void AddSeparatorToParentPage(Page parentPage, long pageNumber, MemorySlice seperatorKey, int separatorKeyPosition)
		{
			var separatorKeyToInsert = parentPage.PrepareKeyToInsert(seperatorKey, separatorKeyPosition);

			if (parentPage.HasSpaceFor(_tx, SizeOf.BranchEntry(separatorKeyToInsert) + Constants.NodeOffsetSize + SizeOf.NewPrefix(separatorKeyToInsert)) == false)
			{
				var pageSplitter = new PageSplitter(_tx, _tree, seperatorKey, -1, pageNumber, NodeFlags.PageRef,
					0, _cursor, _tree.State);
				pageSplitter.Execute();
			}
			else
			{
				parentPage.AddPageRefNode(separatorKeyPosition, separatorKeyToInsert, pageNumber);
			}
		}
예제 #16
0
        private void MoveBranchNode(Page parentPage, Page from, Page to)
        {
            Debug.Assert(from.IsBranch);

	        var originalFromKey = to.PrepareKeyToInsert(GetActualKey(from, from.LastSearchPositionOrLastEntry), to.LastSearchPosition);

            to.EnsureHasSpaceFor(_tx, originalFromKey, -1);

            var fromNode = from.GetNode(from.LastSearchPosition);
            long pageNum = fromNode->PageNumber;

            if (to.LastSearchPosition == 0)
            {
                // cannot add to left implicit side, adjust by moving the left node
                // to the right by one, then adding the new one as the left

	            NodeHeader* actualKeyNode;
                var implicitLeftKey = GetActualKey(to, 0, out actualKeyNode);
	            var implicitLeftNode = to.GetNode(0);
				var leftPageNumber = implicitLeftNode->PageNumber;

	            MemorySlice implicitLeftKeyToInsert;

	            if (implicitLeftNode == actualKeyNode)
	            {
					// no need to create a prefix, just use the existing prefixed key from the node
					// this also prevents from creating a prefix which is the full key given in 'implicitLeftKey'

		            if (_tree.KeysPrefixing)
			            implicitLeftKeyToInsert = new PrefixedSlice(actualKeyNode);
		            else
			            implicitLeftKeyToInsert = new Slice(actualKeyNode);
	            }
				else
					implicitLeftKeyToInsert = to.PrepareKeyToInsert(implicitLeftKey, 1);
	            
				to.EnsureHasSpaceFor(_tx, implicitLeftKeyToInsert, -1);
				to.AddPageRefNode(1, implicitLeftKeyToInsert, leftPageNumber);

				to.ChangeImplicitRefPageNode(pageNum); // setup the new implicit node
            }
            else
            {
				to.AddPageRefNode(to.LastSearchPosition, originalFromKey, pageNum);
            }

            if (from.LastSearchPositionOrLastEntry == 0)
            {
                var rightPageNumber = from.GetNode(1)->PageNumber;
                from.RemoveNode(0); // remove the original implicit node
                from.ChangeImplicitRefPageNode(rightPageNumber); // setup the new implicit node
                Debug.Assert(from.NumberOfEntries >= 2);
            }
            else
            {
                from.RemoveNode(from.LastSearchPositionOrLastEntry);
            }

            var pos = parentPage.LastSearchPositionOrLastEntry;
            parentPage.RemoveNode(pos);
            var newSeparatorKey = GetActualKey(to, 0); // get the next smallest key it has now
            var pageNumber = to.PageNumber;
            if (parentPage.GetNode(0)->PageNumber == to.PageNumber)
            {
                pageNumber = from.PageNumber;
                newSeparatorKey = GetActualKey(from, 0);
            }

			AddSeparatorToParentPage(parentPage, pageNumber, newSeparatorKey, pos);
        }
예제 #17
0
 private byte* AddNodeToPage(Page page, int index)
 {
     switch (_nodeType)
     {
         case NodeFlags.PageRef:
             return page.AddPageRefNode(index, _newKey, _pageNumber);
         case NodeFlags.Data:
             return page.AddDataNode(index, _newKey, _len, _nodeVersion);
         case NodeFlags.MultiValuePageRef:
             return page.AddMultiValueNode(index, _newKey, _len, _nodeVersion);
         default:
             throw new NotSupportedException("Unknown node type");
     }
 }
예제 #18
0
        private void MoveBranchNode(Page parentPage, Page from, Page to)
        {
            Debug.Assert(from.IsBranch);

            var originalFromKey = to.PrepareKeyToInsert(GetActualKey(from, from.LastSearchPositionOrLastEntry), to.LastSearchPosition);

            to.EnsureHasSpaceFor(_tx, originalFromKey, -1);

            var  fromNode = from.GetNode(from.LastSearchPosition);
            long pageNum  = fromNode->PageNumber;

            if (to.LastSearchPosition == 0)
            {
                // cannot add to left implicit side, adjust by moving the left node
                // to the right by one, then adding the new one as the left

                NodeHeader *actualKeyNode;
                var         implicitLeftKey  = GetActualKey(to, 0, out actualKeyNode);
                var         implicitLeftNode = to.GetNode(0);
                var         leftPageNumber   = implicitLeftNode->PageNumber;

                MemorySlice implicitLeftKeyToInsert;

                if (implicitLeftNode == actualKeyNode)
                {
                    // no need to create a prefix, just use the existing prefixed key from the node
                    // this also prevents from creating a prefix which is the full key given in 'implicitLeftKey'

                    if (_tree.KeysPrefixing)
                    {
                        implicitLeftKeyToInsert = new PrefixedSlice(actualKeyNode);
                    }
                    else
                    {
                        implicitLeftKeyToInsert = new Slice(actualKeyNode);
                    }
                }
                else
                {
                    implicitLeftKeyToInsert = to.PrepareKeyToInsert(implicitLeftKey, 1);
                }

                to.EnsureHasSpaceFor(_tx, implicitLeftKeyToInsert, -1);
                to.AddPageRefNode(1, implicitLeftKeyToInsert, leftPageNumber);

                to.ChangeImplicitRefPageNode(pageNum);                 // setup the new implicit node
            }
            else
            {
                to.AddPageRefNode(to.LastSearchPosition, originalFromKey, pageNum);
            }

            if (from.LastSearchPositionOrLastEntry == 0)
            {
                var rightPageNumber = from.GetNode(1)->PageNumber;
                from.RemoveNode(0);                              // remove the original implicit node
                from.ChangeImplicitRefPageNode(rightPageNumber); // setup the new implicit node
                Debug.Assert(from.NumberOfEntries >= 2);
            }
            else
            {
                from.RemoveNode(from.LastSearchPositionOrLastEntry);
            }

            var pos = parentPage.LastSearchPositionOrLastEntry;

            parentPage.RemoveNode(pos);
            var newSeparatorKey = GetActualKey(to, 0); // get the next smallest key it has now
            var pageNumber      = to.PageNumber;

            if (parentPage.GetNode(0)->PageNumber == to.PageNumber)
            {
                pageNumber      = from.PageNumber;
                newSeparatorKey = GetActualKey(from, 0);
            }

            AddSeparatorToParentPage(parentPage, pageNumber, newSeparatorKey, pos);
        }
예제 #19
0
        private byte* AddNodeToPage(Page page, int index, MemorySlice alreadyPreparedNewKey = null)
        {
	        var newKeyToInsert = alreadyPreparedNewKey ?? page.PrepareKeyToInsert(_newKey, index);

            switch (_nodeType)
            {
                case NodeFlags.PageRef:
					return page.AddPageRefNode(index, newKeyToInsert, _pageNumber);
                case NodeFlags.Data:
					return page.AddDataNode(index, newKeyToInsert, _len, _nodeVersion);
                case NodeFlags.MultiValuePageRef:
					return page.AddMultiValueNode(index, newKeyToInsert, _len, _nodeVersion);
                default:
                    throw new NotSupportedException("Unknown node type");
            }
        }