コード例 #1
0
ファイル: Page.cs プロジェクト: hillelskolnik/ravendb
        private void SetNodeKey(NodeHeader *node, ref PrefixedSlice slice)
        {
            if (node->KeySize == 0)
            {
                slice = PrefixedSlice.Empty;
                return;
            }

            if (slice != null && slice != PrefixedSlice.Empty)
            {
                slice.Set(node);
            }
            else
            {
                slice = new PrefixedSlice(node);
            }

            if (slice.Header.PrefixId == PrefixedSlice.NonPrefixedId)
            {
                Debug.Assert(slice.Header.PrefixUsage == 0);

                return;
            }

            Debug.Assert(slice.Header.PrefixId < PrefixCount);

            if (slice.Prefix == null)
            {
                slice.Prefix = new PrefixNode();
            }

            AssertPrefixNode(slice.Header.PrefixId);

            slice.Prefix.Set(_base + _prefixSection->PrefixOffsets[slice.Header.PrefixId], PageNumber);
        }
コード例 #2
0
ファイル: SizeOf.cs プロジェクト: j2jensen/ravendb
        public static int NewPrefix(PrefixedSlice key)
        {
            var size = Constants.PrefixNodeHeaderSize + key.NewPrefix.Size;
            size += size & 1;

            return size;
        }
コード例 #3
0
        public static int NewPrefix(PrefixedSlice key)
        {
            var size = Constants.PrefixNodeHeaderSize + key.NewPrefix.Size;

            size += size & 1;

            return(size);
        }
コード例 #4
0
ファイル: Page.cs プロジェクト: hillelskolnik/ravendb
        private bool TryUseExistingPrefix(MemorySlice key, out PrefixedSlice prefixedSlice)
        {
            if (_prefixSection->NextPrefixId < 1)
            {
                prefixedSlice = null;
                return(false);
            }

            var prefix = new PrefixNode();

            BestPrefixMatch bestMatch = null;

            for (byte prefixId = 0; prefixId < _prefixSection->NextPrefixId; prefixId++)
            {
                AssertPrefixNode(prefixId);

                prefix.Set(_base + _prefixSection->PrefixOffsets[prefixId], PageNumber);

                var length = key.FindPrefixSize(new Slice(prefix.ValuePtr, prefix.PrefixLength));
                if (length == 0)
                {
                    continue;
                }

                if (length == prefix.PrefixLength)                 // full prefix usage
                {
                    prefixedSlice = new PrefixedSlice(prefixId, length, key.Skip(length));
                    return(true);
                }

                // keep on looking for a better prefix

                if (bestMatch == null)
                {
                    bestMatch = new BestPrefixMatch
                    {
                        PrefixId    = prefixId,
                        PrefixUsage = length
                    };
                }
                else if (length > bestMatch.PrefixUsage)
                {
                    bestMatch.PrefixId    = prefixId;
                    bestMatch.PrefixUsage = length;
                }
            }

            if (bestMatch != null && bestMatch.PrefixUsage > MinPrefixLength(key))
            {
                prefixedSlice = new PrefixedSlice(bestMatch.PrefixId, bestMatch.PrefixUsage, key.Skip(bestMatch.PrefixUsage));
                return(true);
            }

            prefixedSlice = null;
            return(false);
        }
コード例 #5
0
ファイル: Page.cs プロジェクト: hillelskolnik/ravendb
        public MemorySlice GetNodeKey(NodeHeader *node)
        {
            if (KeysPrefixed == false)
            {
                var keySize = node->KeySize;
                var key     = new byte[keySize];

                fixed(byte *ptr = key)
                MemoryUtils.CopyInline(ptr, (byte *)node + Constants.NodeHeaderSize, keySize);

                return(new Slice(key));
            }

            if (node->KeySize == 0)
            {
                return(new PrefixedSlice(Slice.Empty));
            }

            var prefixHeader = (PrefixedSliceHeader *)((byte *)node + Constants.NodeHeaderSize);

            var nonPrefixedSize = prefixHeader->NonPrefixedDataSize;
            var nonPrefixedData = new byte[nonPrefixedSize];

            fixed(byte *ptr = nonPrefixedData)
            MemoryUtils.CopyInline(ptr, (byte *)prefixHeader + Constants.PrefixedSliceHeaderSize, nonPrefixedSize);

            var prefixedSlice = new PrefixedSlice(prefixHeader->PrefixId, prefixHeader->PrefixUsage, new Slice(nonPrefixedData));

            if (prefixHeader->PrefixId == PrefixedSlice.NonPrefixedId)
            {
                return(prefixedSlice);
            }

            AssertPrefixNode(prefixedSlice.Header.PrefixId);

            var prefixNodePtr = (PrefixNodeHeader *)(_base + _prefixSection->PrefixOffsets[prefixedSlice.Header.PrefixId]);

            var prefixLength = prefixNodePtr->PrefixLength;
            var prefixData   = new byte[prefixLength];

            fixed(byte *ptr = prefixData)
            MemoryUtils.CopyInline(ptr, (byte *)prefixNodePtr + Constants.PrefixNodeHeaderSize, prefixLength);

            prefixedSlice.Prefix = new PrefixNode(new PrefixNodeHeader {
                PrefixLength = prefixLength
            }, prefixData, PageNumber);

            return(prefixedSlice);
        }
