예제 #1
0
        private bool HasEnoughSpaceToCopyNodes(Page left, Page right)
        {
            var actualSpaceNeeded      = 0;
            var previousSearchPosition = right.LastSearchPosition;

            for (int i = 0; i < right.NumberOfEntries; i++)
            {
                right.LastSearchPosition = i;
                var key  = GetActualKey(right, right.LastSearchPositionOrLastEntry);
                var node = right.GetNode(i);
                actualSpaceNeeded += (SizeOf.NodeEntryWithAnotherKey(node, key) + Constants.NodeOffsetSize);
            }

            right.LastSearchPosition = previousSearchPosition;         //previous position --> prevent mutation of parameter
            return(left.HasSpaceFor(_tx, actualSpaceNeeded));
        }
예제 #2
0
        /// <summary>
        /// Internal method that is used when splitting pages
        /// No need to do any work here, we are always adding at the end
        /// </summary>
        internal void CopyNodeDataToEndOfPage(NodeHeader *other, MemorySlice key)
        {
            var index = NumberOfEntries;

            Debug.Assert(HasSpaceFor(SizeOf.NodeEntryWithAnotherKey(other, key) + Constants.NodeOffsetSize + SizeOf.NewPrefix(key)));

            var nodeSize = SizeOf.NodeEntryWithAnotherKey(other, key);

            Debug.Assert(IsBranch == false || index != 0 || key.KeyLength == 0); // branch page's first item must be the implicit ref

            var nodeVersion = other->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 prefixedKey = key as PrefixedSlice;

            if (prefixedKey != null && prefixedKey.NewPrefix != null)
            {
                WritePrefix(prefixedKey.NewPrefix, prefixedKey.Header.PrefixId);
            }

            var newNode = AllocateNewNode(index, nodeSize, nodeVersion);

            newNode->KeySize = key.Size;
            newNode->Flags   = other->Flags;

            if (key.Options == SliceOptions.Key && key.Size > 0)
            {
                key.CopyTo((byte *)newNode + Constants.NodeHeaderSize);
            }

            if (IsBranch || other->Flags == (NodeFlags.PageRef))
            {
                newNode->PageNumber = other->PageNumber;
                newNode->Flags      = NodeFlags.PageRef;
                return;
            }
            newNode->DataSize = other->DataSize;
            MemoryUtils.Copy((byte *)newNode + Constants.NodeHeaderSize + key.Size,
                             (byte *)other + Constants.NodeHeaderSize + other->KeySize,
                             other->DataSize);
        }
예제 #3
0
파일: Page.cs 프로젝트: stvoidmain/ravendb
        /// <summary>
        /// Internal method that is used when splitting pages
        /// No need to do any work here, we are always adding at the end
        /// </summary>
        internal void CopyNodeDataToEndOfPage(NodeHeader *other, Slice key = null)
        {
            var nodeKey = key ?? new Slice(other);

            Debug.Assert(HasSpaceFor(SizeOf.NodeEntryWithAnotherKey(other, nodeKey) + Constants.NodeOffsetSize));

            var index = NumberOfEntries;

            var nodeSize = SizeOf.NodeEntryWithAnotherKey(other, nodeKey);


            if (other->KeySize == 0 && key == null)             // when copy first item from branch which is implicit ref
            {
                nodeSize += nodeKey.Size;
            }

            Debug.Assert(IsBranch == false || index != 0 || nodeKey.Size == 0); // branch page's first item must be the implicit ref

            var nodeVersion = other->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 newNode = AllocateNewNode(index, nodeKey, nodeSize, nodeVersion);

            newNode->Flags = other->Flags;
            nodeKey.CopyTo((byte *)newNode + Constants.NodeHeaderSize);

            if (IsBranch || other->Flags == (NodeFlags.PageRef))
            {
                newNode->PageNumber = other->PageNumber;
                newNode->Flags      = NodeFlags.PageRef;
                return;
            }
            newNode->DataSize = other->DataSize;
            NativeMethods.memcpy((byte *)newNode + Constants.NodeHeaderSize + other->KeySize,
                                 (byte *)other + Constants.NodeHeaderSize + other->KeySize,
                                 other->DataSize);
        }
예제 #4
0
        private bool TryMergePages(Page parentPage, Page left, Page right)
        {
            TemporaryPage tmp;

            using (_tx.Environment.GetTemporaryPage(_tx, out tmp))
            {
                var mergedPage = tmp.GetTempPage(left.KeysPrefixed);
                Memory.Copy(mergedPage.Base, left.Base, left.PageSize);

                var previousSearchPosition = right.LastSearchPosition;

                for (int i = 0; i < right.NumberOfEntries; i++)
                {
                    right.LastSearchPosition = i;
                    var key  = GetActualKey(right, right.LastSearchPositionOrLastEntry);
                    var node = right.GetNode(i);

                    var prefixedKey = mergedPage.PrepareKeyToInsert(key, mergedPage.NumberOfEntries);

                    if (mergedPage.HasSpaceFor(_tx, SizeOf.NodeEntryWithAnotherKey(node, prefixedKey) + Constants.NodeOffsetSize + SizeOf.NewPrefix(prefixedKey)) == false)
                    {
                        right.LastSearchPosition = previousSearchPosition;                         //previous position --> prevent mutation of parameter
                        return(false);
                    }

                    mergedPage.CopyNodeDataToEndOfPage(node, prefixedKey);
                }

                Memory.Copy(left.Base, mergedPage.Base, left.PageSize);
            }

            parentPage.RemoveNode(parentPage.LastSearchPositionOrLastEntry);             // unlink the right sibling
            _tree.FreePage(right);

            return(true);
        }