Beispiel #1
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);
        }
Beispiel #2
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);
            }
        }
Beispiel #3
0
 public int GetRequiredSpace(MemorySlice key, int len)
 {
     return(SizeOf.NodeEntry(PageMaxSpace, key, len) + Constants.NodeOffsetSize + SizeOf.NewPrefix(key));
 }
Beispiel #4
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);
        }
Beispiel #5
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);
            }
        }
Beispiel #6
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));
        }
Beispiel #7
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);
        }