コード例 #6
0
        private void MultiAddOnNewValue(Transaction tx, Slice key, Slice value, ushort?version, int maxNodeSize)
        {
            MemorySlice valueToInsert;

            if (KeysPrefixing)
            {
                valueToInsert = new PrefixedSlice(value); // first item is never prefixed
            }
            else
            {
                valueToInsert = value;
            }

            var requiredPageSize = Constants.PageHeaderSize +      // header of a nested page
                                   Constants.NodeOffsetSize +      // one node in a nested page
                                   SizeOf.LeafEntry(-1, value, 0); // node header and its value

            if (requiredPageSize + Constants.NodeHeaderSize > maxNodeSize)
            {
                // no choice, very big value, we might as well just put it in its own tree from the get go...
                // otherwise, we would have to put this in overflow page, and that won't save us any space anyway

                var tree = Create(tx, KeysPrefixing, TreeFlags.MultiValue);
                tree.DirectAdd(value, 0);
                tx.AddMultiValueTree(this, key, tree);

                DirectAdd(key, sizeof(TreeRootHeader), NodeFlags.MultiValuePageRef);
                return;
            }

            var actualPageSize = (ushort)Math.Min(Utils.NearestPowerOfTwo(requiredPageSize), maxNodeSize - Constants.NodeHeaderSize);

            var ptr = DirectAdd(key, actualPageSize);

            var nestedPage = new Page(ptr, "multi tree", actualPageSize)
            {
                PageNumber = -1L,// hint that this is an inner page
                Lower      = (ushort)Constants.PageHeaderSize,
                Upper      = KeysPrefixing ? (ushort)(actualPageSize - Constants.PrefixInfoSectionSize) : actualPageSize,
                Flags      = KeysPrefixing ? PageFlags.Leaf | PageFlags.KeysPrefixed : PageFlags.Leaf,
            };

            nestedPage.ClearPrefixInfo();

            CheckConcurrency(key, value, version, 0, TreeActionType.Add);

            nestedPage.AddDataNode(0, valueToInsert, 0, 0);
        }
コード例 #7
0
        public void SetNodeKey(NodeHeader *node, ref MemorySlice sliceInstance)
        {
            if (KeysPrefixed == false)
            {
                sliceInstance.Set(node);
                return;
            }

            if (node->KeySize == 0)
            {
                sliceInstance = PrefixedSlice.Empty;
                return;
            }

            PrefixedSlice prefixedSlice;

            if (sliceInstance != null && sliceInstance != PrefixedSlice.Empty)
            {
                sliceInstance.Set(node);
                prefixedSlice = (PrefixedSlice)sliceInstance;
            }
            else
            {
                sliceInstance = prefixedSlice = new PrefixedSlice(node);
            }

            if (prefixedSlice.Header.PrefixId == PrefixedSlice.NonPrefixedId)
            {
                Debug.Assert(prefixedSlice.Header.PrefixUsage == 0);

                return;
            }

            Debug.Assert(prefixedSlice.Header.PrefixId < PrefixCount);

            if (prefixedSlice.Prefix == null)
            {
                prefixedSlice.Prefix = new PrefixNode();
            }

            AssertPrefixNode(prefixedSlice.Header.PrefixId);

            prefixedSlice.Prefix.Set(_base + _prefixSection->PrefixOffsets[prefixedSlice.Header.PrefixId], PageNumber);
        }
