예제 #1
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));
        }
예제 #2
0
파일: Tree.cs 프로젝트: ppekrol/raven.voron
        internal byte *DirectAdd(Transaction tx, Slice key, int len)
        {
            if (tx.Flags == (TransactionFlags.ReadWrite) == false)
            {
                throw new ArgumentException("Cannot add a value in a read only transaction");
            }

            if (key.Size > tx.Pager.MaxNodeSize)
            {
                throw new ArgumentException("Key size is too big, must be at most " + tx.Pager.MaxNodeSize + " bytes, but was " + key.Size, "key");
            }


            using (var cursor = tx.NewCursor(this))
            {
                var txInfo = tx.GetTreeInformation(this);

                FindPageFor(tx, key, cursor);

                var page = tx.ModifyCursor(this, cursor);

                if (page.LastMatch == 0) // this is an update operation
                {
                    RemoveLeafNode(tx, cursor, page);
                }
                else // new item should be recorded
                {
                    txInfo.State.EntriesCount++;
                }

                var   lastSearchPosition = page.LastSearchPosition; // searching for overflow pages might change this
                byte *overFlowPos        = null;
                var   pageNumber         = -1L;
                if (ShouldGoToOverflowPage(tx, len))
                {
                    pageNumber = WriteToOverflowPages(tx, txInfo, len, out overFlowPos);
                    len        = -1;
                }

                byte *dataPos;
                if (page.HasSpaceFor(key, len) == false)
                {
                    var pageSplitter = new PageSplitter(tx, _cmp, key, len, pageNumber, cursor, txInfo);
                    dataPos = pageSplitter.Execute();
                    DebugValidateTree(tx, txInfo.RootPageNumber);
                }
                else
                {
                    dataPos = page.AddNode(lastSearchPosition, key, len, pageNumber);
                    cursor.IncrementItemCount();
                    page.DebugValidate(tx, _cmp, txInfo.RootPageNumber);
                }
                if (overFlowPos != null)
                {
                    return(overFlowPos);
                }
                return(dataPos);
            }
        }
예제 #3
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;
        }
예제 #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
파일: PageSplitter.cs 프로젝트: mow/ravendb
        private byte *InsertNewKey(Page p)
        {
            int pos = p.NodePositionFor(_newKey);

            var newKeyToInsert = p.PrepareKeyToInsert(_newKey, pos);

            if (p.HasSpaceFor(_tx, p.GetRequiredSpace(newKeyToInsert, _len)) == false)
            {
                _cursor.Push(p);

                var pageSplitter = new PageSplitter(_tx, _tree, _newKey, _len, _pageNumber, _nodeType, _nodeVersion, _cursor, _treeState);

                return(pageSplitter.Execute());
            }

            byte *dataPos = AddNodeToPage(p, pos, newKeyToInsert);

            _cursor.Push(p);
            return(dataPos);
        }
