private bool TryUseRecentTransactionPage(Slice key, out TreePage page, out TreeNodeHeader *node) { node = null; page = null; var foundPage = _recentlyFoundPages?.Find(key); if (foundPage == null) { return(false); } if (foundPage.Page != null) { // we can't share the same instance, Page instance may be modified by // concurrently run iterators page = new TreePage(foundPage.Page.Base, foundPage.Page.PageSize); } else { page = GetReadOnlyTreePage(foundPage.Number); } if (page.IsLeaf == false) { VoronUnrecoverableErrorException.Raise(_llt.Environment, "Index points to a non leaf page"); } node = page.Search(_llt, key); // will set the LastSearchPosition return(true); }
/// <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(TreeNodeHeader *other, Slice key) { var index = NumberOfEntries; Debug.Assert(HasSpaceFor(TreeSizeOf.NodeEntryWithAnotherKey(other, key) + Constants.Tree.NodeOffsetSize)); var nodeSize = TreeSizeOf.NodeEntryWithAnotherKey(other, key); Debug.Assert(IsBranch == false || index != 0 || key.Size == 0);// branch page's first item must be the implicit ref var newNode = AllocateNewNode(index, nodeSize); Debug.Assert(key.Size <= ushort.MaxValue); newNode->KeySize = (ushort)key.Size; newNode->Flags = other->Flags; if (key.Options == SliceOptions.Key && key.Size > 0) { key.CopyTo((byte *)newNode + Constants.Tree.NodeHeaderSize); } if (IsBranch || other->Flags == (TreeNodeFlags.PageRef)) { newNode->PageNumber = other->PageNumber; newNode->Flags = TreeNodeFlags.PageRef; return; } newNode->DataSize = other->DataSize; Memory.Copy((byte *)newNode + Constants.Tree.NodeHeaderSize + key.Size, (byte *)other + Constants.Tree.NodeHeaderSize + other->KeySize, other->DataSize); }
private bool TryOverwriteOverflowPages(TreeNodeHeader *updatedNode, int len, out byte *pos) { if (updatedNode->Flags == TreeNodeFlags.PageRef) { var readOnlyOverflowPage = GetReadOnlyTreePage(updatedNode->PageNumber); if (len <= readOnlyOverflowPage.OverflowSize) { var availableOverflows = _llt.DataPager.GetNumberOfOverflowPages(readOnlyOverflowPage.OverflowSize); var requestedOverflows = _llt.DataPager.GetNumberOfOverflowPages(len); var overflowsToFree = availableOverflows - requestedOverflows; for (int i = 0; i < overflowsToFree; i++) { _llt.FreePage(readOnlyOverflowPage.PageNumber + requestedOverflows + i); } State.RecordFreedPage(readOnlyOverflowPage, overflowsToFree); var writtableOverflowPage = AllocateNewPage(_llt, TreePageFlags.Value, requestedOverflows, updatedNode->PageNumber); writtableOverflowPage.Flags = PageFlags.Overflow | PageFlags.VariableSizeTreePage; writtableOverflowPage.OverflowSize = len; pos = writtableOverflowPage.Base + Constants.Tree.PageHeaderSize; PageModified?.Invoke(writtableOverflowPage.PageNumber); return(true); } } pos = null; return(false); }
private TreePage GetNestedMultiValuePage(byte *nestedPagePtr, TreeNodeHeader *currentNode) { var nestedPage = new TreePage(nestedPagePtr, "multi tree", (ushort)TreeNodeHeader.GetDataSize(_tx, currentNode)); Debug.Assert(nestedPage.PageNumber == -1); // nested page marker return(nestedPage); }
private bool TryOverwriteDataOrMultiValuePageRefNode(TreeNodeHeader *updatedNode, int len, TreeNodeFlags requestedNodeType, out byte *pos) { switch (requestedNodeType) { case TreeNodeFlags.Data: case TreeNodeFlags.MultiValuePageRef: { if (updatedNode->DataSize == len && (updatedNode->Flags == TreeNodeFlags.Data || updatedNode->Flags == TreeNodeFlags.MultiValuePageRef)) { updatedNode->Flags = requestedNodeType; pos = (byte *)updatedNode + Constants.Tree.NodeHeaderSize + updatedNode->KeySize; return(true); } break; } case TreeNodeFlags.PageRef: throw new InvalidOperationException("We never add PageRef explicitly"); default: throw new ArgumentOutOfRangeException(); } pos = null; return(false); }
private void RemoveBranchWithOneEntry(TreePage page, TreePage parentPage) { Debug.Assert(page.NumberOfEntries == 1); var pageRefNumber = page.GetNode(0)->PageNumber; TreeNodeHeader *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); nodeHeader->PageNumber = pageRefNumber; if (_cursor.CurrentPage.PageNumber == page.PageNumber) { _cursor.Pop(); _cursor.Push(_tree.GetReadOnlyTreePage(pageRefNumber)); } _tree.FreePage(page); }
public TreeNodeHeaderSafe(Tree tree, TreeNodeHeader *nodeHeader) { _tree = tree ?? throw new ArgumentNullException(nameof(tree)); _nodeHeader = nodeHeader; using (TreeNodeHeader.ToSlicePtr(tree.Llt.Allocator, nodeHeader, out Slice keySlice)) Key = keySlice.ToString(); }
public static int GetDataSize(LowLevelTransaction tx, TreeNodeHeader *node) { if (node->Flags == (TreeNodeFlags.PageRef)) { var overFlowPage = tx.GetPage(node->PageNumber); return(overFlowPage.OverflowSize); } return(node->DataSize); }
public static void CopyTo(LowLevelTransaction tx, TreeNodeHeader *node, byte *dest) { if (node->Flags == (TreeNodeFlags.PageRef)) { var overFlowPage = tx.GetPage(node->PageNumber); Memory.Copy(dest, overFlowPage.Pointer + Constants.TreePageHeaderSize, overFlowPage.OverflowSize); } Memory.Copy(dest, (byte *)node + node->KeySize + Constants.NodeHeaderSize, node->DataSize); }
public static byte *DirectAccess(LowLevelTransaction tx, TreeNodeHeader *node) { if (node->Flags == (TreeNodeFlags.PageRef)) { var overFlowPage = tx.GetReadOnlyTreePage(node->PageNumber); return(overFlowPage.Base + Constants.TreePageHeaderSize); } return((byte *)node + node->KeySize + Constants.NodeHeaderSize); }
public int GetDataSize(TreeNodeHeader *node) { if (node->Flags == (TreeNodeFlags.PageRef)) { var overFlowPage = GetReadOnlyPage(node->PageNumber); return(overFlowPage.OverflowSize); } return(node->DataSize); }
public byte *DirectAccessFromHeader(TreeNodeHeader *node) { if (node->Flags == TreeNodeFlags.PageRef) { var overFlowPage = GetReadOnlyTreePage(node->PageNumber); return(overFlowPage.Base + Constants.Tree.PageHeaderSize); } return((byte *)node + node->KeySize + Constants.Tree.NodeHeaderSize); }
internal TreePage FindPageFor(Slice key, out TreeNodeHeader *node, out Func <TreeCursor> cursor) { TreePage p; if (TryUseRecentTransactionPage(key, out cursor, out p, out node)) { return(p); } return(SearchForPage(key, out cursor, out node)); }
public ValueReader GetValueReaderFromHeader(TreeNodeHeader *node) { if (node->Flags == TreeNodeFlags.PageRef) { var overFlowPage = GetReadOnlyPage(node->PageNumber); Debug.Assert(overFlowPage.IsOverflow, "Requested overflow page but got " + overFlowPage.Flags); Debug.Assert(overFlowPage.OverflowSize > 0, "Overflow page cannot be size equal 0 bytes"); return(new ValueReader(overFlowPage.Pointer + Constants.Tree.PageHeaderSize, overFlowPage.OverflowSize)); } return(new ValueReader((byte *)node + node->KeySize + Constants.Tree.NodeHeaderSize, node->DataSize)); }
public static Slice GetData(LowLevelTransaction tx, TreeNodeHeader *node) { if (node->Flags == (TreeNodeFlags.PageRef)) { var overFlowPage = tx.GetPage(node->PageNumber); if (overFlowPage.OverflowSize > ushort.MaxValue) { throw new InvalidOperationException("Cannot convert big data to a slice, too big"); } return(Slice.External(tx.Allocator, overFlowPage.Pointer + Constants.TreePageHeaderSize, (ushort)overFlowPage.OverflowSize)); } return(Slice.External(tx.Allocator, (byte *)node + node->KeySize + Constants.NodeHeaderSize, (ushort)node->DataSize)); }
public static int NodeEntry(TreeNodeHeader *other) { var sz = other->KeySize + Constants.NodeHeaderSize; if (other->Flags == TreeNodeFlags.Data || other->Flags == TreeNodeFlags.MultiValuePageRef) { sz += other->DataSize; } sz += sz & 1; return(sz); }
public static ValueReader Reader(LowLevelTransaction tx, TreeNodeHeader *node) { if (node->Flags == (TreeNodeFlags.PageRef)) { var overFlowPage = tx.GetPage(node->PageNumber); Debug.Assert(overFlowPage.IsOverflow, "Requested overflow page but got " + overFlowPage.Flags); Debug.Assert(overFlowPage.OverflowSize > 0, "Overflow page cannot be size equal 0 bytes"); return(new ValueReader(overFlowPage.Pointer + Constants.Tree.PageHeaderSize, overFlowPage.OverflowSize)); } return(new ValueReader((byte *)node + node->KeySize + Constants.Tree.NodeHeaderSize, node->DataSize)); }
private byte *OptimizedOnlyMoveNewValueToTheRightPage(TreePage rightPage) { // 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 TreePage 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 TreeNodeHeader *node = _page.GetNode(_page.NumberOfEntries - 1); Debug.Assert(node->Flags == TreeNodeFlags.PageRef); rightPage.AddPageRefNode(0, Slices.BeforeAllKeys, node->PageNumber); pos = AddNodeToPage(rightPage, 1); Slice separatorKey; using (TreeNodeHeader.ToSlicePtr(_tx.Allocator, node, out separatorKey)) { 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); }
public static int NodeEntryWithAnotherKey(TreeNodeHeader *other, Slice key) { var keySize = key.HasValue ? key.Size : other->KeySize; var sz = keySize + Constants.NodeHeaderSize; if (other->Flags == TreeNodeFlags.Data || other->Flags == TreeNodeFlags.MultiValuePageRef) { sz += other->DataSize; } sz += sz & 1; return(sz); }
private void EnsureNestedPagePointer(TreePage page, TreeNodeHeader *currentItem, ref TreePage nestedPage, ref byte *nestedPagePtr) { var movedItem = page.GetNode(page.LastSearchPosition); if (movedItem == currentItem) { return; } // HasSpaceFor could called Defrag internally and read item has moved // need to ensure the nested page has a valid pointer nestedPagePtr = DirectAccessFromHeader(movedItem); nestedPage = new TreePage(nestedPagePtr, (ushort)GetDataSize(movedItem)); }
private Slice GetActualKey(TreePage page, int pos, out TreeNodeHeader *node) { node = page.GetNode(pos); var key = TreeNodeHeader.ToSlicePtr(_tx.Allocator, node); while (key.Size == 0) { Debug.Assert(page.IsBranch); page = _tx.GetReadOnlyTreePage(node->PageNumber); node = page.GetNode(0); key = TreeNodeHeader.ToSlicePtr(_tx.Allocator, node); } return(key); }
private int AdjustSplitPosition(int currentIndex, int splitIndex, ref bool toRight) { Slice keyToInsert = _newKey; int pageSize = TreeSizeOf.NodeEntry(AbstractPager.PageMaxSpace, keyToInsert, _len) + Constants.Tree.NodeOffsetSize; if (toRight == false) { for (int i = 0; i < splitIndex; i++) { TreeNodeHeader *node = _page.GetNode(i); pageSize += node->GetNodeSize(); pageSize += pageSize & 1; if (pageSize > _page.PageMaxSpace) { if (i <= currentIndex) { if (i < currentIndex) { toRight = true; } return(currentIndex); } return(i); } } } else { for (int i = _page.NumberOfEntries - 1; i >= splitIndex; i--) { TreeNodeHeader *node = _page.GetNode(i); pageSize += node->GetNodeSize(); pageSize += pageSize & 1; if (pageSize > _page.PageMaxSpace) { if (i >= currentIndex) { toRight = false; return(currentIndex); } return(i + 1); } } } return(splitIndex); }
internal TreePage FindPageFor(Slice key, out TreeNodeHeader *node, out Func <Slice, TreeCursor> cursor, bool allowCompressed = false) { TreePage p; if (TryUseRecentTransactionPage(key, out cursor, out p, out node)) { if (allowCompressed == false && p.IsCompressed) { ThrowOnCompressedPage(p); } return(p); } return(SearchForPage(key, allowCompressed, out cursor, out node)); }
private ByteStringContext.ExternalScope GetActualKey(TreePage page, int pos, out TreeNodeHeader *node, out Slice key) { node = page.GetNode(pos); var scope = TreeNodeHeader.ToSlicePtr(_tx.Allocator, node, out key); while (key.Size == 0) { Debug.Assert(page.IsBranch); page = _tree.GetReadOnlyTreePage(node->PageNumber); node = page.GetNode(0); scope.Dispose(); scope = TreeNodeHeader.ToSlicePtr(_tx.Allocator, node, out key); } return(scope); }
public TreeNodeHeaderSafe(Tree tree, TreeNodeHeader *nodeHeader) { _tree = tree ?? throw new ArgumentNullException(nameof(tree)); _nodeHeader = nodeHeader; using (TreeNodeHeader.ToSlicePtr(tree.Llt.Allocator, nodeHeader, out Slice keySlice)) { // uncomment to convert the slice to long //if (keySlice.Size == sizeof(long)) //{ // var idPtr = (long*)keySlice.Content.Ptr; // var id = Bits.SwapBytes(*idPtr); // Key = id.ToString(); //} //else Key = keySlice.ToString(); } }
private ActualKeyScope GetActualKey(TreePage page, int pos, out TreeNodeHeader *node, out Slice key) { DecompressedLeafPage decompressedLeafPage = null; node = page.GetNode(pos); var scope = TreeNodeHeader.ToSlicePtr(_tx.Allocator, node, out key); while (key.Size == 0) { Debug.Assert(page.IsBranch); page = _tree.GetReadOnlyTreePage(node->PageNumber); if (page.IsCompressed == false) { node = page.GetNode(0); } else { decompressedLeafPage?.Dispose(); decompressedLeafPage = _tree.DecompressPage(page, skipCache: true); if (decompressedLeafPage.NumberOfEntries > 0) { node = decompressedLeafPage.GetNode(0); } else { // we have empty page after decompression (each compressed entry has a corresponding CompressionTombstone) // we can safely use the node key of first tombstone (they have proper order) node = page.GetNode(0); } } scope.Dispose(); scope = TreeNodeHeader.ToSlicePtr(_tx.Allocator, node, out key); } return(new ActualKeyScope { DecompressedLeafPage = decompressedLeafPage, ExternalScope = scope }); }
private Tree OpenMultiValueTree(Slice key, TreeNodeHeader *item) { Tree tree; if (_tx.TryGetMultiValueTree(this, key, out tree)) { return(tree); } var childTreeHeader = (TreeRootHeader *)((byte *)item + item->KeySize + Constants.Tree.NodeHeaderSize); Debug.Assert(childTreeHeader->RootPageNumber < _llt.State.NextPageNumber); Debug.Assert(childTreeHeader->Flags == TreeFlags.MultiValue); tree = Open(_llt, _tx, key, childTreeHeader); _tx.AddMultiValueTree(this, key, tree); return(tree); }
public Slice GetData(TreeNodeHeader *node) { Slice outputDataSlice; if (node->Flags == TreeNodeFlags.PageRef) { var overFlowPage = GetReadOnlyPage(node->PageNumber); if (overFlowPage.OverflowSize > ushort.MaxValue) { throw new InvalidOperationException("Cannot convert big data to a slice, too big"); } Slice.External(Llt.Allocator, overFlowPage.Pointer + Constants.Tree.PageHeaderSize, (ushort)overFlowPage.OverflowSize, out outputDataSlice); } else { Slice.External(Llt.Allocator, (byte *)node + node->KeySize + Constants.Tree.NodeHeaderSize, (ushort)node->DataSize, out outputDataSlice); } return(outputDataSlice); }
private bool TryUseRecentTransactionPage(Slice key, out TreePage page, out TreeNodeHeader *node) { node = null; page = null; var recentPages = _recentlyFoundPages; if (recentPages == null) { return(false); } var foundPage = recentPages.Find(key); if (foundPage == null) { return(false); } if (foundPage.Page != null) { // we can't share the same instance, Page instance may be modified by // concurrently run iterators page = new TreePage(foundPage.Page.Base, foundPage.Page.Source, foundPage.Page.PageSize); } else { page = _llt.GetReadOnlyTreePage(foundPage.Number); } if (page.IsLeaf == false) { throw new InvalidDataException("Index points to a non leaf page"); } node = page.Search(_llt, key); // will set the LastSearchPosition return(true); }
private void RemoveBranchWithOneEntry(TreePage page, TreePage parentPage) { var pageRefNumber = page.GetNode(0)->PageNumber; TreeNodeHeader *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); nodeHeader->PageNumber = pageRefNumber; _tree.FreePage(page); }