コード例 #8
0
ファイル: Tree.MultiTree.cs プロジェクト: jesuslpm/ravendb
        private void MultiAddOnNewValue(Transaction tx, Slice key, Slice value, ushort? version, int maxNodeSize)
        {
            MemorySlice valueToInsert;

            if(KeysPrefixing)
                valueToInsert = new PrefixedSlice(value); // first item is never prefixed
            else
                valueToInsert = value;

            var requiredPageSize = Constants.PageHeaderSize + SizeOf.LeafEntry(-1, valueToInsert, 0) + Constants.NodeOffsetSize;
            if (requiredPageSize > maxNodeSize)
            {
                // no choice, very big value, we might as well just put it in its own tree from the get go...
                // otherwise, we would have to put this in overflow page, and that won't save us any space anyway

                var tree = Create(tx, KeysPrefixing, TreeFlags.MultiValue);
                tree.DirectAdd(value, 0);
                tx.AddMultiValueTree(this, key, tree);

                DirectAdd(key, sizeof (TreeRootHeader), NodeFlags.MultiValuePageRef);
                return;
            }

            var actualPageSize = (ushort) Math.Min(Utils.NearestPowerOfTwo(requiredPageSize), maxNodeSize);

            var ptr = DirectAdd(key, actualPageSize);

            var nestedPage = new Page(ptr, "multi tree", actualPageSize)
            {
                PageNumber = -1L,// hint that this is an inner page
                Lower = (ushort) Constants.PageHeaderSize,
                Upper = KeysPrefixing ? (ushort)(actualPageSize - Constants.PrefixInfoSectionSize) : actualPageSize,
                Flags = KeysPrefixing ? PageFlags.Leaf | PageFlags.KeysPrefixed : PageFlags.Leaf,
            };

            nestedPage.ClearPrefixInfo();

            CheckConcurrency(key, value, version, 0, TreeActionType.Add);

            nestedPage.AddDataNode(0, valueToInsert, 0, 0);
        }
コード例 #9
0
ファイル: Page.cs プロジェクト: hillelskolnik/ravendb
        private bool TryCreateNewPrefix(MemorySlice key, int nodeIndex, out PrefixedSlice prefixedSlice)
        {
            if (_prefixSection->NextPrefixId >= PrefixCount || NumberOfEntries == 0)
            {
                prefixedSlice = null;
                return(false);
            }

            MemorySlice left;
            MemorySlice right;

            if (nodeIndex > 0 && nodeIndex < NumberOfEntries)             // middle
            {
                left  = GetNodeKey(nodeIndex - 1);
                right = GetNodeKey(nodeIndex);
            }
            else if (nodeIndex == 0)             // first
            {
                left  = null;
                right = GetNodeKey(0);
            }
            else if (nodeIndex == NumberOfEntries)             // last
            {
                left  = GetNodeKey(nodeIndex - 1);
                right = null;
            }
            else
            {
                throw new NotSupportedException("Invalid node index prefix: " + nodeIndex + ". Number of entries: " + NumberOfEntries);
            }

            ushort leftLength  = 0;
            ushort rightLength = 0;

            if (left != null && left.Size > 0)             // not before all keys
            {
                leftLength = key.FindPrefixSize(left);
            }

            if (right != null)
            {
                rightLength = key.FindPrefixSize(right);
            }

            var minPrefixLength = MinPrefixLength(key);

            if (left != null && leftLength > minPrefixLength && leftLength > rightLength)
            {
                prefixedSlice = new PrefixedSlice(_prefixSection->NextPrefixId, leftLength, key.Skip(leftLength))
                {
                    NewPrefix = new Slice(left.ToSlice(), leftLength)
                };

                return(true);
            }

            if (right != null && rightLength > minPrefixLength && rightLength > leftLength)
            {
                prefixedSlice = new PrefixedSlice(_prefixSection->NextPrefixId, rightLength, key.Skip(rightLength))
                {
                    NewPrefix = new Slice(right.ToSlice(), rightLength)
                };

                return(true);
            }

            prefixedSlice = null;
            return(false);
        }
