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)); }
internal byte *DirectAdd(Transaction tx, Slice key, int len) { if (tx.Flags == (TransactionFlags.ReadWrite) == false) { throw new ArgumentException("Cannot add a value in a read only transaction"); } if (key.Size > tx.Pager.MaxNodeSize) { throw new ArgumentException("Key size is too big, must be at most " + tx.Pager.MaxNodeSize + " bytes, but was " + key.Size, "key"); } using (var cursor = tx.NewCursor(this)) { var txInfo = tx.GetTreeInformation(this); FindPageFor(tx, key, cursor); var page = tx.ModifyCursor(this, cursor); if (page.LastMatch == 0) // this is an update operation { RemoveLeafNode(tx, cursor, page); } else // new item should be recorded { txInfo.State.EntriesCount++; } var lastSearchPosition = page.LastSearchPosition; // searching for overflow pages might change this byte *overFlowPos = null; var pageNumber = -1L; if (ShouldGoToOverflowPage(tx, len)) { pageNumber = WriteToOverflowPages(tx, txInfo, len, out overFlowPos); len = -1; } byte *dataPos; if (page.HasSpaceFor(key, len) == false) { var pageSplitter = new PageSplitter(tx, _cmp, key, len, pageNumber, cursor, txInfo); dataPos = pageSplitter.Execute(); DebugValidateTree(tx, txInfo.RootPageNumber); } else { dataPos = page.AddNode(lastSearchPosition, key, len, pageNumber); cursor.IncrementItemCount(); page.DebugValidate(tx, _cmp, txInfo.RootPageNumber); } if (overFlowPos != null) { return(overFlowPos); } return(dataPos); } }
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; }
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 *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); }
internal byte *DirectAdd(MemorySlice key, int len, NodeFlags nodeType = NodeFlags.Data, ushort?version = null) { Debug.Assert(nodeType == NodeFlags.Data || nodeType == NodeFlags.MultiValuePageRef); if (_tx.Flags == (TransactionFlags.ReadWrite) == false) { throw new ArgumentException("Cannot add a value in a read only transaction"); } if (key.Size + Constants.NodeHeaderSize > AbstractPager.NodeMaxSize) { throw new ArgumentException( "Key size is too big, must be at most " + (AbstractPager.NodeMaxSize - Constants.NodeHeaderSize) + " bytes, but was " + key.Size, "key"); } Lazy <Cursor> lazy; NodeHeader * node; var foundPage = FindPageFor(key, out node, out lazy); var page = _tx.ModifyPage(foundPage.PageNumber, this, foundPage); ushort nodeVersion = 0; bool? shouldGoToOverflowPage = null; if (page.LastMatch == 0) // this is an update operation { node = page.GetNode(page.LastSearchPosition); Debug.Assert(page.GetNodeKey(node).Equals(key)); shouldGoToOverflowPage = _tx.DataPager.ShouldGoToOverflowPage(len); byte *pos; if (shouldGoToOverflowPage == false) { // optimization for Data and MultiValuePageRef - try to overwrite existing node space if (TryOverwriteDataOrMultiValuePageRefNode(node, key, len, nodeType, version, out pos)) { return(pos); } } else { // optimization for PageRef - try to overwrite existing overflows if (TryOverwriteOverflowPages(State, node, key, len, version, out pos)) { return(pos); } } RemoveLeafNode(page, out nodeVersion); } else // new item should be recorded { State.EntriesCount++; } CheckConcurrency(key, version, nodeVersion, TreeActionType.Add); var lastSearchPosition = page.LastSearchPosition; // searching for overflow pages might change this byte *overFlowPos = null; var pageNumber = -1L; if (shouldGoToOverflowPage ?? _tx.DataPager.ShouldGoToOverflowPage(len)) { pageNumber = WriteToOverflowPages(State, len, out overFlowPos); len = -1; nodeType = NodeFlags.PageRef; } var keyToInsert = page.PrepareKeyToInsert(key, lastSearchPosition); byte *dataPos; if (page.HasSpaceFor(_tx, keyToInsert, len) == false) { var cursor = lazy.Value; cursor.Update(cursor.Pages.First, page); var pageSplitter = new PageSplitter(_tx, this, key, len, pageNumber, nodeType, nodeVersion, cursor, State); dataPos = pageSplitter.Execute(); DebugValidateTree(State.RootPageNumber); } else { switch (nodeType) { case NodeFlags.PageRef: dataPos = page.AddPageRefNode(lastSearchPosition, keyToInsert, pageNumber); break; case NodeFlags.Data: dataPos = page.AddDataNode(lastSearchPosition, keyToInsert, len, nodeVersion); break; case NodeFlags.MultiValuePageRef: dataPos = page.AddMultiValueNode(lastSearchPosition, keyToInsert, len, nodeVersion); break; default: throw new NotSupportedException("Unknown node type for direct add operation: " + nodeType); } page.DebugValidate(_tx, State.RootPageNumber); } if (overFlowPos != null) { return(overFlowPos); } return(dataPos); }
internal byte* DirectAdd(Transaction tx, Slice key, int len, NodeFlags nodeType = NodeFlags.Data, ushort? version = null) { Debug.Assert(nodeType == NodeFlags.Data || nodeType == NodeFlags.MultiValuePageRef); if (tx.Flags == (TransactionFlags.ReadWrite) == false) throw new ArgumentException("Cannot add a value in a read only transaction"); if (key.Size > tx.DataPager.MaxNodeSize) throw new ArgumentException( "Key size is too big, must be at most " + tx.DataPager.MaxNodeSize + " bytes, but was " + key.Size, "key"); Lazy<Cursor> lazy; var foundPage = FindPageFor(tx, key, out lazy); var page = tx.ModifyPage(foundPage.PageNumber, foundPage); ushort nodeVersion = 0; bool? shouldGoToOverflowPage = null; if (page.LastMatch == 0) // this is an update operation { var node = page.GetNode(page.LastSearchPosition); Debug.Assert(node->KeySize == key.Size && new Slice(node).Equals(key)); shouldGoToOverflowPage = tx.DataPager.ShouldGoToOverflowPage(len); byte* pos; if (shouldGoToOverflowPage == false) { // optimization for Data and MultiValuePageRef - try to overwrite existing node space if (TryOverwriteDataOrMultiValuePageRefNode(node, key, len, nodeType, version, out pos)) return pos; } else { // optimization for PageRef - try to overwrite existing overflows if (TryOverwriteOverflowPages(tx, State, node, key, len, version, out pos)) return pos; } RemoveLeafNode(tx, page, out nodeVersion); } else // new item should be recorded { State.EntriesCount++; } CheckConcurrency(key, version, nodeVersion, TreeActionType.Add); var lastSearchPosition = page.LastSearchPosition; // searching for overflow pages might change this byte* overFlowPos = null; var pageNumber = -1L; if (shouldGoToOverflowPage ?? tx.DataPager.ShouldGoToOverflowPage(len)) { pageNumber = WriteToOverflowPages(tx, State, len, out overFlowPos); len = -1; nodeType = NodeFlags.PageRef; } byte* dataPos; if (page.HasSpaceFor(tx, key, len) == false) { var cursor = lazy.Value; cursor.Update(cursor.Pages.First, page); var pageSplitter = new PageSplitter(tx, this, _cmp, key, len, pageNumber, nodeType, nodeVersion, cursor, State); dataPos = pageSplitter.Execute(); DebugValidateTree(tx, State.RootPageNumber); } else { switch (nodeType) { case NodeFlags.PageRef: dataPos = page.AddPageRefNode(lastSearchPosition, key, pageNumber); break; case NodeFlags.Data: dataPos = page.AddDataNode(lastSearchPosition, key, len, nodeVersion); break; case NodeFlags.MultiValuePageRef: dataPos = page.AddMultiValueNode(lastSearchPosition, key, len, nodeVersion); break; default: throw new NotSupportedException("Unknown node type for direct add operation: " + nodeType); } page.DebugValidate(tx, _cmp, State.RootPageNumber); } if (overFlowPos != null) return overFlowPos; return dataPos; }
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); } }
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 void AddSeparatorToParentPage(Page rightPage, Slice seperatorKey) { if (_parentPage.HasSpaceFor(_tx ,SizeOf.BranchEntry(seperatorKey) + Constants.NodeOffsetSize) == false) { var pageSplitter = new PageSplitter(_tx, _tree, _cmp, seperatorKey, -1, rightPage.PageNumber, NodeFlags.PageRef, 0, _cursor, _treeState); pageSplitter.Execute(); } else { _parentPage.NodePositionFor(seperatorKey, _cmp); // select the appropriate place for this _parentPage.AddPageRefNode(_parentPage.LastSearchPosition, seperatorKey, rightPage.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); }
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); }