private void MoveBranchNode(Page parentPage, Page from, Page to) { Debug.Assert(from.IsBranch); var originalFromKeyStart = GetActualKey(from, from.LastSearchPositionOrLastEntry); to.EnsureHasSpaceFor(_tx, originalFromKeyStart, -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 var implicitLeftKey = GetActualKey(to, 0); var leftPageNumber = to.GetNode(0)->PageNumber; to.AddPageRefNode(1, implicitLeftKey, leftPageNumber); to.AddPageRefNode(0, Slice.BeforeAllKeys, pageNum); to.RemoveNode(1); } else { to.AddPageRefNode(to.LastSearchPosition, originalFromKeyStart, pageNum); } if (from.LastSearchPositionOrLastEntry == 0) { // cannot just remove the left node, need to adjust those var rightPageNumber = from.GetNode(1)->PageNumber; from.RemoveNode(0); // remove the original implicit node from.RemoveNode(0); // remove the next node that we now turned into implicit from.EnsureHasSpaceFor(_tx, Slice.BeforeAllKeys, -1); from.AddPageRefNode(0, Slice.BeforeAllKeys, rightPageNumber); Debug.Assert(from.NumberOfEntries >= 2); } else { from.RemoveNode(from.LastSearchPositionOrLastEntry); } var pos = parentPage.LastSearchPositionOrLastEntry; parentPage.RemoveNode(pos); var newKey = 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; newKey = GetActualKey(from, 0); } parentPage.EnsureHasSpaceFor(_tx, newKey, -1); parentPage.AddPageRefNode(pos, newKey, pageNumber); }
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 void MoveLeafNode(Page parentPage, Page from, Page to) { Debug.Assert(from.IsBranch == false); var originalFromKeyStart = GetActualKey(from, from.LastSearchPositionOrLastEntry); var fromNode = from.GetNode(from.LastSearchPosition); byte *val = @from.Base + @from.KeysOffsets[@from.LastSearchPosition] + Constants.NodeHeaderSize + originalFromKeyStart.Size; var nodeVersion = fromNode->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; } byte *dataPos; switch (fromNode->Flags) { case NodeFlags.PageRef: to.EnsureHasSpaceFor(_tx, originalFromKeyStart, -1); dataPos = to.AddPageRefNode(to.LastSearchPosition, originalFromKeyStart, fromNode->PageNumber); break; case NodeFlags.Data: to.EnsureHasSpaceFor(_tx, originalFromKeyStart, fromNode->DataSize); dataPos = to.AddDataNode(to.LastSearchPosition, originalFromKeyStart, fromNode->DataSize, nodeVersion); break; case NodeFlags.MultiValuePageRef: to.EnsureHasSpaceFor(_tx, originalFromKeyStart, fromNode->DataSize); dataPos = to.AddMultiValueNode(to.LastSearchPosition, originalFromKeyStart, fromNode->DataSize, nodeVersion); break; default: throw new NotSupportedException("Invalid node type to move: " + fromNode->Flags); } if (dataPos != null) { NativeMethods.memcpy(dataPos, val, fromNode->DataSize); } from.RemoveNode(from.LastSearchPositionOrLastEntry); var pos = parentPage.LastSearchPositionOrLastEntry; parentPage.RemoveNode(pos); var newKey = 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; newKey = GetActualKey(from, 0); } parentPage.EnsureHasSpaceFor(_tx, newKey, -1); parentPage.AddPageRefNode(pos, newKey, 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 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); } }
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 *AddNodeToPage(Page page, int index) { switch (_nodeType) { case NodeFlags.PageRef: return(page.AddPageRefNode(index, _newKey, _pageNumber)); case NodeFlags.Data: return(page.AddDataNode(index, _newKey, _len, _nodeVersion)); case NodeFlags.MultiValuePageRef: return(page.AddMultiValueNode(index, _newKey, _len, _nodeVersion)); default: throw new NotSupportedException("Unknown node type"); } }
private byte *AddNodeToPage(Page page, int index, MemorySlice alreadyPreparedNewKey = null) { var newKeyToInsert = alreadyPreparedNewKey ?? page.PrepareKeyToInsert(_newKey, index); switch (_nodeType) { case NodeFlags.PageRef: return(page.AddPageRefNode(index, newKeyToInsert, _pageNumber)); case NodeFlags.Data: return(page.AddDataNode(index, newKeyToInsert, _len, _nodeVersion)); case NodeFlags.MultiValuePageRef: return(page.AddMultiValueNode(index, newKeyToInsert, _len, _nodeVersion)); default: throw new NotSupportedException("Unknown node type"); } }
private void MoveLeafNode(Page parentPage, Page from, Page to) { Debug.Assert(from.IsBranch == false); var originalFromKeyStart = GetActualKey(from, from.LastSearchPositionOrLastEntry); var fromNode = from.GetNode(from.LastSearchPosition); byte* val = @from.Base + @from.KeysOffsets[@from.LastSearchPosition] + Constants.NodeHeaderSize + originalFromKeyStart.Size; var nodeVersion = fromNode->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 prefixedOriginalFromKey = to.PrepareKeyToInsert(originalFromKeyStart, to.LastSearchPosition); byte* dataPos; var fromDataSize = fromNode->DataSize; switch (fromNode->Flags) { case NodeFlags.PageRef: to.EnsureHasSpaceFor(_tx, prefixedOriginalFromKey, -1); dataPos = to.AddPageRefNode(to.LastSearchPosition, prefixedOriginalFromKey, fromNode->PageNumber); break; case NodeFlags.Data: to.EnsureHasSpaceFor(_tx, prefixedOriginalFromKey, fromDataSize); dataPos = to.AddDataNode(to.LastSearchPosition, prefixedOriginalFromKey, fromDataSize, nodeVersion); break; case NodeFlags.MultiValuePageRef: to.EnsureHasSpaceFor(_tx, prefixedOriginalFromKey, fromDataSize); dataPos = to.AddMultiValueNode(to.LastSearchPosition, prefixedOriginalFromKey, fromDataSize, nodeVersion); break; default: throw new NotSupportedException("Invalid node type to move: " + fromNode->Flags); } if(dataPos != null && fromDataSize > 0) Memory.Copy(dataPos, val, fromDataSize); 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); }
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)); }
public byte *Execute() { Page rightPage = Tree.NewPage(_tx, _page.Flags, 1); _treeState.RecordNewPage(_page, 1); rightPage.Flags = _page.Flags; if (_cursor.PageCount == 0) // we need to do a root split { Page newRootPage = Tree.NewPage(_tx, PageFlags.Branch, 1); _cursor.Push(newRootPage); _treeState.RootPageNumber = newRootPage.PageNumber; _treeState.Depth++; _treeState.RecordNewPage(newRootPage, 1); // now add implicit left page newRootPage.AddPageRefNode(0, Slice.BeforeAllKeys, _page.PageNumber); _parentPage = newRootPage; _parentPage.LastSearchPosition++; } else { // we already popped the page, so the current one on the stack is what the parent of the page _parentPage = _tx.ModifyPage(_cursor.CurrentPage.PageNumber, _cursor.CurrentPage); _cursor.Update(_cursor.Pages.First, _parentPage); } if (_page.IsLeaf) { _tx.ClearRecentFoundPages(_tree); } 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 byte *pos; if (_page.IsBranch) { // 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, Slice.Empty, node->PageNumber); pos = AddNodeToPage(rightPage, 1); AddSeparatorToParentPage(rightPage, new Slice(node)); _page.RemoveNode(_page.NumberOfEntries - 1); } else { AddSeparatorToParentPage(rightPage, _newKey); pos = AddNodeToPage(rightPage, 0); } _cursor.Push(rightPage); return(pos); } return(SplitPageInHalf(rightPage)); }
private void MoveBranchNode(Page parentPage, Page from, Page to) { Debug.Assert(from.IsBranch); var originalFromKeyStart = GetActualKey(from, from.LastSearchPositionOrLastEntry); to.EnsureHasSpaceFor(_tx, originalFromKeyStart, -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 var implicitLeftKey = GetActualKey(to, 0); var leftPageNumber = to.GetNode(0)->PageNumber; to.AddPageRefNode(1, implicitLeftKey, leftPageNumber); to.AddPageRefNode(0, Slice.BeforeAllKeys, pageNum); to.RemoveNode(1); } else { to.AddPageRefNode(to.LastSearchPosition, originalFromKeyStart, pageNum); } if (from.LastSearchPositionOrLastEntry == 0) { // cannot just remove the left node, need to adjust those var rightPageNumber = from.GetNode(1)->PageNumber; from.RemoveNode(0); // remove the original implicit node from.RemoveNode(0); // remove the next node that we now turned into implicit from.EnsureHasSpaceFor(_tx, Slice.BeforeAllKeys, -1); from.AddPageRefNode(0, Slice.BeforeAllKeys, rightPageNumber); Debug.Assert(from.NumberOfEntries >= 2); } else { from.RemoveNode(from.LastSearchPositionOrLastEntry); } var pos = parentPage.LastSearchPositionOrLastEntry; parentPage.RemoveNode(pos); var newKey = 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; newKey = GetActualKey(from, 0); } parentPage.EnsureHasSpaceFor(_tx, newKey, -1); parentPage.AddPageRefNode(pos, newKey, pageNumber); }
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 byte *Execute() { using (_tree.IsFreeSpaceTree ? _tx.Environment.FreeSpaceHandling.Disable() : null) { 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); _tree.State.RootPageNumber = newRootPage.PageNumber; _tree.State.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 _parentPage = _tx.ModifyPage(_cursor.CurrentPage.PageNumber, _tree, _cursor.CurrentPage); _cursor.Update(_cursor.Pages.First, _parentPage); } if (_page.IsLeaf) { _tree.ClearRecentFoundPages(); } 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 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); } }
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); }
private byte* AddNodeToPage(Page page, int index) { switch (_nodeType) { case NodeFlags.PageRef: return page.AddPageRefNode(index, _newKey, _pageNumber); case NodeFlags.Data: return page.AddDataNode(index, _newKey, _len, _nodeVersion); case NodeFlags.MultiValuePageRef: return page.AddMultiValueNode(index, _newKey, _len, _nodeVersion); default: throw new NotSupportedException("Unknown node type"); } }
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); }
private byte* AddNodeToPage(Page page, int index, MemorySlice alreadyPreparedNewKey = null) { var newKeyToInsert = alreadyPreparedNewKey ?? page.PrepareKeyToInsert(_newKey, index); switch (_nodeType) { case NodeFlags.PageRef: return page.AddPageRefNode(index, newKeyToInsert, _pageNumber); case NodeFlags.Data: return page.AddDataNode(index, newKeyToInsert, _len, _nodeVersion); case NodeFlags.MultiValuePageRef: return page.AddMultiValueNode(index, newKeyToInsert, _len, _nodeVersion); default: throw new NotSupportedException("Unknown node type"); } }