コード例 #10
0
ファイル: Page.cs プロジェクト: ricardobrandao/ravendb
        public MemorySlice GetNodeKey(NodeHeader* node)
        {
            if (KeysPrefixed == false)
            {
                var keySize = node->KeySize;
                var key = new byte[keySize];

                fixed (byte* ptr = key)
                    Memory.CopyInline(ptr, (byte*)node + Constants.NodeHeaderSize, keySize);

                return new Slice(key);
            }

            if (node->KeySize == 0)
                return new PrefixedSlice(Slice.Empty);

            var prefixHeader = (PrefixedSliceHeader*)((byte*)node + Constants.NodeHeaderSize);

            var nonPrefixedSize = prefixHeader->NonPrefixedDataSize;
            var nonPrefixedData = new byte[nonPrefixedSize];

            fixed (byte* ptr = nonPrefixedData)
                Memory.CopyInline(ptr, (byte*)prefixHeader + Constants.PrefixedSliceHeaderSize, nonPrefixedSize);

            var prefixedSlice = new PrefixedSlice(prefixHeader->PrefixId, prefixHeader->PrefixUsage, new Slice(nonPrefixedData));

            if (prefixHeader->PrefixId == PrefixedSlice.NonPrefixedId)
                return prefixedSlice;

            AssertPrefixNode(prefixedSlice.Header.PrefixId);

            var prefixNodePtr = (PrefixNodeHeader*) (_base + _prefixSection->PrefixOffsets[prefixedSlice.Header.PrefixId]);

            var prefixLength = prefixNodePtr->PrefixLength;
            var prefixData = new byte[prefixLength];

            fixed (byte* ptr = prefixData)
                Memory.CopyInline(ptr, (byte*)prefixNodePtr + Constants.PrefixNodeHeaderSize, prefixLength);

            prefixedSlice.Prefix = new PrefixNode(new PrefixNodeHeader{ PrefixLength =  prefixLength }, prefixData, PageNumber);

            return prefixedSlice;
        }
コード例 #11
0
ファイル: Page.cs プロジェクト: ricardobrandao/ravendb
        private bool TryCreateNewPrefix(MemorySlice key, int nodeIndex, out PrefixedSlice prefixedSlice)
        {
            if (_prefixSection->NextPrefixId >= PrefixCount || NumberOfEntries == 0)
            {
                prefixedSlice = null;
                return false;
            }

            MemorySlice left;
            MemorySlice right;

            if (nodeIndex > 0 && nodeIndex < NumberOfEntries) // middle
            {
                left = GetNodeKey(nodeIndex - 1);
                right = GetNodeKey(nodeIndex);
            }
            else if (nodeIndex == 0) // first
            {
                left = null;
                right = GetNodeKey(0);
            }
            else if (nodeIndex == NumberOfEntries) // last
            {
                left = GetNodeKey(nodeIndex - 1);
                right = null;
            }
            else
                throw new NotSupportedException("Invalid node index prefix: " + nodeIndex + ". Number of entries: " + NumberOfEntries);

            ushort leftLength = 0;
            ushort rightLength = 0;

            if (left != null && left.Size > 0) // not before all keys
                leftLength = key.FindPrefixSize(left);

            if (right != null)
                rightLength = key.FindPrefixSize(right);

            var minPrefixLength = MinPrefixLength(key);

            if (left != null && leftLength > minPrefixLength && leftLength > rightLength)
            {
                prefixedSlice = new PrefixedSlice(_prefixSection->NextPrefixId, leftLength, key.Skip(leftLength))
                {
                    NewPrefix = new Slice(left.ToSlice(), leftLength)
                };

                return true;
            }

            if (right != null && rightLength > minPrefixLength && rightLength > leftLength)
            {
                prefixedSlice = new PrefixedSlice(_prefixSection->NextPrefixId, rightLength, key.Skip(rightLength))
                {
                    NewPrefix = new Slice(right.ToSlice(), rightLength)
                };

                return true;
            }

            prefixedSlice = null;
            return false;
        }
