diff --git a/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.cpp b/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.cpp index f3f0accc..1840e39c 100644 --- a/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.cpp +++ b/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.cpp @@ -32,14 +32,15 @@ namespace blobstore { // numLeavesdepth()); + bool increaseTreeDepth = endIndex > maxLeavesForDepth; - _traverseExistingSubtree(root.get(), std::min(beginIndex, maxLeavesForDepth), std::min(endIndex, maxLeavesForDepth), 0, false, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); + _traverseExistingSubtree(root.get(), std::min(beginIndex, maxLeavesForDepth), std::min(endIndex, maxLeavesForDepth), 0, increaseTreeDepth, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); // If the traversal goes too far right for a tree this depth, increase tree depth by one and continue traversal. // This is recursive, i.e. will be repeated if the tree is still not deep enough. // We don't increase to the full needed tree depth in one step, because we want the traversal to go as far as possible // and only then increase the depth - this causes the tree to be in consistent shape (balanced) for longer. - if (endIndex > maxLeavesForDepth) { + if (increaseTreeDepth) { // TODO Test cases that increase tree depth by 0, 1, 2, ... levels auto newRoot = _increaseTreeDepth(std::move(root)); return traverseAndReturnRoot(std::move(newRoot), std::max(beginIndex, maxLeavesForDepth), endIndex, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); diff --git a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_TraverseLeaves.cpp b/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_TraverseLeaves.cpp index 10fc875f..d0f8a931 100644 --- a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_TraverseLeaves.cpp +++ b/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_TraverseLeaves.cpp @@ -389,4 +389,30 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddlePartOfFourLevelTree) { TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode()+5, 2*nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode() -1); } +TEST_F(DataTreeTest_TraverseLeaves, LastLeafIsAlreadyResizedInCallback) { + auto root = CreateLeaf(); + root->flush(); + auto tree = treeStore.load(root->key()).value(); + tree->traverseLeaves(0, 2, [this] (uint32_t leafIndex, DataLeafNode *leaf) { + if (leafIndex == 0) { + EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf(), leaf->numBytes()); + } else { + EXPECT_TRUE(false) << "only two nodes"; + } + }, [this] (uint32_t /*nodeIndex*/) -> Data { + return Data(1); + }); +} + +TEST_F(DataTreeTest_TraverseLeaves, LastLeafIsAlreadyResizedInCallback_TwoLevel) { + auto root = CreateFullTwoLevelWithLastLeafSize(5); + root->flush(); + auto tree = treeStore.load(root->key()).value(); + tree->traverseLeaves(0, nodeStore->layout().maxChildrenPerInnerNode()+1, [this] (uint32_t leafIndex, DataLeafNode *leaf) { + EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf(), leaf->numBytes()); + }, [this] (uint32_t /*nodeIndex*/) -> Data { + return Data(1); + }); +} + //TODO Refactor the test cases that are too long