private unsafe static void RenderPage(LowLevelTransaction tx, TreePage page, TextWriter sw, string text, bool open) { sw.WriteLine( "<ul><li><input type='checkbox' id='page-{0}' {3} /><label for='page-{0}'>{4}: Page {0:#,#;;0} - {1} - {2:#,#;;0} entries</label><ul>", page.PageNumber, page.IsLeaf ? "Leaf" : "Branch", page.NumberOfEntries, open ? "checked" : "", text); for (int i = 0; i < page.NumberOfEntries; i++) { var nodeHeader = page.GetNode(i); var key = TreeNodeHeader.ToSlicePtr(tx.Allocator, nodeHeader).ToString(); if (page.IsLeaf) { sw.Write("<li>{0} {1} - size: {2:#,#}</li>", key, nodeHeader->Flags, TreeNodeHeader.GetDataSize(tx, nodeHeader)); } else { var pageNum = nodeHeader->PageNumber; if (i == 0) { key = "[smallest]"; } RenderPage(tx, tx.GetReadOnlyTreePage(pageNum), sw, key, false); } } sw.WriteLine("</ul></li></ul>"); }
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); }
protected unsafe Tuple <Slice, Slice> ReadKey(Transaction txh, Tree tree, Slice key) { TreeNodeHeader *node; tree.FindPageFor(key, out node); if (node == null) { return(null); } Slice item1; TreeNodeHeader.ToSlicePtr(txh.Allocator, node, out item1); if (SliceComparer.CompareInline(item1, key) != 0) { return(null); } Slice item2; Slice.External(txh.Allocator, (byte *)node + node->KeySize + Constants.Tree.NodeHeaderSize, (ushort)node->DataSize, ByteStringType.Immutable, out item2); return(Tuple.Create(item1, item2)); }
public void CopyToOriginal(LowLevelTransaction tx, bool defragRequired, bool wasModified) { if (CalcSizeUsed() < Original.PageMaxSpace) { // no need to compress Original.Lower = (ushort)Constants.Tree.PageHeaderSize; Original.Upper = (ushort)Original.PageSize; Original.Flags &= ~PageFlags.Compressed; for (var i = 0; i < NumberOfEntries; i++) { var node = GetNode(i); using (TreeNodeHeader.ToSlicePtr(tx.Allocator, node, out var slice)) Original.CopyNodeDataToEndOfPage(node, slice); } } else { using (LeafPageCompressor.TryGetCompressedTempPage(tx, this, out var compressed, defrag: defragRequired)) { if (compressed == null) { if (wasModified == false) { return; } ThrowCouldNotCompressDecompressedPage(PageNumber); } LeafPageCompressor.CopyToPage(compressed, Original); } } }
public void CopyToOriginal(LowLevelTransaction tx, bool defragRequired) { if (CalcSizeUsed() < Original.PageMaxSpace) { // no need to compress Original.Lower = (ushort)Constants.Tree.PageHeaderSize; Original.Upper = (ushort)Original.PageSize; Original.Flags &= ~PageFlags.Compressed; for (var i = 0; i < NumberOfEntries; i++) { var node = GetNode(i); Slice slice; using (TreeNodeHeader.ToSlicePtr(tx.Allocator, node, out slice)) Original.CopyNodeDataToEndOfPage(node, slice); } } else { CompressionResult compressed; using (LeafPageCompressor.TryGetCompressedTempPage(tx, this, out compressed, defrag: defragRequired)) { if (compressed == null) { throw new InvalidOperationException("Could not compress a page which was already compressed. Should never happen"); } LeafPageCompressor.CopyToPage(compressed, Original); } } }
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(); }
private MultiValuesReport CreateMultiValuesReport(Tree tree) { var multiValues = new MultiValuesReport(); using (var multiTreeIterator = tree.Iterate(false)) { if (multiTreeIterator.Seek(Slices.BeforeAllKeys)) { do { var currentNode = multiTreeIterator.Current; switch (currentNode->Flags) { case TreeNodeFlags.MultiValuePageRef: { var multiValueTreeHeader = (TreeRootHeader *)((byte *)currentNode + currentNode->KeySize + Constants.NodeHeaderSize); Debug.Assert(multiValueTreeHeader->Flags == TreeFlags.MultiValue); multiValues.NumberOfEntries += multiValueTreeHeader->NumberOfEntries; multiValues.BranchPages += multiValueTreeHeader->BranchPages; multiValues.LeafPages += multiValueTreeHeader->LeafPages; multiValues.PageCount += multiValueTreeHeader->PageCount; break; } case TreeNodeFlags.Data: { var nestedPage = GetNestedMultiValuePage(TreeNodeHeader.DirectAccess(_tx, currentNode), currentNode); multiValues.NumberOfEntries += nestedPage.NumberOfEntries; break; } case TreeNodeFlags.PageRef: { var overFlowPage = _tx.GetReadOnlyTreePage(currentNode->PageNumber); var nestedPage = GetNestedMultiValuePage(overFlowPage.Base + Constants.TreePageHeaderSize, currentNode); multiValues.NumberOfEntries += nestedPage.NumberOfEntries; break; } default: throw new VoronUnrecoverableErrorException("currentNode->FixedTreeFlags has value of " + currentNode->Flags); } } while (multiTreeIterator.MoveNext()); } } return(multiValues); }
public void CopyToOriginal(LowLevelTransaction tx, bool defragRequired, bool wasModified, Tree tree) { if (CalcSizeUsed() < Original.PageMaxSpace) { // no need to compress Original.Lower = (ushort)Constants.Tree.PageHeaderSize; Original.Upper = (ushort)Original.PageSize; Original.Flags &= ~PageFlags.Compressed; for (var i = 0; i < NumberOfEntries; i++) { var node = GetNode(i); using (TreeNodeHeader.ToSlicePtr(tx.Allocator, node, out var slice)) Original.CopyNodeDataToEndOfPage(node, slice); } tree.DecompressionsCache.Invalidate(PageNumber, DecompressionUsage.Write); } else { using (LeafPageCompressor.TryGetCompressedTempPage(tx, this, out var compressed, defrag: defragRequired)) { if (compressed == null) { if (wasModified == false) { return; } if (NumberOfEntries > 0) { // we aren't able to compress the page back to 8KB page // let's split it and try to copy it then SplitPage(tx, tree); } else { ThrowCouldNotCompressEmptyDecompressedPage(PageNumber); } CopyToOriginal(tx, defragRequired: true, wasModified: true, tree); return; } LeafPageCompressor.CopyToPage(compressed, Original); } } }
private AggregationResult AggregateLeafPage(TreePage page, LowLevelTransaction lowLevelTransaction, TransactionOperationContext indexContext, CancellationToken token) { using (_treeReductionStats.LeafAggregation.Start()) { for (int i = 0; i < page.NumberOfEntries; i++) { var valueReader = TreeNodeHeader.Reader(lowLevelTransaction, page.GetNode(i)); var reduceEntry = new BlittableJsonReaderObject(valueReader.Base, valueReader.Length, indexContext); _aggregationBatch.Add(reduceEntry); } return(AggregateBatchResults(_aggregationBatch, indexContext, token)); } }
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 static unsafe void RenderPage(Tree tree, TreePage page, TextWriter sw, string text, bool open) { sw.WriteLine( "<ul><li><input type='checkbox' id='page-{0}' {3} /><label for='page-{0}'>{4}: Page {0:#,#;;0} - {1} - {2:#,#;;0} entries {5}</label><ul>", page.PageNumber, page.IsLeaf ? "Leaf" : "Branch", page.NumberOfEntries, open ? "checked" : "", text, page.IsCompressed? $"(Compressed ({page.CompressionHeader->NumberOfCompressedEntries} entries [uncompressed/compressed: {page.CompressionHeader->UncompressedSize}/{page.CompressionHeader->CompressedSize}])" : string.Empty); for (int i = 0; i < page.NumberOfEntries; i++) { var nodeHeader = page.GetNode(i); string key; Slice keySlice; using (TreeNodeHeader.ToSlicePtr(tree.Llt.Allocator, nodeHeader, out keySlice)) { key = keySlice.ToString(); } if (page.IsLeaf) { sw.Write("<li>{0} {1} - size: {2:#,#}</li>", key, nodeHeader->Flags, tree.GetDataSize(nodeHeader)); } else { var pageNum = nodeHeader->PageNumber; if (i == 0) { key = "[smallest]"; } RenderPage(tree, tree.GetReadOnlyTreePage(pageNum), sw, key, false); } } sw.WriteLine("</ul></li></ul>"); }
private static unsafe ReduceTree RenderTree(Tree tree, ulong reduceKeyHash, Dictionary <long, string> idToDocIdHash, Index index, TransactionOperationContext context) { var stack = new Stack <ReduceTreePage>(); var rootPage = tree.GetReadOnlyTreePage(tree.State.RootPageNumber); var root = new ReduceTreePage(rootPage); root.AggregationResult = GetReduceResult(reduceKeyHash, index, context); stack.Push(root); var table = context.Transaction.InnerTransaction.OpenTable( ReduceMapResultsBase <MapReduceIndexDefinition> .ReduceResultsSchema, ReduceMapResultsBase <MapReduceIndexDefinition> .PageNumberToReduceResultTableName); var tx = tree.Llt; while (stack.Count > 0) { var node = stack.Pop(); var page = node.Page; if (page.IsCompressed) { var decompressed = tree.DecompressPage(page, DecompressionUsage.Read, true); node.DecompressedLeaf = decompressed; page = decompressed; } if (page.NumberOfEntries == 0 && page != rootPage) { throw new InvalidOperationException($"The page {page.PageNumber} is empty"); } for (var i = 0; i < page.NumberOfEntries; i++) { if (page.IsBranch) { var p = page.GetNode(i)->PageNumber; var childNode = new ReduceTreePage(tree.GetReadOnlyTreePage(p)); node.Children.Add(childNode); stack.Push(childNode); } else { var entry = new MapResultInLeaf(); var valueReader = TreeNodeHeader.Reader(tx, page.GetNode(i)); entry.Data = new BlittableJsonReaderObject(valueReader.Base, valueReader.Length, context); using (page.GetNodeKey(tx, i, out Slice s)) { var mapEntryId = Bits.SwapBytes(*(long *)s.Content.Ptr); if (idToDocIdHash.TryGetValue(mapEntryId, out string docId)) { entry.Source = docId; } } node.Entries.Add(entry); } } if (node != root) { node.AggregationResult = GetAggregationResult(node.PageNumber, table, context); } } return(new ReduceTree { DisplayName = GetTreeName(root.AggregationResult, index.Definition, context), Name = tree.Name.ToString(), Root = root, Depth = tree.State.Depth, PageCount = tree.State.PageCount, NumberOfEntries = tree.State.NumberOfEntries }); }
public TreeNodeHeader *Original_WithPrefetch_Search(TreePage page, ByteStringContext allocator, Slice key) { int numberOfEntries = page.NumberOfEntries; if (numberOfEntries == 0) { goto NoEntries; } int lastMatch = -1; int lastSearchPosition = 0; SliceOptions options = key.Options; if (options == SliceOptions.Key) { if (numberOfEntries == 1) { goto SingleEntryKey; } int low = page.IsLeaf ? 0 : 1; int high = numberOfEntries - 1; int position = 0; ushort *offsets = page.KeysOffsets; byte * @base = page.Base; while (low <= high) { position = (low + high) >> 1; var node = (TreeNodeHeader *)(@base + offsets[position]); Slice pageKey; using (TreeNodeHeader.ToSlicePtr(allocator, node, out pageKey)) { Sse.Prefetch0(pageKey.Content.Ptr); lastMatch = SliceComparer.CompareInline(key, pageKey); } if (lastMatch == 0) { break; } if (lastMatch > 0) { low = position + 1; } else { high = position - 1; } } if (lastMatch > 0) // found entry less than key { position++; // move to the smallest entry larger than the key } lastSearchPosition = position; goto MultipleEntryKey; } if (options == SliceOptions.BeforeAllKeys) { lastMatch = 1; goto MultipleEntryKey; } if (options == SliceOptions.AfterAllKeys) { lastSearchPosition = numberOfEntries - 1; goto MultipleEntryKey; } return(null); NoEntries: { page.LastSearchPosition = 0; page.LastMatch = 1; return(null); } SingleEntryKey: { var node = page.GetNode(0); Slice pageKey; using (TreeNodeHeader.ToSlicePtr(allocator, node, out pageKey)) { page.LastMatch = SliceComparer.CompareInline(key, pageKey); } page.LastSearchPosition = page.LastMatch > 0 ? 1 : 0; return(page.LastSearchPosition == 0 ? node : null); } MultipleEntryKey: { page.LastMatch = lastMatch; page.LastSearchPosition = lastSearchPosition; if (lastSearchPosition >= numberOfEntries) { return(null); } return(page.GetNode(lastSearchPosition)); } }