コード例 #12
0
ファイル: PageSplitter.cs プロジェクト: felipeleusin/ravendb
        private int AdjustSplitPosition(int currentIndex, int splitIndex,
            ref bool newPosition)
        {
	        MemorySlice keyToInsert;

	        if (_tree.KeysPrefixing)
		        keyToInsert = new PrefixedSlice(_newKey); // let's assume that _newkey won't be prefixed to ensure the destination page will have enough space
	        else
		        keyToInsert = _newKey;

	        var pageSize = SizeOf.NodeEntry(AbstractPager.PageMaxSpace, keyToInsert , _len) + Constants.NodeOffsetSize;

			if(_tree.KeysPrefixing)
				pageSize += (Constants.PrefixNodeHeaderSize + 1); // let's assume that prefix will be created to ensure the destination page will have enough space, + 1 because prefix node might require 2-byte alignment

            if (currentIndex <= splitIndex)
            {
                newPosition = false;
                for (int i = 0; i < splitIndex; i++)
                {
                    NodeHeader* node = _page.GetNode(i);
                    pageSize += node->GetNodeSize();
                    pageSize += pageSize & 1;
                    if (pageSize > AbstractPager.PageMaxSpace)
                    {
                        if (i <= currentIndex)
                        {
                            if (i < currentIndex)
                                newPosition = true;
                            return currentIndex;
                        }
                        return (ushort) i;
                    }
                }
            }
            else
            {
                for (int i = _page.NumberOfEntries - 1; i >= splitIndex; i--)
                {
                    NodeHeader* node = _page.GetNode(i);
                    pageSize += node->GetNodeSize();
                    pageSize += pageSize & 1;
                    if (pageSize > AbstractPager.PageMaxSpace)
                    {
                        if (i >= currentIndex)
                        {
                            newPosition = false;
                            return currentIndex;
                        }
                        return (ushort) (i + 1);
                    }
                }
            }
            return splitIndex;
        }
コード例 #13
0
        /// <summary>
        ///     For leaf pages, check the split point based on what
        ///     fits where, since otherwise adding the node can fail.
        ///     This check is only needed when the data items are
        ///     relatively large, such that being off by one will
        ///     make the difference between success or failure.
        ///     It's also relevant if a page happens to be laid out
        ///     such that one half of its nodes are all "small" and
        ///     the other half of its nodes are "large." If the new
        ///     item is also "large" and falls on the half with
        ///     "large" nodes, it also may not fit.
        /// </summary>
        private int AdjustSplitPosition(int currentIndex, int splitIndex,
                                        ref bool newPosition)
        {
            MemorySlice keyToInsert;

            if (_tree.KeysPrefixing)
            {
                keyToInsert = new PrefixedSlice(_newKey);         // let's assume that _newkey won't be prefixed to ensure the destination page will have enough space
            }
            else
            {
                keyToInsert = _newKey;
            }

            int nodeSize = SizeOf.NodeEntry(AbstractPager.PageMaxSpace, keyToInsert, _len) + Constants.NodeOffsetSize;

            if (_page.NumberOfEntries >= 20 && nodeSize <= AbstractPager.PageMaxSpace / 16)
            {
                return(splitIndex);
            }

            int pageSize = nodeSize;

            if (_tree.KeysPrefixing)
            {
                pageSize += (Constants.PrefixNodeHeaderSize + 1);                 // let's assume that prefix will be created to ensure the destination page will have enough space, + 1 because prefix node might require 2-byte alignment
            }
            if (currentIndex <= splitIndex)
            {
                newPosition = false;
                for (int i = 0; i < splitIndex; i++)
                {
                    NodeHeader *node = _page.GetNode(i);
                    pageSize += node->GetNodeSize();
                    pageSize += pageSize & 1;
                    if (pageSize > AbstractPager.PageMaxSpace)
                    {
                        if (i <= currentIndex)
                        {
                            if (i < currentIndex)
                            {
                                newPosition = true;
                            }
                            return(currentIndex);
                        }
                        return((ushort)i);
                    }
                }
            }
            else
            {
                for (int i = _page.NumberOfEntries - 1; i >= splitIndex; i--)
                {
                    NodeHeader *node = _page.GetNode(i);
                    pageSize += node->GetNodeSize();
                    pageSize += pageSize & 1;
                    if (pageSize > AbstractPager.PageMaxSpace)
                    {
                        if (i >= currentIndex)
                        {
                            newPosition = false;
                            return(currentIndex);
                        }
                        return((ushort)(i + 1));
                    }
                }
            }
            return(splitIndex);
        }
