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)); }
private byte *InsertNewKey(Page p) { int pos = p.NodePositionFor(_newKey); byte *dataPos = AddNodeToPage(p, pos); _cursor.Push(p); return(dataPos); }
private byte *InsertNewKey(Page p) { var pos = p.NodePositionFor(_newKey, _cmp); var dataPos = p.AddNode(pos, _newKey, _len, _pageNumber); _cursor.Push(p); IncrementItemCountIfNecessary(); return(dataPos); }
private void AddSeperatorToParentPage(Page rightPage, Slice seperatorKey) { if (_parentPage.SizeLeft < SizeOf.BranchEntry(seperatorKey) + Constants.NodeOffsetSize) { new PageSplitter(_tx, _cmp, seperatorKey, -1, rightPage.PageNumber, _cursor, _txInfo).Execute(); } else { _parentPage.NodePositionFor(seperatorKey, _cmp); // select the appropriate place for this _parentPage.AddNode(_parentPage.LastSearchPosition, seperatorKey, -1, rightPage.PageNumber); } }
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); } }
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)); }
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); }
private bool TryUseRecentTransactionPage(Transaction tx, Slice key, out Lazy<Cursor> cursor, out Page page) { page = null; cursor = null; var recentPages = tx.GetRecentlyFoundPages(this); if (recentPages == null) return false; var foundPage = recentPages.Find(key); if (foundPage == null) return false; var lastFoundPageNumber = foundPage.Number; page = tx.GetReadOnlyPage(lastFoundPageNumber); if (page.IsLeaf == false) throw new DataException("Index points to a non leaf page"); page.NodePositionFor(key, _cmp); // will set the LastSearchPosition var cursorPath = foundPage.CursorPath; var pageCopy = page; cursor = new Lazy<Cursor>(() => { var c = new Cursor(); foreach (var p in cursorPath) { if (p == lastFoundPageNumber) c.Push(pageCopy); else { var cursorPage = tx.GetReadOnlyPage(p); if (key.Options == SliceOptions.BeforeAllKeys) { cursorPage.LastSearchPosition = 0; } else if (key.Options == SliceOptions.AfterAllKeys) { cursorPage.LastSearchPosition = (ushort)(cursorPage.NumberOfEntries - 1); } else if (cursorPage.Search(key, _cmp) != null) { if (cursorPage.LastMatch != 0) { cursorPage.LastSearchPosition--; } } c.Push(cursorPage); } } return c; }); return true; }
public byte *Execute() { Page rightPage = _tree.NewPage(_page.Flags, 1); if (_cursor.PageCount == 0) // we need to do a root split { Page newRootPage = _tree.NewPage(_tree.KeysPrefixing ? PageFlags.Branch | PageFlags.KeysPrefixed : PageFlags.Branch, 1); _cursor.Push(newRootPage); _treeState.RootPageNumber = newRootPage.PageNumber; _treeState.Depth++; // now add implicit left page newRootPage.AddPageRefNode(0, _tree.KeysPrefixing ? (MemorySlice)PrefixedSlice.BeforeAllKeys : Slice.BeforeAllKeys, _page.PageNumber); _parentPage = newRootPage; _parentPage.LastSearchPosition++; } else { // we already popped the page, so the current one on the stack is the parent of the page if (_tree.Name == Constants.FreeSpaceTreeName) { // a special case for FreeSpaceTree because the allocation of a new page called above // can cause a delete of a free space section resulting in a run of the tree rebalancer // and here the parent page that exists in cursor can be outdated _parentPage = _tx.ModifyPage(_cursor.CurrentPage.PageNumber, _tree, null); // pass _null_ to make sure we'll get the most updated parent page _parentPage.LastSearchPosition = _cursor.CurrentPage.LastSearchPosition; _parentPage.LastMatch = _cursor.CurrentPage.LastMatch; } else { _parentPage = _tx.ModifyPage(_cursor.CurrentPage.PageNumber, _tree, _cursor.CurrentPage); } _cursor.Update(_cursor.Pages.First, _parentPage); } if (_page.IsLeaf) { _tree.ClearRecentFoundPages(); } if (_tree.Name == Constants.FreeSpaceTreeName) { // we need to refresh the LastSearchPosition of the split page which is used by the free space handling // because the allocation of a new page called above could remove some sections // from the page that is being split _page.NodePositionFor(_newKey); } if (_page.LastSearchPosition >= _page.NumberOfEntries) { // when we get a split at the end of the page, we take that as a hint that the user is doing // sequential inserts, at that point, we are going to keep the current page as is and create a new // page, this will allow us to do minimal amount of work to get the best density Page branchOfSeparator; byte *pos; if (_page.IsBranch) { if (_page.NumberOfEntries > 2) { // here we steal the last entry from the current page so we maintain the implicit null left entry NodeHeader *node = _page.GetNode(_page.NumberOfEntries - 1); Debug.Assert(node->Flags == NodeFlags.PageRef); rightPage.AddPageRefNode(0, _tree.KeysPrefixing ? (MemorySlice)PrefixedSlice.BeforeAllKeys : Slice.BeforeAllKeys, node->PageNumber); pos = AddNodeToPage(rightPage, 1); var separatorKey = _page.GetNodeKey(node); AddSeparatorToParentPage(rightPage.PageNumber, separatorKey, out branchOfSeparator); _page.RemoveNode(_page.NumberOfEntries - 1); } else { _tree.FreePage(rightPage); // return the unnecessary right page pos = AddSeparatorToParentPage(_pageNumber, _newKey, out branchOfSeparator); if (_cursor.CurrentPage.PageNumber != branchOfSeparator.PageNumber) { _cursor.Push(branchOfSeparator); } return(pos); } } else { AddSeparatorToParentPage(rightPage.PageNumber, _newKey, out branchOfSeparator); pos = AddNodeToPage(rightPage, 0); } _cursor.Push(rightPage); return(pos); } return(SplitPageInHalf(rightPage)); }
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; }
private byte* InsertNewKey(Page p) { int pos = p.NodePositionFor(_newKey); byte* dataPos = AddNodeToPage(p, pos); _cursor.Push(p); return dataPos; }
private bool TryUseRecentTransactionPage(Slice key, out Lazy <Cursor> cursor, out Page page) { page = null; cursor = null; var recentPages = _tx.GetRecentlyFoundPages(this); if (recentPages == null) { return(false); } var foundPage = recentPages.Find(key); if (foundPage == null) { return(false); } var lastFoundPageNumber = foundPage.Number; page = _tx.GetReadOnlyPage(lastFoundPageNumber); if (page.IsLeaf == false) { throw new DataException("Index points to a non leaf page"); } page.NodePositionFor(key); // will set the LastSearchPosition var cursorPath = foundPage.CursorPath; var pageCopy = page; cursor = new Lazy <Cursor>(() => { var c = new Cursor(); foreach (var p in cursorPath) { if (p == lastFoundPageNumber) { c.Push(pageCopy); } else { var cursorPage = _tx.GetReadOnlyPage(p); if (key.Options == SliceOptions.BeforeAllKeys) { cursorPage.LastSearchPosition = 0; } else if (key.Options == SliceOptions.AfterAllKeys) { cursorPage.LastSearchPosition = (ushort)(cursorPage.NumberOfEntries - 1); } else if (cursorPage.Search(key) != null) { if (cursorPage.LastMatch != 0) { cursorPage.LastSearchPosition--; } } c.Push(cursorPage); } } return(c); }); return(true); }
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); }