public bool MovePrev() { while (true) { _currentPage.LastSearchPosition--; if (_currentPage.LastSearchPosition >= 0) { // run out of entries, need to select the next page... while (_currentPage.IsBranch) { _cursor.Push(_currentPage); var node = _currentPage.GetNode(_currentPage.LastSearchPosition); _currentPage = _tx.GetReadOnlyPage(node->PageNumber); _currentPage.LastSearchPosition = _currentPage.NumberOfEntries - 1; } var current = _currentPage.GetNode(_currentPage.LastSearchPosition); if (this.ValidateCurrentKey(current, _currentPage) == false) { return(false); } _currentPage.SetNodeKey(current, ref _currentInternalKey); _currentKey = _currentInternalKey.ToSlice(); return(true); // there is another entry in this page } if (_cursor.PageCount == 0) { break; } _currentPage = _cursor.Pop(); } _currentPage = null; return(false); }
private void RemoveBranchWithOneEntry(Page page, Page parentPage) { Debug.Assert(page.NumberOfEntries == 1); var pageRefNumber = page.GetNode(0)->PageNumber; NodeHeader *nodeHeader = null; for (int i = 0; i < parentPage.NumberOfEntries; i++) { nodeHeader = parentPage.GetNode(i); if (nodeHeader->PageNumber == page.PageNumber) { break; } } Debug.Assert(nodeHeader->PageNumber == page.PageNumber, string.Format("Node page number: {0}, page number: {1}", nodeHeader->PageNumber, page.PageNumber)); nodeHeader->PageNumber = pageRefNumber; if (_cursor.CurrentPage.PageNumber == page.PageNumber) { _cursor.Pop(); _cursor.Push(_tx.GetReadOnlyPage(pageRefNumber)); } _tree.FreePage(page); }
public bool Seek(Slice key) { _currentPage = _tree.FindPageFor(_tx, key, _cursor); _cursor.Pop(); var node = _currentPage.Search(key, _cmp); if (node == null) { return(false); } _currentKey.Set(node); return(this.ValidateCurrentKey(Current, _cmp)); }
public PageSplitter(Transaction tx, Tree tree, SliceComparer cmp, Slice newKey, int len, long pageNumber, NodeFlags nodeType, ushort nodeVersion, Cursor cursor, TreeMutableState treeState) { _tx = tx; _tree = tree; _cmp = cmp; _newKey = newKey; _len = len; _pageNumber = pageNumber; _nodeType = nodeType; _nodeVersion = nodeVersion; _cursor = cursor; _treeState = treeState; Page page = _cursor.Pages.First.Value; _page = tx.ModifyPage(page.PageNumber, page); _cursor.Pop(); }
public PageSplitter(Transaction tx, Tree tree, SliceComparer cmp, Slice newKey, int len, long pageNumber, NodeFlags nodeType, ushort nodeVersion, Cursor cursor, TreeMutableState treeState) { _tx = tx; _tree = tree; _cmp = cmp; _newKey = newKey; _len = len; _pageNumber = pageNumber; _nodeType = nodeType; _nodeVersion = nodeVersion; _cursor = cursor; _treeState = treeState; Page page = _cursor.Pages.First.Value; _page = tx.ModifyPage(page.PageNumber, page); _cursor.Pop(); }
private void RebalanceRoot(Cursor cursor, Page page) { if (page.NumberOfEntries == 0) { return; // nothing to do } if (!page.IsBranch || page.NumberOfEntries > 1) { return; // cannot do anything here } // in this case, we have a root pointer with just one pointer, we can just swap it out var node = page.GetNode(0); Debug.Assert(node->Flags == (NodeFlags.PageRef)); _tree.State.LeafPages = 1; _tree.State.BranchPages = 0; _tree.State.Depth = 1; _tree.State.PageCount = 1; var rootPage = _tx.ModifyPage(node->PageNumber, null); _tree.State.RootPageNumber = rootPage.PageNumber; Debug.Assert(rootPage.Dirty); cursor.Pop(); cursor.Push(rootPage); _tx.FreePage(page.PageNumber); }
public bool Seek(Slice key) { if (_disposed) { throw new ObjectDisposedException("TreeIterator " + _tree.Name); } Lazy <Cursor> lazy; NodeHeader * node; _currentPage = _tree.FindPageFor(key, out node, out lazy); _cursor = lazy.Value; _cursor.Pop(); if (node != null) { _currentPage.SetNodeKey(node, ref _currentInternalKey); _currentKey = _currentInternalKey.ToSlice(); return(this.ValidateCurrentKey(Current, _currentPage)); } // The key is not found in the db, but we are Seek()ing for equals or starts with. // We know that the exact value isn't there, but it is possible that the next page has values // that is actually greater than the key, so we need to check it as well. _currentPage.LastSearchPosition = _currentPage.NumberOfEntries; // force next MoveNext to move to the next _page_. return(MoveNext()); }
public bool MovePrev() { if (_disposed) { throw new ObjectDisposedException("TreeIterator " + _tree.Name); } while (true) { _currentPage.LastSearchPosition--; if (_currentPage.LastSearchPosition >= 0) { // run out of entries, need to select the next page... while (_currentPage.IsBranch) { _cursor.Push(_currentPage); var node = _currentPage.GetNode(_currentPage.LastSearchPosition); _currentPage = _tx.GetReadOnlyPage(node->PageNumber); _currentPage.LastSearchPosition = _currentPage.NumberOfEntries - 1; if (_prefetch && _currentPage.IsLeaf) { MaybePrefetchOverflowPages(_currentPage); } } var current = _currentPage.GetNode(_currentPage.LastSearchPosition); if (this.ValidateCurrentKey(current, _currentPage) == false) { return(false); } _currentPage.SetNodeKey(current, ref _currentInternalKey); _currentKey = _currentInternalKey.ToSlice(); return(true);// there is another entry in this page } if (_cursor.PageCount == 0) { break; } _currentPage = _cursor.Pop(); } _currentPage = null; return(false); }
public PageSplitter(Transaction tx, SliceComparer cmp, Slice newKey, int len, long pageNumber, Cursor cursor, TreeDataInTransaction txInfo) { _tx = tx; _cmp = cmp; _newKey = newKey; _len = len; _pageNumber = pageNumber; _cursor = cursor; _txInfo = txInfo; _page = _cursor.Pop(); }
public bool Seek(Slice key) { Lazy<Cursor> lazy; _currentPage = _tree.FindPageFor(_tx, key, out lazy); _cursor = lazy.Value; _cursor.Pop(); var node = _currentPage.Search(key, _cmp); if (node == null) { return false; } _currentKey.Set(node); return this.ValidateCurrentKey(Current, _cmp); }
public bool Seek(Slice key) { Lazy<Cursor> lazy; _currentPage = _tree.FindPageFor(key, out lazy); _cursor = lazy.Value; _cursor.Pop(); var node = _currentPage.Search(key); if (node != null) { _currentKey.Set(node); return this.ValidateCurrentKey(Current); } // The key is not found in the db, but we are Seek()ing for equals or starts with. // We know that the exact value isn't there, but it is possible that the next page has values // that is actually greater than the key, so we need to check it as well. _currentPage.LastSearchPosition = _currentPage.NumberOfEntries; // force next MoveNext to move to the next _page_. return MoveNext(); }
public PageSplitter(Transaction tx, Tree tree, MemorySlice newKey, int len, long pageNumber, NodeFlags nodeType, ushort nodeVersion, Cursor cursor) { _tx = tx; _tree = tree; _newKey = newKey; _len = len; _pageNumber = pageNumber; _nodeType = nodeType; _nodeVersion = nodeVersion; _cursor = cursor; Page page = _cursor.Pages.First.Value; _page = tx.ModifyPage(page.PageNumber, _tree, page); _cursor.Pop(); }
public bool Seek(Slice key) { Lazy <Cursor> lazy; _currentPage = _tree.FindPageFor(key, out lazy); _cursor = lazy.Value; _cursor.Pop(); var node = _currentPage.Search(key); if (node != null) { _currentKey.Set(node); return(this.ValidateCurrentKey(Current)); } // The key is not found in the db, but we are Seek()ing for equals or starts with. // We know that the exact value isn't there, but it is possible that the next page has values // that is actually greater than the key, so we need to check it as well. _currentPage.LastSearchPosition = _currentPage.NumberOfEntries; // force next MoveNext to move to the next _page_. return(MoveNext()); }
public Page Execute(Cursor cursor, Page page) { _tx.ClearRecentFoundPages(_tree); if (cursor.PageCount <= 1) // the root page { RebalanceRoot(cursor, page); return null; } var parentPage = _tx.ModifyPage(cursor.ParentPage.PageNumber, cursor.ParentPage); cursor.Update(cursor.Pages.First.Next, parentPage); if (page.NumberOfEntries == 0) // empty page, just delete it and fixup parent { // need to delete the implicit left page, shift right if (parentPage.LastSearchPosition == 0 && parentPage.NumberOfEntries > 2) { var newImplicit = parentPage.GetNode(1)->PageNumber; parentPage.RemoveNode(0); parentPage.RemoveNode(0); parentPage.AddPageRefNode(0, Slice.Empty, newImplicit); } else // will be set to rights by the next rebalance call { parentPage.RemoveNode(parentPage.LastSearchPositionOrLastEntry); } _tx.FreePage(page.PageNumber); cursor.Pop(); return parentPage; } var minKeys = page.IsBranch ? 2 : 1; if ((page.UseMoreSizeThan(_tx.DataPager.PageMinSpace)) && page.NumberOfEntries >= minKeys) return null; // above space/keys thresholds Debug.Assert(parentPage.NumberOfEntries >= 2); // if we have less than 2 entries in the parent, the tree is invalid var sibling = SetupMoveOrMerge(cursor, page, parentPage); Debug.Assert(sibling.PageNumber != page.PageNumber); minKeys = sibling.IsBranch ? 2 : 1; // branch must have at least 2 keys if (sibling.UseMoreSizeThan(_tx.DataPager.PageMinSpace) && sibling.NumberOfEntries > minKeys) { // neighbor is over the min size and has enough key, can move just one key to the current page if (page.IsBranch) { MoveBranchNode(parentPage, sibling, page); } else MoveLeafNode(parentPage, sibling, page); cursor.Pop(); return parentPage; } if (page.LastSearchPosition == 0) // this is the right page, merge left { if (!HasEnoughSpaceToCopyNodes(sibling, page)) return null; MergePages(parentPage, sibling, page); } else // this is the left page, merge right { if (!HasEnoughSpaceToCopyNodes(page, sibling)) return null; MergePages(parentPage, page, sibling); } cursor.Pop(); return parentPage; }
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); }
public Page Execute(Cursor cursor, Page page) { if (cursor.PageCount <= 1) // the root page { RebalanceRoot(cursor, _txInfo, page); return(null); } var parentPage = cursor.ParentPage; if (page.NumberOfEntries == 0) // empty page, just delete it and fixup parent { // need to delete the implicit left page, shift right if (parentPage.LastSearchPosition == 0 && parentPage.NumberOfEntries > 2) { var newImplicit = parentPage.GetNode(1)->PageNumber; parentPage.AddNode(0, Slice.Empty, -1, newImplicit); parentPage.RemoveNode(1); parentPage.RemoveNode(1); } else // will be set to rights by the next rebalance call { parentPage.RemoveNode(parentPage.LastSearchPosition); } cursor.Pop(); return(parentPage); } var minKeys = page.IsBranch ? 2 : 1; if (page.SizeUsed >= _tx.Pager.PageMinSpace && page.NumberOfEntries >= minKeys) { return(null); // above space/keys thresholds } Debug.Assert(parentPage.NumberOfEntries >= 2); // if we have less than 2 entries in the parent, the tree is invalid var sibling = SetupMoveOrMerge(cursor, page, parentPage); Debug.Assert(sibling.PageNumber != page.PageNumber); minKeys = sibling.IsBranch ? 2 : 1; // branch must have at least 2 keys if (sibling.SizeUsed > _tx.Pager.PageMinSpace && sibling.NumberOfEntries > minKeys) { // neighbor is over the min size and has enough key, can move just one key to the current page if (page.IsBranch) { MoveBranchNode(parentPage, sibling, page); } else { MoveLeafNode(parentPage, sibling, page); } cursor.Pop(); return(parentPage); } if (page.LastSearchPosition == 0) // this is the right page, merge left { MergePages(parentPage, sibling, page); } else // this is the left page, merge right { MergePages(parentPage, page, sibling); } cursor.Pop(); return(parentPage); }
private byte *SplitPageInHalf(Page rightPage) { bool toRight; var currentIndex = _page.LastSearchPosition; var splitIndex = _page.NumberOfEntries / 2; if (currentIndex <= splitIndex) { toRight = false; } else { toRight = true; var leftPageEntryCount = splitIndex; var rightPageEntryCount = _page.NumberOfEntries - leftPageEntryCount + 1; if (rightPageEntryCount > leftPageEntryCount) { splitIndex++; Debug.Assert(splitIndex < _page.NumberOfEntries); } } PrefixNode[] prefixes = null; if (_tree.KeysPrefixing && _page.HasPrefixes) { prefixes = _page.GetPrefixes(); } if (_page.IsLeaf || prefixes != null) { splitIndex = AdjustSplitPosition(currentIndex, splitIndex, prefixes, ref toRight); } var currentKey = _page.GetNodeKey(splitIndex); MemorySlice seperatorKey; if (toRight && splitIndex == currentIndex) { seperatorKey = currentKey.Compare(_newKey) < 0 ? currentKey : _newKey; } else { seperatorKey = currentKey; } Page parentOfRight; AddSeparatorToParentPage(rightPage.PageNumber, seperatorKey, out parentOfRight); var parentOfPage = _cursor.CurrentPage; MemorySlice instance = _page.CreateNewEmptyKey(); if (prefixes != null) { for (int i = 0; i < prefixes.Length; i++) { var prefix = prefixes[i]; rightPage.WritePrefix(new Slice(prefix.ValuePtr, prefix.PrefixLength), i); } } bool addedAsImplicitRef = false; if (_page.IsBranch && toRight && seperatorKey == _newKey) { // _newKey needs to be inserted as first key (BeforeAllKeys) to the right page, so we need to add it before we move entries from the current page AddNodeToPage(rightPage, 0, _tree.KeysPrefixing ? (MemorySlice)PrefixedSlice.BeforeAllKeys : Slice.BeforeAllKeys); addedAsImplicitRef = true; } // move the actual entries from page to right page ushort nKeys = _page.NumberOfEntries; for (int i = splitIndex; i < nKeys; i++) { NodeHeader *node = _page.GetNode(i); if (_page.IsBranch && rightPage.NumberOfEntries == 0) { rightPage.CopyNodeDataToEndOfPage(node, _tree.KeysPrefixing ? (MemorySlice)PrefixedSlice.BeforeAllKeys : Slice.BeforeAllKeys); } else { _page.SetNodeKey(node, ref instance); var key = rightPage.PrepareKeyToInsert(instance, rightPage.NumberOfEntries); rightPage.CopyNodeDataToEndOfPage(node, key); } } _page.Truncate(_tx, splitIndex); byte *pos; if (addedAsImplicitRef == false) { try { if (toRight && _cursor.CurrentPage.PageNumber != parentOfRight.PageNumber) { // modify the cursor if we are going to insert to the right page _cursor.Pop(); _cursor.Push(parentOfRight); } // actually insert the new key pos = toRight ? InsertNewKey(rightPage) : InsertNewKey(_page); } catch (InvalidOperationException e) { if (e.Message.StartsWith("The page is full and cannot add an entry") == false) { throw; } throw new InvalidOperationException(GatherDetailedDebugInfo(rightPage, currentKey, seperatorKey, currentIndex, splitIndex, toRight), e); } } else { pos = null; _cursor.Push(rightPage); } if (_page.IsBranch) // remove a branch that has only one entry, the page ref needs to be added to the parent of the current page { Debug.Assert(_page.NumberOfEntries > 0); Debug.Assert(rightPage.NumberOfEntries > 0); if (_page.NumberOfEntries == 1) { RemoveBranchWithOneEntry(_page, parentOfPage); } if (rightPage.NumberOfEntries == 1) { RemoveBranchWithOneEntry(rightPage, parentOfRight); } } return(pos); }
public Page Execute(Page page) { _tree.ClearRecentFoundPages(); if (_cursor.PageCount <= 1) // the root page { RebalanceRoot(page); return(null); } var parentPage = _tx.ModifyPage(_cursor.ParentPage.PageNumber, _tree, _cursor.ParentPage); _cursor.Update(_cursor.Pages.First.Next, parentPage); if (page.NumberOfEntries == 0) // empty page, just delete it and fixup parent { // need to change the implicit left page if (parentPage.LastSearchPosition == 0 && parentPage.NumberOfEntries > 2) { var newImplicit = parentPage.GetNode(1)->PageNumber; parentPage.RemoveNode(0); parentPage.ChangeImplicitRefPageNode(newImplicit); } else // will be set to rights by the next rebalance call { parentPage.RemoveNode(parentPage.LastSearchPositionOrLastEntry); } _tree.FreePage(page); _cursor.Pop(); return(parentPage); } if (page.IsBranch && page.NumberOfEntries == 1) { RemoveBranchWithOneEntry(page, parentPage); _cursor.Pop(); return(parentPage); } var minKeys = page.IsBranch ? 2 : 1; if ((page.UseMoreSizeThan(_tx.DataPager.PageMinSpace)) && page.NumberOfEntries >= minKeys) { return(null); // above space/keys thresholds } Debug.Assert(parentPage.NumberOfEntries >= 2); // if we have less than 2 entries in the parent, the tree is invalid var sibling = SetupMoveOrMerge(page, parentPage); Debug.Assert(sibling.PageNumber != page.PageNumber); if (page.Flags != sibling.Flags) { return(null); } minKeys = sibling.IsBranch ? 2 : 1; // branch must have at least 2 keys if (sibling.UseMoreSizeThan(_tx.DataPager.PageMinSpace) && sibling.NumberOfEntries > minKeys) { _cursor.Pop(); // neighbor is over the min size and has enough key, can move just one key to the current page if (page.IsBranch) { MoveBranchNode(parentPage, sibling, page); } else { MoveLeafNode(parentPage, sibling, page); } return(parentPage); } if (page.LastSearchPosition == 0) // this is the right page, merge left { if (TryMergePages(parentPage, sibling, page) == false) { return(null); } } else // this is the left page, merge right { if (TryMergePages(parentPage, page, sibling) == false) { return(null); } } _cursor.Pop(); return(parentPage); }
private void RebalanceRoot(Cursor cursor, Page page) { if (page.NumberOfEntries == 0) return; // nothing to do if (!page.IsBranch || page.NumberOfEntries > 1) { return; // cannot do anything here } // in this case, we have a root pointer with just one pointer, we can just swap it out var node = page.GetNode(0); Debug.Assert(node->Flags == (NodeFlags.PageRef)); _tree.State.LeafPages = 1; _tree.State.BranchPages = 0; _tree.State.Depth = 1; _tree.State.PageCount = 1; var rootPage = _tx.ModifyPage(node->PageNumber, null); _tree.State.RootPageNumber = rootPage.PageNumber; Debug.Assert(rootPage.Dirty); cursor.Pop(); cursor.Push(rootPage); _tx.FreePage(page.PageNumber); }