コード例 #14
0
ファイル: PageSplitter.cs プロジェクト: VPashkov/ravendb
        private int AdjustSplitPosition(int currentIndex, int splitIndex, PrefixNode[] prefixes, ref bool toRight)
        {
	        MemorySlice keyToInsert;

	        int pageSize = 0;

	        if (_tree.KeysPrefixing)
			{
				keyToInsert = new PrefixedSlice(_newKey); // let's assume that _newkey won't match any of the existing prefixes

				pageSize += Constants.PrefixInfoSectionSize;
				pageSize += Constants.PrefixNodeHeaderSize + 1; // possible new prefix,  + 1 because of possible 2-byte alignment
			}
	        else
		        keyToInsert = _newKey;

	        pageSize += SizeOf.NodeEntry(AbstractPager.PageMaxSpace, keyToInsert , _len) + Constants.NodeOffsetSize;

			if (prefixes != null)
			{
				// we are going to copy all existing prefixes so we need to take into account their sizes
				for (var i = 0; i < prefixes.Length; i++)
				{
					var prefixNodeSize = Constants.PrefixNodeHeaderSize + prefixes[i].Header.PrefixLength;
					pageSize += prefixNodeSize + (prefixNodeSize & 1); // & 1 because we need 2-byte alignment
				}
			}

			if (toRight == false)
			{
				for (int i = 0; i < splitIndex; i++)
				{
					NodeHeader* node = _page.GetNode(i);
					pageSize += node->GetNodeSize();
					pageSize += pageSize & 1;
					if (pageSize > AbstractPager.PageMaxSpace)
					{
						if (i <= currentIndex)
						{
							if (i < currentIndex)
								toRight = true;
							return currentIndex;
						}
						return i;
					}
				}
			}
			else
			{
				for (int i = _page.NumberOfEntries - 1; i >= splitIndex; i--)
				{
					NodeHeader* node = _page.GetNode(i);
					pageSize += node->GetNodeSize();
					pageSize += pageSize & 1;
					if (pageSize > AbstractPager.PageMaxSpace)
					{
						if (i >= currentIndex)
						{
							toRight = false;
							return currentIndex;
						}
						return i + 1;
					}
				}
			}

            return splitIndex;
        }
コード例 #15
0
ファイル: Page.cs プロジェクト: felipeleusin/ravendb
	    public void SetNodeKey(NodeHeader* node, ref MemorySlice sliceInstance)
	    {
			if (KeysPrefixed == false)
			{
				sliceInstance.Set(node);
				return;
			}

			if (node->KeySize == 0)
			{
				sliceInstance = PrefixedSlice.Empty;
				return;
			}

			PrefixedSlice prefixedSlice;

			if (sliceInstance != null && sliceInstance != PrefixedSlice.Empty)
			{
				sliceInstance.Set(node);
				prefixedSlice = (PrefixedSlice)sliceInstance;
			}
			else
				sliceInstance = prefixedSlice = new PrefixedSlice(node);

			if (prefixedSlice.Header.PrefixId == PrefixedSlice.NonPrefixedId)
			{
				Debug.Assert(prefixedSlice.Header.PrefixUsage == 0);

				return;
			}

			Debug.Assert(prefixedSlice.Header.PrefixId < PrefixCount);

			if (prefixedSlice.Prefix == null)
				prefixedSlice.Prefix = new PrefixNode();

			AssertPrefixNode(prefixedSlice.Header.PrefixId);

			prefixedSlice.Prefix.Set(_base + _prefixSection->PrefixOffsets[prefixedSlice.Header.PrefixId], PageNumber);	   
	    }
コード例 #16
0
ファイル: TreeRebalancer.cs プロジェクト: VPashkov/ravendb
        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