예제 #8
0
        internal byte *DirectAdd(MemorySlice key, int len, NodeFlags nodeType = NodeFlags.Data, ushort?version = null)
        {
            Debug.Assert(nodeType == NodeFlags.Data || nodeType == NodeFlags.MultiValuePageRef);

            if (_tx.Flags == (TransactionFlags.ReadWrite) == false)
            {
                throw new ArgumentException("Cannot add a value in a read only transaction");
            }

            if (key.Size + Constants.NodeHeaderSize > AbstractPager.NodeMaxSize)
            {
                throw new ArgumentException(
                          "Key size is too big, must be at most " + (AbstractPager.NodeMaxSize - Constants.NodeHeaderSize) + " bytes, but was " + key.Size, "key");
            }

            Lazy <Cursor> lazy;
            NodeHeader *  node;
            var           foundPage = FindPageFor(key, out node, out lazy);

            var page = _tx.ModifyPage(foundPage.PageNumber, this, foundPage);

            ushort nodeVersion            = 0;
            bool?  shouldGoToOverflowPage = null;

            if (page.LastMatch == 0) // this is an update operation
            {
                node = page.GetNode(page.LastSearchPosition);

                Debug.Assert(page.GetNodeKey(node).Equals(key));

                shouldGoToOverflowPage = _tx.DataPager.ShouldGoToOverflowPage(len);

                byte *pos;
                if (shouldGoToOverflowPage == false)
                {
                    // optimization for Data and MultiValuePageRef - try to overwrite existing node space
                    if (TryOverwriteDataOrMultiValuePageRefNode(node, key, len, nodeType, version, out pos))
                    {
                        return(pos);
                    }
                }
                else
                {
                    // optimization for PageRef - try to overwrite existing overflows
                    if (TryOverwriteOverflowPages(State, node, key, len, version, out pos))
                    {
                        return(pos);
                    }
                }

                RemoveLeafNode(page, out nodeVersion);
            }
            else // new item should be recorded
            {
                State.EntriesCount++;
            }

            CheckConcurrency(key, version, nodeVersion, TreeActionType.Add);

            var   lastSearchPosition = page.LastSearchPosition; // searching for overflow pages might change this
            byte *overFlowPos        = null;
            var   pageNumber         = -1L;

            if (shouldGoToOverflowPage ?? _tx.DataPager.ShouldGoToOverflowPage(len))
            {
                pageNumber = WriteToOverflowPages(State, len, out overFlowPos);
                len        = -1;
                nodeType   = NodeFlags.PageRef;
            }

            var keyToInsert = page.PrepareKeyToInsert(key, lastSearchPosition);

            byte *dataPos;

            if (page.HasSpaceFor(_tx, keyToInsert, len) == false)
            {
                var cursor = lazy.Value;
                cursor.Update(cursor.Pages.First, page);

                var pageSplitter = new PageSplitter(_tx, this, key, len, pageNumber, nodeType, nodeVersion, cursor, State);
                dataPos = pageSplitter.Execute();

                DebugValidateTree(State.RootPageNumber);
            }
            else
            {
                switch (nodeType)
                {
                case NodeFlags.PageRef:
                    dataPos = page.AddPageRefNode(lastSearchPosition, keyToInsert, pageNumber);
                    break;

                case NodeFlags.Data:
                    dataPos = page.AddDataNode(lastSearchPosition, keyToInsert, len, nodeVersion);
                    break;

                case NodeFlags.MultiValuePageRef:
                    dataPos = page.AddMultiValueNode(lastSearchPosition, keyToInsert, len, nodeVersion);
                    break;

                default:
                    throw new NotSupportedException("Unknown node type for direct add operation: " + nodeType);
                }
                page.DebugValidate(_tx, State.RootPageNumber);
            }
            if (overFlowPos != null)
            {
                return(overFlowPos);
            }
            return(dataPos);
        }
예제 #9
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);
			}
		}