ファイル: Page.cs プロジェクト: ricardobrandao/ravendb
        private bool TryUseExistingPrefix(MemorySlice key, out PrefixedSlice prefixedSlice)
        {
            if (_prefixSection->NextPrefixId < 1)
            {
                prefixedSlice = null;
                return false;
            }

            BestPrefixMatch bestMatch = null;

            for (byte prefixId = 0; prefixId < _prefixSection->NextPrefixId; prefixId++)
            {
                AssertPrefixNode(prefixId);

                var prefix = new PrefixNode();

                prefix.Set(_base + _prefixSection->PrefixOffsets[prefixId], PageNumber);

                var length = key.FindPrefixSize(new Slice(prefix.ValuePtr, prefix.PrefixLength));
                if (length == 0)
                    continue;

                if (length == prefix.PrefixLength) // full prefix usage
                {
                    prefixedSlice = new PrefixedSlice(prefixId, length, key.Skip(length))
                    {
                        Prefix = prefix
                    };
                    return true;
                }

                // keep on looking for a better prefix

                if (bestMatch == null)
                {
                    bestMatch = new BestPrefixMatch
                    {
                        PrefixId = prefixId,
                        PrefixUsage = length,
                        PrefixNode = prefix
                    };
                }
                else if (length > bestMatch.PrefixUsage)
                {
                    bestMatch.PrefixId = prefixId;
                    bestMatch.PrefixUsage = length;
                    bestMatch.PrefixNode = prefix;
                }
            }

            if (bestMatch != null && bestMatch.PrefixUsage > MinPrefixLength(key))
            {
                prefixedSlice = new PrefixedSlice(bestMatch.PrefixId, bestMatch.PrefixUsage, key.Skip(bestMatch.PrefixUsage))
                {
                    Prefix = bestMatch.PrefixNode
                };
                return true;
            }

            prefixedSlice = null;
            return false;
        }
コード例 #18
0
ファイル: PageSplitter.cs プロジェクト: jrusbatch/ravendb
        private int AdjustSplitPosition(int currentIndex, int splitIndex, PrefixNode[] prefixes, ref bool newPosition)
        {
	        MemorySlice keyToInsert;

	        if (_tree.KeysPrefixing)
		        keyToInsert = new PrefixedSlice(_newKey); // let's assume that _newkey won't be prefixed to ensure the destination page will have enough space
	        else
		        keyToInsert = _newKey;

	        var pageSize = SizeOf.NodeEntry(AbstractPager.PageMaxSpace, keyToInsert , _len) + Constants.NodeOffsetSize;

			if (prefixes != null)
			{
				// we are going to copy all existing prefixes so we need to take into account their sizes
				for (var i = 0; i < prefixes.Length; i++)
				{
					pageSize += (Constants.PrefixNodeHeaderSize + prefixes[i].Header.PrefixLength) & 1; // & 1 because we need 2-byte alignment
				}
			}

            if (currentIndex <= splitIndex)
            {
                newPosition = false;
                for (int i = 0; i < splitIndex; i++)
                {
                    NodeHeader* node = _page.GetNode(i);
                    pageSize += node->GetNodeSize();
                    pageSize += pageSize & 1;
                    if (pageSize > AbstractPager.PageMaxSpace)
                    {
                        if (i <= currentIndex)
                        {
                            if (i < currentIndex)
                                newPosition = true;
                            return currentIndex;
                        }
                        return (ushort) i;
                    }
                }
            }
            else
            {
                for (int i = _page.NumberOfEntries - 1; i >= splitIndex; i--)
                {
                    NodeHeader* node = _page.GetNode(i);
                    pageSize += node->GetNodeSize();
                    pageSize += pageSize & 1;
                    if (pageSize > AbstractPager.PageMaxSpace)
                    {
                        if (i >= currentIndex)
                        {
                            newPosition = false;
                            return currentIndex;
                        }
                        return (ushort) (i + 1);
                    }
                }
            }
            return splitIndex;
        }
コード例 #19
0
ファイル: Page.cs プロジェクト: ricardobrandao/ravendb
        private void SetNodeKey(NodeHeader* node, ref PrefixedSlice slice)
        {
            if (node->KeySize == 0)
            {
                slice = PrefixedSlice.Empty;
                return;
            }

            if (slice != null && slice != PrefixedSlice.Empty)
            {
                slice.Set(node);
            }
            else
            {
                slice = new PrefixedSlice(node);
            }

            if (slice.Header.PrefixId == PrefixedSlice.NonPrefixedId)
            {
                Debug.Assert(slice.Header.PrefixUsage == 0);

                return;
            }

            Debug.Assert(slice.Header.PrefixId < PrefixCount);

            if (slice.Prefix == null)
                slice.Prefix = new PrefixNode();

            AssertPrefixNode(slice.Header.PrefixId);

            slice.Prefix.Set(_base + _prefixSection->PrefixOffsets[slice.Header.PrefixId], PageNumber);
        }