예제 #10
0
파일: Tree.cs 프로젝트: paulcbetts/ravendb
		internal byte* DirectAdd(Transaction tx, Slice key, int len, NodeFlags nodeType = NodeFlags.Data, ushort? version = null)
		{
			Debug.Assert(nodeType == NodeFlags.Data || nodeType == NodeFlags.MultiValuePageRef);

			if (tx.Flags == (TransactionFlags.ReadWrite) == false)
				throw new ArgumentException("Cannot add a value in a read only transaction");

			if (key.Size > tx.DataPager.MaxNodeSize)
				throw new ArgumentException(
					"Key size is too big, must be at most " + tx.DataPager.MaxNodeSize + " bytes, but was " + key.Size, "key");

			Lazy<Cursor> lazy;
			var foundPage = FindPageFor(tx, key, out lazy);

			var page = tx.ModifyPage(foundPage.PageNumber, foundPage);

			ushort nodeVersion = 0;
			bool? shouldGoToOverflowPage = null;
			if (page.LastMatch == 0) // this is an update operation
			{
				var node = page.GetNode(page.LastSearchPosition);

				Debug.Assert(node->KeySize == key.Size && new Slice(node).Equals(key));

				shouldGoToOverflowPage = tx.DataPager.ShouldGoToOverflowPage(len);

				byte* pos;
				if (shouldGoToOverflowPage == false)
				{
					// optimization for Data and MultiValuePageRef - try to overwrite existing node space
					if (TryOverwriteDataOrMultiValuePageRefNode(node, key, len, nodeType, version, out pos))
						return pos;
				}
				else
				{
					// optimization for PageRef - try to overwrite existing overflows
					if (TryOverwriteOverflowPages(tx, State, node, key, len, version, out pos))
						return pos;
				}

				RemoveLeafNode(tx, page, out nodeVersion);
			}
			else // new item should be recorded
			{
				State.EntriesCount++;
			}

			CheckConcurrency(key, version, nodeVersion, TreeActionType.Add);

			var lastSearchPosition = page.LastSearchPosition; // searching for overflow pages might change this
			byte* overFlowPos = null;
			var pageNumber = -1L;
			if (shouldGoToOverflowPage ?? tx.DataPager.ShouldGoToOverflowPage(len))
			{
				pageNumber = WriteToOverflowPages(tx, State, len, out overFlowPos);
				len = -1;
				nodeType = NodeFlags.PageRef;
			}

			byte* dataPos;
			if (page.HasSpaceFor(tx, key, len) == false)
			{
			    var cursor = lazy.Value;
			    cursor.Update(cursor.Pages.First, page);
			    
			    var pageSplitter = new PageSplitter(tx, this, _cmp, key, len, pageNumber, nodeType, nodeVersion, cursor, State);
			    dataPos = pageSplitter.Execute();

			    DebugValidateTree(tx, State.RootPageNumber);
			}
			else
			{
				switch (nodeType)
				{
					case NodeFlags.PageRef:
						dataPos = page.AddPageRefNode(lastSearchPosition, key, pageNumber);
						break;
					case NodeFlags.Data:
						dataPos = page.AddDataNode(lastSearchPosition, key, len, nodeVersion);
						break;
					case NodeFlags.MultiValuePageRef:
						dataPos = page.AddMultiValueNode(lastSearchPosition, key, len, nodeVersion);
						break;
					default:
						throw new NotSupportedException("Unknown node type for direct add operation: " + nodeType);
				}
				page.DebugValidate(tx, _cmp, State.RootPageNumber);
			}
			if (overFlowPos != null)
				return overFlowPos;
			return dataPos;
		}
예제 #11
0
        private void AddSeparatorToParentPage(long pageNumber, MemorySlice seperatorKey)
        {
	        var separatorKeyToInsert = _parentPage.PrepareKeyToInsert(seperatorKey, _parentPage.LastSearchPosition);

			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);
                pageSplitter.Execute();
            }
            else
            {
                _parentPage.NodePositionFor(seperatorKey); // select the appropriate place for this
				_parentPage.AddPageRefNode(_parentPage.LastSearchPosition, separatorKeyToInsert, pageNumber);
            }
        }
예제 #12
0
        private byte* InsertNewKey(Page p)
        {
            int pos = p.NodePositionFor(_newKey);

			var newKeyToInsert = p.PrepareKeyToInsert(_newKey, pos);

			if (p.HasSpaceFor(_tx, p.GetRequiredSpace(newKeyToInsert, _len)) == false)
			{
				_cursor.Push(p);

				var pageSplitter = new PageSplitter(_tx, _tree, _newKey, _len, _pageNumber, _nodeType, _nodeVersion, _cursor, _treeState);

				return pageSplitter.Execute();
			}

            byte* dataPos = AddNodeToPage(p, pos, newKeyToInsert);
            _cursor.Push(p);
            return dataPos;
        }
예제 #13
0
 private void AddSeparatorToParentPage(Page rightPage, Slice seperatorKey)
 {
     if (_parentPage.HasSpaceFor(_tx ,SizeOf.BranchEntry(seperatorKey) + Constants.NodeOffsetSize) == false)
     {
         var pageSplitter = new PageSplitter(_tx, _tree, _cmp, seperatorKey, -1, rightPage.PageNumber, NodeFlags.PageRef,
             0, _cursor, _treeState);
         pageSplitter.Execute();
     }
     else
     {
         _parentPage.NodePositionFor(seperatorKey, _cmp); // select the appropriate place for this
         _parentPage.AddPageRefNode(_parentPage.LastSearchPosition, seperatorKey, rightPage.PageNumber);
     }
 }
예제 #14
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);
        }
예제 #15
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);
        }