コード例 #20
0
ファイル: PageSplitter.cs プロジェクト: mow/ravendb
        private int AdjustSplitPosition(int currentIndex, int splitIndex, PrefixNode[] prefixes, ref bool toRight)
        {
            MemorySlice keyToInsert;

            int pageSize = 0;

            if (_tree.KeysPrefixing)
            {
                keyToInsert = new PrefixedSlice(_newKey); // let's assume that _newkey won't match any of the existing prefixes

                pageSize += Constants.PrefixInfoSectionSize;
                pageSize += Constants.PrefixNodeHeaderSize + 1; // possible new prefix,  + 1 because of possible 2-byte alignment
            }
            else
            {
                keyToInsert = _newKey;
            }

            pageSize += SizeOf.NodeEntry(AbstractPager.PageMaxSpace, keyToInsert, _len) + Constants.NodeOffsetSize;

            if (prefixes != null)
            {
                // we are going to copy all existing prefixes so we need to take into account their sizes
                for (var i = 0; i < prefixes.Length; i++)
                {
                    var prefixNodeSize = Constants.PrefixNodeHeaderSize + prefixes[i].Header.PrefixLength;
                    pageSize += prefixNodeSize + (prefixNodeSize & 1); // & 1 because we need 2-byte alignment
                }
            }

            if (toRight == false)
            {
                for (int i = 0; i < splitIndex; i++)
                {
                    NodeHeader *node = _page.GetNode(i);
                    pageSize += node->GetNodeSize();
                    pageSize += pageSize & 1;
                    if (pageSize > AbstractPager.PageMaxSpace)
                    {
                        if (i <= currentIndex)
                        {
                            if (i < currentIndex)
                            {
                                toRight = true;
                            }
                            return(currentIndex);
                        }
                        return(i);
                    }
                }
            }
            else
            {
                for (int i = _page.NumberOfEntries - 1; i >= splitIndex; i--)
                {
                    NodeHeader *node = _page.GetNode(i);
                    pageSize += node->GetNodeSize();
                    pageSize += pageSize & 1;
                    if (pageSize > AbstractPager.PageMaxSpace)
                    {
                        if (i >= currentIndex)
                        {
                            toRight = false;
                            return(currentIndex);
                        }
                        return(i + 1);
                    }
                }
            }

            return(splitIndex);
        }
コード例 #21
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);
        }
コード例 #22
0
        private int AdjustSplitPosition(int currentIndex, int splitIndex, PrefixNode[] prefixes, ref bool newPosition)
        {
            MemorySlice keyToInsert;

            if (_tree.KeysPrefixing)
            {
                keyToInsert = new PrefixedSlice(_newKey);         // let's assume that _newkey won't be prefixed to ensure the destination page will have enough space
            }
            else
            {
                keyToInsert = _newKey;
            }

            var pageSize = SizeOf.NodeEntry(AbstractPager.PageMaxSpace, keyToInsert, _len) + Constants.NodeOffsetSize;

            if (prefixes != null)
            {
                // we are going to copy all existing prefixes so we need to take into account their sizes
                for (var i = 0; i < prefixes.Length; i++)
                {
                    pageSize += (Constants.PrefixNodeHeaderSize + prefixes[i].Header.PrefixLength) & 1;                     // & 1 because we need 2-byte alignment
                }
            }

            if (currentIndex <= splitIndex)
            {
                newPosition = false;
                for (int i = 0; i < splitIndex; i++)
                {
                    NodeHeader *node = _page.GetNode(i);
                    pageSize += node->GetNodeSize();
                    pageSize += pageSize & 1;
                    if (pageSize > AbstractPager.PageMaxSpace)
                    {
                        if (i <= currentIndex)
                        {
                            if (i < currentIndex)
                            {
                                newPosition = true;
                            }
                            return(currentIndex);
                        }
                        return((ushort)i);
                    }
                }
            }
            else
            {
                for (int i = _page.NumberOfEntries - 1; i >= splitIndex; i--)
                {
                    NodeHeader *node = _page.GetNode(i);
                    pageSize += node->GetNodeSize();
                    pageSize += pageSize & 1;
                    if (pageSize > AbstractPager.PageMaxSpace)
                    {
                        if (i >= currentIndex)
                        {
                            newPosition = false;
                            return(currentIndex);
                        }
                        return((ushort)(i + 1));
                    }
                }
            }
            return(splitIndex);
        }