From bbdd8a548ba07cf84da2561a713ee16ed61f84dc Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Sun, 17 Jul 2016 10:16:09 +0200 Subject: [PATCH] Special case treatment for traversals until exactly the last leaf has to load the last leaf to grow it. Before this commit, we just always loaded the last traversed leaf and checked its size. Now we only do so if it's the right border leaf. This saves us loading some leaves. --- .../implementations/onblocks/BlobOnBlocks.cpp | 9 +- .../onblocks/datatreestore/DataTree.cpp | 6 +- .../onblocks/datatreestore/DataTree.h | 4 +- .../datatreestore/impl/LeafTraverser.cpp | 25 +++-- .../datatreestore/impl/LeafTraverser.h | 12 +- .../parallelaccessdatatreestore/DataTreeRef.h | 2 +- .../DataTreeTest_Performance.cpp | 2 +- .../DataTreeTest_ResizeByTraversing.cpp | 2 +- .../DataTreeTest_TraverseLeaves.cpp | 104 +++++++++--------- 9 files changed, 84 insertions(+), 82 deletions(-) diff --git a/src/blobstore/implementations/onblocks/BlobOnBlocks.cpp b/src/blobstore/implementations/onblocks/BlobOnBlocks.cpp index 51d04b04..304e37ca 100644 --- a/src/blobstore/implementations/onblocks/BlobOnBlocks.cpp +++ b/src/blobstore/implementations/onblocks/BlobOnBlocks.cpp @@ -49,15 +49,16 @@ void BlobOnBlocks::_traverseLeaves(uint64_t beginByte, uint64_t sizeBytes, funct uint32_t firstLeaf = beginByte / maxBytesPerLeaf; uint32_t endLeaf = utils::ceilDivision(endByte, maxBytesPerLeaf); bool blobIsGrowingFromThisTraversal = false; - auto _onExistingLeaf = [&onExistingLeaf, beginByte, endByte, endLeaf, maxBytesPerLeaf, &blobIsGrowingFromThisTraversal] (uint32_t leafIndex, LeafHandle leafHandle) { + auto _onExistingLeaf = [&onExistingLeaf, beginByte, endByte, endLeaf, maxBytesPerLeaf, &blobIsGrowingFromThisTraversal] (uint32_t leafIndex, bool isRightBorderLeaf, LeafHandle leafHandle) { uint64_t indexOfFirstLeafByte = leafIndex * maxBytesPerLeaf; ASSERT(endByte > indexOfFirstLeafByte, "Traversal went too far right"); uint32_t dataBegin = utils::maxZeroSubtraction(beginByte, indexOfFirstLeafByte); uint32_t dataEnd = std::min(maxBytesPerLeaf, endByte - indexOfFirstLeafByte); - if (leafIndex == endLeaf-1) { + // If we are traversing exactly until the last leaf, then the last leaf wasn't resized by the traversal and might have a wrong size. We have to fix it. + if (isRightBorderLeaf) { + ASSERT(leafIndex == endLeaf-1, "If we traversed further right, this wouldn't be the right border leaf."); auto leaf = leafHandle.node(); if (leaf->numBytes() < dataEnd) { - // If we are traversing an area that didn't exist before (i.e. in the area of the last leaf that wasn't used before), then the last leaf might have a wrong size. We have to fix it. leaf->resize(dataEnd); blobIsGrowingFromThisTraversal = true; } @@ -127,12 +128,12 @@ void BlobOnBlocks::_read(void *target, uint64_t offset, uint64_t count) const { void BlobOnBlocks::write(const void *source, uint64_t offset, uint64_t count) { auto onExistingLeaf = [source, offset, count] (uint64_t indexOfFirstLeafByte, LeafHandle leaf, uint32_t leafDataOffset, uint32_t leafDataSize) { ASSERT(indexOfFirstLeafByte+leafDataOffset>=offset && indexOfFirstLeafByte-offset+leafDataOffset <= count && indexOfFirstLeafByte-offset+leafDataOffset+leafDataSize <= count, "Reading from source out of bounds"); - //TODO Simplify formula, make it easier to understand if (leafDataOffset == 0 && leafDataSize == leaf.nodeStore()->layout().maxBytesPerLeaf()) { Data leafData(leafDataSize); std::memcpy(leafData.data(), (uint8_t*)source + indexOfFirstLeafByte - offset, leafDataSize); leaf.nodeStore()->overwriteLeaf(leaf.key(), std::move(leafData)); } else { + //TODO Simplify formula, make it easier to understand leaf.node()->write((uint8_t *) source + indexOfFirstLeafByte - offset + leafDataOffset, leafDataOffset, leafDataSize); } diff --git a/src/blobstore/implementations/onblocks/datatreestore/DataTree.cpp b/src/blobstore/implementations/onblocks/datatreestore/DataTree.cpp index c2338b65..7e38c694 100644 --- a/src/blobstore/implementations/onblocks/datatreestore/DataTree.cpp +++ b/src/blobstore/implementations/onblocks/datatreestore/DataTree.cpp @@ -96,7 +96,7 @@ uint32_t DataTree::_computeNumLeaves(const DataNode &node) const { return numLeavesInLeftChildren + numLeavesInRightChild; } -void DataTree::traverseLeaves(uint32_t beginIndex, uint32_t endIndex, function onExistingLeaf, function onCreateLeaf) { +void DataTree::traverseLeaves(uint32_t beginIndex, uint32_t endIndex, function onExistingLeaf, function onCreateLeaf) { //TODO Can we allow multiple runs of traverseLeaves() in parallel? Also in parallel with resizeNumBytes()? std::unique_lock lock(_mutex); ASSERT(beginIndex <= endIndex, "Invalid parameters"); @@ -111,7 +111,7 @@ void DataTree::traverseLeaves(uint32_t beginIndex, uint32_t endIndex, function onExistingLeaf, + function onExistingLeaf, function onCreateLeaf, function onBacktrackFromSubtree) { _rootNode = LeafTraverser(_nodeStore).traverseAndReturnRoot(std::move(_rootNode), beginIndex, endIndex, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); @@ -151,7 +151,7 @@ void DataTree::resizeNumBytes(uint64_t newNumBytes) { uint32_t newNumLeaves = std::max(UINT64_C(1), utils::ceilDivision(newNumBytes, _nodeStore->layout().maxBytesPerLeaf())); uint32_t newLastLeafSize = newNumBytes - (newNumLeaves-1) * _nodeStore->layout().maxBytesPerLeaf(); uint32_t maxChildrenPerInnerNode = _nodeStore->layout().maxChildrenPerInnerNode(); - auto onExistingLeaf = [newLastLeafSize] (uint32_t /*index*/, LeafHandle leafHandle) { + auto onExistingLeaf = [newLastLeafSize] (uint32_t /*index*/, bool /*isRightBorderLeaf*/, LeafHandle leafHandle) { auto leaf = leafHandle.node(); // This is only called, if the new last leaf was already existing if (leaf->numBytes() != newLastLeafSize) { diff --git a/src/blobstore/implementations/onblocks/datatreestore/DataTree.h b/src/blobstore/implementations/onblocks/datatreestore/DataTree.h index 2b362e8d..ae9bb80e 100644 --- a/src/blobstore/implementations/onblocks/datatreestore/DataTree.h +++ b/src/blobstore/implementations/onblocks/datatreestore/DataTree.h @@ -31,7 +31,7 @@ public: //Returning uint64_t, because calculations handling this probably need to be done in 64bit to support >4GB blobs. uint64_t maxBytesPerLeaf() const; - void traverseLeaves(uint32_t beginIndex, uint32_t endIndex, std::function onExistingLeaf, std::function onCreateLeaf); + void traverseLeaves(uint32_t beginIndex, uint32_t endIndex, std::function onExistingLeaf, std::function onCreateLeaf); void resizeNumBytes(uint64_t newNumBytes); uint32_t numLeaves() const; @@ -56,7 +56,7 @@ private: //TODO Use underscore for private methods void _traverseLeaves(uint32_t beginIndex, uint32_t endIndex, - std::function onExistingLeaf, + std::function onExistingLeaf, std::function onCreateLeaf, std::function onBacktrackFromSubtree); uint32_t leavesPerFullChild(const datanodestore::DataInnerNode &root) const; diff --git a/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.cpp b/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.cpp index ab363ab0..62be3393 100644 --- a/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.cpp +++ b/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.cpp @@ -24,11 +24,11 @@ namespace blobstore { : _nodeStore(nodeStore) { } - unique_ref LeafTraverser::traverseAndReturnRoot(unique_ref root, uint32_t beginIndex, uint32_t endIndex, function onExistingLeaf, function onCreateLeaf, function onBacktrackFromSubtree) { + unique_ref LeafTraverser::traverseAndReturnRoot(unique_ref root, uint32_t beginIndex, uint32_t endIndex, function onExistingLeaf, function onCreateLeaf, function onBacktrackFromSubtree) { return _traverseAndReturnRoot(std::move(root), beginIndex, endIndex, true, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); } - unique_ref LeafTraverser::_traverseAndReturnRoot(unique_ref root, uint32_t beginIndex, uint32_t endIndex, bool isLeftBorderOfTraversal, function onExistingLeaf, function onCreateLeaf, function onBacktrackFromSubtree) { + unique_ref LeafTraverser::_traverseAndReturnRoot(unique_ref root, uint32_t beginIndex, uint32_t endIndex, bool isLeftBorderOfTraversal, function onExistingLeaf, function onCreateLeaf, function onBacktrackFromSubtree) { ASSERT(beginIndex <= endIndex, "Invalid parameters"); //TODO Test cases with numLeaves < / >= beginIndex, ideally test all configurations: @@ -47,13 +47,13 @@ namespace blobstore { leaf->resize(_nodeStore->layout().maxBytesPerLeaf()); } if (beginIndex == 0 && endIndex == 1) { - onExistingLeaf(0, LeafHandle(_nodeStore, leaf)); + onExistingLeaf(0, true, LeafHandle(_nodeStore, leaf)); } } else { DataInnerNode *inner = dynamic_cast(root.get()); ASSERT(inner != nullptr, "Depth != 0 has to be leaf node"); _traverseExistingSubtree(inner, std::min(beginIndex, maxLeavesForDepth), - std::min(endIndex, maxLeavesForDepth), 0, isLeftBorderOfTraversal, + std::min(endIndex, maxLeavesForDepth), 0, isLeftBorderOfTraversal, true, increaseTreeDepth, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); } @@ -77,7 +77,7 @@ namespace blobstore { return DataNode::convertToNewInnerNode(std::move(root), _nodeStore->layout(), *copyOfOldRoot); } - void LeafTraverser::_traverseExistingSubtree(const blockstore::Key &key, uint8_t depth, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool growLastLeaf, function onExistingLeaf, function onCreateLeaf, function onBacktrackFromSubtree) { + void LeafTraverser::_traverseExistingSubtree(const blockstore::Key &key, uint8_t depth, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool isRightBorderNode, bool growLastLeaf, function onExistingLeaf, function onCreateLeaf, function onBacktrackFromSubtree) { if (depth == 0) { ASSERT(beginIndex <= 1 && endIndex <= 1, "If root node is a leaf, the (sub)tree has only one leaf - access indices must be 0 or 1."); @@ -88,7 +88,7 @@ namespace blobstore { } } if (beginIndex == 0 && endIndex == 1) { - onExistingLeaf(leafOffset, std::move(leafHandle)); + onExistingLeaf(leafOffset, isRightBorderNode, std::move(leafHandle)); } } else { auto node = _nodeStore->load(key); @@ -100,11 +100,11 @@ namespace blobstore { ASSERT(inner != none, "Has to be either leaf or inner node"); ASSERT((*inner)->depth() == depth, "Wrong depth given"); _traverseExistingSubtree(inner->get(), beginIndex, endIndex, leafOffset, isLeftBorderOfTraversal, - growLastLeaf, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); + isRightBorderNode, growLastLeaf, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); } } - void LeafTraverser::_traverseExistingSubtree(DataInnerNode *root, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool growLastLeaf, function onExistingLeaf, function onCreateLeaf, function onBacktrackFromSubtree) { + void LeafTraverser::_traverseExistingSubtree(DataInnerNode *root, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool isRightBorderNode, bool growLastLeaf, function onExistingLeaf, function onCreateLeaf, function onBacktrackFromSubtree) { ASSERT(beginIndex <= endIndex, "Invalid parameters"); //TODO Call callbacks for different leaves in parallel. @@ -123,8 +123,8 @@ namespace blobstore { ASSERT(numChildren > 0, "Node doesn't have children."); auto childKey = root->getChild(numChildren-1)->key(); uint32_t childOffset = (numChildren-1) * leavesPerChild; - _traverseExistingSubtree(childKey, root->depth()-1, leavesPerChild, leavesPerChild, childOffset, true, true, - [] (uint32_t /*index*/, LeafHandle /*leaf*/) {ASSERT(false, "We don't actually traverse any leaves.");}, + _traverseExistingSubtree(childKey, root->depth()-1, leavesPerChild, leavesPerChild, childOffset, true, false, true, + [] (uint32_t /*index*/, bool /*isRightBorderNode*/, LeafHandle /*leaf*/) {ASSERT(false, "We don't actually traverse any leaves.");}, [] (uint32_t /*index*/) -> Data {ASSERT(false, "We don't actually traverse any leaves.");}, [] (DataInnerNode* /*node*/) {ASSERT(false, "We don't actually traverse any leaves.");}); } @@ -136,10 +136,11 @@ namespace blobstore { uint32_t localBeginIndex = utils::maxZeroSubtraction(beginIndex, childOffset); uint32_t localEndIndex = std::min(leavesPerChild, endIndex - childOffset); bool isFirstChild = (childIndex == beginChild); - bool isLastChild = (childIndex == numChildren - 1); + bool isLastExistingChild = (childIndex == numChildren - 1); + bool isLastChild = isLastExistingChild && (numChildren == endChild); ASSERT(localEndIndex <= leavesPerChild, "We don't want the child to add a tree level because it doesn't have enough space for the traversal."); _traverseExistingSubtree(childKey, root->depth()-1, localBeginIndex, localEndIndex, leafOffset + childOffset, isLeftBorderOfTraversal && isFirstChild, - shouldGrowLastExistingLeaf && isLastChild, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); + isRightBorderNode && isLastChild, shouldGrowLastExistingLeaf && isLastExistingChild, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); } // Traverse new children (including gap children, i.e. children that are created but not traversed because they're to the right of the current size, but to the left of the traversal region) diff --git a/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.h b/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.h index 428875c4..915eb6c4 100644 --- a/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.h +++ b/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.h @@ -29,7 +29,7 @@ namespace blobstore { cpputils::unique_ref traverseAndReturnRoot( cpputils::unique_ref root, uint32_t beginIndex, uint32_t endIndex, - std::function onExistingLeaf, + std::function onExistingLeaf, std::function onCreateLeaf, std::function onBacktrackFromSubtree); @@ -38,15 +38,15 @@ namespace blobstore { cpputils::unique_ref _traverseAndReturnRoot( cpputils::unique_ref root, uint32_t beginIndex, uint32_t endIndex, bool isLeftBorderOfTraversal, - std::function onExistingLeaf, + std::function onExistingLeaf, std::function onCreateLeaf, std::function onBacktrackFromSubtree); - void _traverseExistingSubtree(datanodestore::DataInnerNode *root, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool growLastLeaf, - std::function onExistingLeaf, + void _traverseExistingSubtree(datanodestore::DataInnerNode *root, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool isRightBorderNode, bool growLastLeaf, + std::function onExistingLeaf, std::function onCreateLeaf, std::function onBacktrackFromSubtree); - void _traverseExistingSubtree(const blockstore::Key &key, uint8_t depth, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool growLastLeaf, - std::function onExistingLeaf, + void _traverseExistingSubtree(const blockstore::Key &key, uint8_t depth, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool isRightBorderNode, bool growLastLeaf, + std::function onExistingLeaf, std::function onCreateLeaf, std::function onBacktrackFromSubtree); cpputils::unique_ref _increaseTreeDepth(cpputils::unique_ref root); diff --git a/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/DataTreeRef.h b/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/DataTreeRef.h index 7f8a7025..26ac1f3e 100644 --- a/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/DataTreeRef.h +++ b/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/DataTreeRef.h @@ -22,7 +22,7 @@ public: return _baseTree->maxBytesPerLeaf(); } - void traverseLeaves(uint32_t beginIndex, uint32_t endIndex, std::function onExistingLeaf, std::function onCreateLeaf) { + void traverseLeaves(uint32_t beginIndex, uint32_t endIndex, std::function onExistingLeaf, std::function onCreateLeaf) { return _baseTree->traverseLeaves(beginIndex, endIndex, onExistingLeaf, onCreateLeaf); } diff --git a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_Performance.cpp b/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_Performance.cpp index b2563091..718f18e5 100644 --- a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_Performance.cpp +++ b/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_Performance.cpp @@ -16,7 +16,7 @@ using cpputils::make_unique_ref; class DataTreeTest_Performance: public DataTreeTest { public: void Traverse(DataTree *tree, uint64_t beginIndex, uint64_t endIndex) { - tree->traverseLeaves(beginIndex, endIndex, [] (uint32_t /*index*/, LeafHandle /*leaf*/) {}, [this] (uint32_t /*index*/) -> Data {return Data(maxChildrenPerInnerNode).FillWithZeroes();}); + tree->traverseLeaves(beginIndex, endIndex, [] (uint32_t /*index*/, bool /*isRightBorderNode*/, LeafHandle /*leaf*/) {}, [this] (uint32_t /*index*/) -> Data {return Data(maxChildrenPerInnerNode).FillWithZeroes();}); } uint64_t maxChildrenPerInnerNode = nodeStore->layout().maxChildrenPerInnerNode(); diff --git a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_ResizeByTraversing.cpp b/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_ResizeByTraversing.cpp index ee5057e1..9cbb6d55 100644 --- a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_ResizeByTraversing.cpp +++ b/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_ResizeByTraversing.cpp @@ -111,7 +111,7 @@ public: void GrowTree(DataTree *tree) { uint64_t maxBytesPerLeaf = tree->maxBytesPerLeaf(); - tree->traverseLeaves(traversalBeginIndex, newNumberOfLeaves, [] (uint32_t, LeafHandle){}, [maxBytesPerLeaf] (uint32_t) -> Data { return Data(maxBytesPerLeaf).FillWithZeroes();}); + tree->traverseLeaves(traversalBeginIndex, newNumberOfLeaves, [] (uint32_t, bool, LeafHandle){}, [maxBytesPerLeaf] (uint32_t) -> Data { return Data(maxBytesPerLeaf).FillWithZeroes();}); tree->flush(); } diff --git a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_TraverseLeaves.cpp b/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_TraverseLeaves.cpp index bc669c30..a2da6dfb 100644 --- a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_TraverseLeaves.cpp +++ b/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_TraverseLeaves.cpp @@ -16,7 +16,7 @@ using std::shared_ptr; class TraversorMock { public: - MOCK_METHOD2(calledExistingLeaf, void(DataLeafNode*, uint32_t)); + MOCK_METHOD3(calledExistingLeaf, void(DataLeafNode*, bool, uint32_t)); MOCK_METHOD1(calledCreateLeaf, shared_ptr(uint32_t)); }; @@ -46,26 +46,26 @@ public: }); } - void EXPECT_TRAVERSE_LEAF(const Key &key, uint32_t leafIndex) { - EXPECT_CALL(traversor, calledExistingLeaf(KeyEq(key), leafIndex)).Times(1); + void EXPECT_TRAVERSE_LEAF(const Key &key, bool isRightBorderLeaf, uint32_t leafIndex) { + EXPECT_CALL(traversor, calledExistingLeaf(KeyEq(key), isRightBorderLeaf, leafIndex)).Times(1); } - void EXPECT_TRAVERSE_ALL_CHILDREN_OF(const DataInnerNode &node, uint32_t firstLeafIndex) { + void EXPECT_TRAVERSE_ALL_CHILDREN_OF(const DataInnerNode &node, bool isRightBorderNode, uint32_t firstLeafIndex) { for (unsigned int i = 0; i < node.numChildren(); ++i) { - EXPECT_TRAVERSE_LEAF(node.getChild(i)->key(), firstLeafIndex+i); + EXPECT_TRAVERSE_LEAF(node.getChild(i)->key(), isRightBorderNode && i == node.numChildren()-1, firstLeafIndex+i); } } void EXPECT_DONT_TRAVERSE_ANY_LEAVES() { - EXPECT_CALL(traversor, calledExistingLeaf(_, _)).Times(0); + EXPECT_CALL(traversor, calledExistingLeaf(_, _, _)).Times(0); EXPECT_CALL(traversor, calledCreateLeaf(_)).Times(0); } void TraverseLeaves(DataNode *root, uint32_t beginIndex, uint32_t endIndex) { root->flush(); auto tree = treeStore.load(root->key()).value(); - tree->traverseLeaves(beginIndex, endIndex, [this] (uint32_t nodeIndex, LeafHandle leaf) { - traversor.calledExistingLeaf(leaf.node(), nodeIndex); + tree->traverseLeaves(beginIndex, endIndex, [this] (uint32_t nodeIndex, bool isRightBorderNode,LeafHandle leaf) { + traversor.calledExistingLeaf(leaf.node(), isRightBorderNode, nodeIndex); }, [this] (uint32_t nodeIndex) -> Data { return traversor.calledCreateLeaf(nodeIndex)->copy(); }); @@ -76,7 +76,7 @@ public: TEST_F(DataTreeTest_TraverseLeaves, TraverseSingleLeafTree) { auto root = CreateLeaf(); - EXPECT_TRAVERSE_LEAF(root->key(), 0); + EXPECT_TRAVERSE_LEAF(root->key(), true, 0); TraverseLeaves(root.get(), 0, 1); } @@ -97,21 +97,21 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseNothingInSingleLeafTree2) { TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstLeafOfFullTwolevelTree) { auto root = CreateFullTwoLevel(); - EXPECT_TRAVERSE_LEAF(root->getChild(0)->key(), 0); + EXPECT_TRAVERSE_LEAF(root->getChild(0)->key(), false, 0); TraverseLeaves(root.get(), 0, 1); } TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddleLeafOfFullTwolevelTree) { auto root = CreateFullTwoLevel(); - EXPECT_TRAVERSE_LEAF(root->getChild(5)->key(), 5); + EXPECT_TRAVERSE_LEAF(root->getChild(5)->key(), false, 5); TraverseLeaves(root.get(), 5, 6); } TEST_F(DataTreeTest_TraverseLeaves, TraverseLastLeafOfFullTwolevelTree) { auto root = CreateFullTwoLevel(); - EXPECT_TRAVERSE_LEAF(root->getChild(nodeStore->layout().maxChildrenPerInnerNode()-1)->key(), nodeStore->layout().maxChildrenPerInnerNode()-1); + EXPECT_TRAVERSE_LEAF(root->getChild(nodeStore->layout().maxChildrenPerInnerNode()-1)->key(), true, nodeStore->layout().maxChildrenPerInnerNode()-1); TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode()-1, nodeStore->layout().maxChildrenPerInnerNode()); } @@ -132,43 +132,43 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseNothingInFullTwolevelTree2) { TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstLeafOfThreeLevelMinDataTree) { auto root = CreateThreeLevelMinData(); - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(0)->key())->getChild(0)->key(), 0); + EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(0)->key())->getChild(0)->key(), false, 0); TraverseLeaves(root.get(), 0, 1); } TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddleLeafOfThreeLevelMinDataTree) { auto root = CreateThreeLevelMinData(); - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(0)->key())->getChild(5)->key(), 5); + EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(0)->key())->getChild(5)->key(), false, 5); TraverseLeaves(root.get(), 5, 6); } TEST_F(DataTreeTest_TraverseLeaves, TraverseLastLeafOfThreeLevelMinDataTree) { auto root = CreateThreeLevelMinData(); - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), nodeStore->layout().maxChildrenPerInnerNode()); + EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), true, nodeStore->layout().maxChildrenPerInnerNode()); TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode(), nodeStore->layout().maxChildrenPerInnerNode()+1); } TEST_F(DataTreeTest_TraverseLeaves, TraverseAllLeavesOfFullTwolevelTree) { auto root = CreateFullTwoLevel(); - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*root, 0); + EXPECT_TRAVERSE_ALL_CHILDREN_OF(*root, true, 0); TraverseLeaves(root.get(), 0, nodeStore->layout().maxChildrenPerInnerNode()); } TEST_F(DataTreeTest_TraverseLeaves, TraverseAllLeavesOfThreelevelMinDataTree) { auto root = CreateThreeLevelMinData(); - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(0)->key()), 0); - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), nodeStore->layout().maxChildrenPerInnerNode()); + EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(0)->key()), false, 0); + EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), true, nodeStore->layout().maxChildrenPerInnerNode()); TraverseLeaves(root.get(), 0, nodeStore->layout().maxChildrenPerInnerNode()+1); } TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstChildOfThreelevelMinDataTree) { auto root = CreateThreeLevelMinData(); - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(0)->key()), 0); + EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(0)->key()), false, 0); TraverseLeaves(root.get(), 0, nodeStore->layout().maxChildrenPerInnerNode()); } @@ -176,7 +176,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstChildOfThreelevelMinDataTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstPartOfFullTwolevelTree) { auto root = CreateFullTwoLevel(); for (unsigned int i = 0; i < 5; ++i) { - EXPECT_TRAVERSE_LEAF(root->getChild(i)->key(), i); + EXPECT_TRAVERSE_LEAF(root->getChild(i)->key(), false, i); } TraverseLeaves(root.get(), 0, 5); @@ -185,7 +185,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstPartOfFullTwolevelTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseInnerPartOfFullTwolevelTree) { auto root = CreateFullTwoLevel(); for (unsigned int i = 5; i < 10; ++i) { - EXPECT_TRAVERSE_LEAF(root->getChild(i)->key(), i); + EXPECT_TRAVERSE_LEAF(root->getChild(i)->key(), false, i); } TraverseLeaves(root.get(), 5, 10); @@ -194,7 +194,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseInnerPartOfFullTwolevelTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseLastPartOfFullTwolevelTree) { auto root = CreateFullTwoLevel(); for (unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { - EXPECT_TRAVERSE_LEAF(root->getChild(i)->key(), i); + EXPECT_TRAVERSE_LEAF(root->getChild(i)->key(), i==nodeStore->layout().maxChildrenPerInnerNode()-1, i); } TraverseLeaves(root.get(), 5, nodeStore->layout().maxChildrenPerInnerNode()); @@ -204,7 +204,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstPartOfThreelevelMinDataTree) { auto root = CreateThreeLevelMinData(); auto node = LoadInnerNode(root->getChild(0)->key()); for (unsigned int i = 0; i < 5; ++i) { - EXPECT_TRAVERSE_LEAF(node->getChild(i)->key(), i); + EXPECT_TRAVERSE_LEAF(node->getChild(i)->key(), false, i); } TraverseLeaves(root.get(), 0, 5); @@ -214,7 +214,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseInnerPartOfThreelevelMinDataTree) { auto root = CreateThreeLevelMinData(); auto node = LoadInnerNode(root->getChild(0)->key()); for (unsigned int i = 5; i < 10; ++i) { - EXPECT_TRAVERSE_LEAF(node->getChild(i)->key(), i); + EXPECT_TRAVERSE_LEAF(node->getChild(i)->key(), false, i); } TraverseLeaves(root.get(), 5, 10); @@ -224,16 +224,16 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseLastPartOfThreelevelMinDataTree) { auto root = CreateThreeLevelMinData(); auto node = LoadInnerNode(root->getChild(0)->key()); for (unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { - EXPECT_TRAVERSE_LEAF(node->getChild(i)->key(), i); + EXPECT_TRAVERSE_LEAF(node->getChild(i)->key(), false, i); } - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), nodeStore->layout().maxChildrenPerInnerNode()); + EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), true, nodeStore->layout().maxChildrenPerInnerNode()); TraverseLeaves(root.get(), 5, nodeStore->layout().maxChildrenPerInnerNode()+1); } TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstLeafOfThreelevelTree) { auto root = CreateThreeLevel(); - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(0)->key())->getChild(0)->key(), 0); + EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(0)->key())->getChild(0)->key(), false, 0); TraverseLeaves(root.get(), 0, 1); } @@ -241,7 +241,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstLeafOfThreelevelTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseLastLeafOfThreelevelTree) { auto root = CreateThreeLevel(); uint32_t numLeaves = nodeStore->layout().maxChildrenPerInnerNode() * 5 + 3; - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->LastChild()->key())->LastChild()->key(), numLeaves-1); + EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->LastChild()->key())->LastChild()->key(), true, numLeaves-1); TraverseLeaves(root.get(), numLeaves-1, numLeaves); } @@ -249,7 +249,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseLastLeafOfThreelevelTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddleLeafOfThreelevelTree) { auto root = CreateThreeLevel(); uint32_t wantedLeafIndex = nodeStore->layout().maxChildrenPerInnerNode() * 2 + 5; - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(2)->key())->getChild(5)->key(), wantedLeafIndex); + EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(2)->key())->getChild(5)->key(), false, wantedLeafIndex); TraverseLeaves(root.get(), wantedLeafIndex, wantedLeafIndex+1); } @@ -258,12 +258,12 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstPartOfThreelevelTree) { auto root = CreateThreeLevel(); //Traverse all leaves in the first two children of the root for(unsigned int i = 0; i < 2; ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode()); + EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), false, i * nodeStore->layout().maxChildrenPerInnerNode()); } //Traverse some of the leaves in the third child of the root auto child = LoadInnerNode(root->getChild(2)->key()); for(unsigned int i = 0; i < 5; ++i) { - EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 2 * nodeStore->layout().maxChildrenPerInnerNode() + i); + EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), false, 2 * nodeStore->layout().maxChildrenPerInnerNode() + i); } TraverseLeaves(root.get(), 0, 2 * nodeStore->layout().maxChildrenPerInnerNode() + 5); @@ -274,16 +274,16 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddlePartOfThreelevelTree_OnlyFullC //Traverse some of the leaves in the second child of the root auto child = LoadInnerNode(root->getChild(1)->key()); for(unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { - EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), nodeStore->layout().maxChildrenPerInnerNode() + i); + EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), false, nodeStore->layout().maxChildrenPerInnerNode() + i); } //Traverse all leaves in the third and fourth child of the root for(unsigned int i = 2; i < 4; ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode()); + EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()),false, i * nodeStore->layout().maxChildrenPerInnerNode()); } //Traverse some of the leaves in the fifth child of the root child = LoadInnerNode(root->getChild(4)->key()); for(unsigned int i = 0; i < 5; ++i) { - EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 4 * nodeStore->layout().maxChildrenPerInnerNode() + i); + EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), false, 4 * nodeStore->layout().maxChildrenPerInnerNode() + i); } TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode() + 5, 4 * nodeStore->layout().maxChildrenPerInnerNode() + 5); @@ -294,16 +294,16 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddlePartOfThreelevelTree_AlsoLastN //Traverse some of the leaves in the second child of the root auto child = LoadInnerNode(root->getChild(1)->key()); for(unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { - EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), nodeStore->layout().maxChildrenPerInnerNode() + i); + EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), false, nodeStore->layout().maxChildrenPerInnerNode() + i); } //Traverse all leaves in the third, fourth and fifth child of the root for(unsigned int i = 2; i < 5; ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode()); + EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), false, i * nodeStore->layout().maxChildrenPerInnerNode()); } //Traverse some of the leaves in the sixth child of the root child = LoadInnerNode(root->getChild(5)->key()); for(unsigned int i = 0; i < 2; ++i) { - EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 5 * nodeStore->layout().maxChildrenPerInnerNode() + i); + EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), false, 5 * nodeStore->layout().maxChildrenPerInnerNode() + i); } TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode() + 5, 5 * nodeStore->layout().maxChildrenPerInnerNode() + 2); @@ -314,16 +314,16 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseLastPartOfThreelevelTree) { //Traverse some of the leaves in the second child of the root auto child = LoadInnerNode(root->getChild(1)->key()); for(unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { - EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), nodeStore->layout().maxChildrenPerInnerNode() + i); + EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), false, nodeStore->layout().maxChildrenPerInnerNode() + i); } //Traverse all leaves in the third, fourth and fifth child of the root for(unsigned int i = 2; i < 5; ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode()); + EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), false, i * nodeStore->layout().maxChildrenPerInnerNode()); } //Traverse all of the leaves in the sixth child of the root child = LoadInnerNode(root->getChild(5)->key()); for(unsigned int i = 0; i < child->numChildren(); ++i) { - EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 5 * nodeStore->layout().maxChildrenPerInnerNode() + i); + EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), i == child->numChildren()-1, 5 * nodeStore->layout().maxChildrenPerInnerNode() + i); } TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode() + 5, 5 * nodeStore->layout().maxChildrenPerInnerNode() + child->numChildren()); @@ -333,12 +333,12 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseAllLeavesOfThreelevelTree) { auto root = CreateThreeLevel(); //Traverse all leaves in the third, fourth and fifth child of the root for(unsigned int i = 0; i < 5; ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode()); + EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), false, i * nodeStore->layout().maxChildrenPerInnerNode()); } //Traverse all of the leaves in the sixth child of the root auto child = LoadInnerNode(root->getChild(5)->key()); for(unsigned int i = 0; i < child->numChildren(); ++i) { - EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 5 * nodeStore->layout().maxChildrenPerInnerNode() + i); + EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), i==child->numChildren()-1, 5 * nodeStore->layout().maxChildrenPerInnerNode() + i); } TraverseLeaves(root.get(), 0, 5 * nodeStore->layout().maxChildrenPerInnerNode() + child->numChildren()); @@ -349,17 +349,17 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseAllLeavesOfFourLevelTree) { //Traverse all leaves of the full threelevel tree in the first child auto firstChild = LoadInnerNode(root->getChild(0)->key()); for(unsigned int i = 0; i < firstChild->numChildren(); ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(firstChild->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode()); + EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(firstChild->getChild(i)->key()), false, i * nodeStore->layout().maxChildrenPerInnerNode()); } //Traverse all leaves of the full threelevel tree in the second child auto secondChild = LoadInnerNode(root->getChild(1)->key()); for(unsigned int i = 0; i < secondChild->numChildren(); ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(secondChild->getChild(i)->key()), (nodeStore->layout().maxChildrenPerInnerNode() + i) * nodeStore->layout().maxChildrenPerInnerNode()); + EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(secondChild->getChild(i)->key()), false, (nodeStore->layout().maxChildrenPerInnerNode() + i) * nodeStore->layout().maxChildrenPerInnerNode()); } //Traverse all leaves of the non-full threelevel tree in the third child auto thirdChild = LoadInnerNode(root->getChild(2)->key()); - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(thirdChild->getChild(0)->key()), 2 * nodeStore->layout().maxChildrenPerInnerNode() * nodeStore->layout().maxChildrenPerInnerNode()); - EXPECT_TRAVERSE_LEAF(LoadInnerNode(thirdChild->getChild(1)->key())->getChild(0)->key(), 2 * nodeStore->layout().maxChildrenPerInnerNode() * nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode()); + EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(thirdChild->getChild(0)->key()), false, 2 * nodeStore->layout().maxChildrenPerInnerNode() * nodeStore->layout().maxChildrenPerInnerNode()); + EXPECT_TRAVERSE_LEAF(LoadInnerNode(thirdChild->getChild(1)->key())->getChild(0)->key(), true, 2 * nodeStore->layout().maxChildrenPerInnerNode() * nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode()); TraverseLeaves(root.get(), 0, 2*nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode() + 1); } @@ -370,21 +370,21 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddlePartOfFourLevelTree) { auto firstChild = LoadInnerNode(root->getChild(0)->key()); auto secondChildOfFirstChild = LoadInnerNode(firstChild->getChild(1)->key()); for(unsigned int i = 5; i < secondChildOfFirstChild->numChildren(); ++i) { - EXPECT_TRAVERSE_LEAF(secondChildOfFirstChild->getChild(i)->key(), nodeStore->layout().maxChildrenPerInnerNode()+i); + EXPECT_TRAVERSE_LEAF(secondChildOfFirstChild->getChild(i)->key(), false, nodeStore->layout().maxChildrenPerInnerNode()+i); } for(unsigned int i = 2; i < firstChild->numChildren(); ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(firstChild->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode()); + EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(firstChild->getChild(i)->key()), false, i * nodeStore->layout().maxChildrenPerInnerNode()); } //Traverse all leaves of the full threelevel tree in the second child auto secondChild = LoadInnerNode(root->getChild(1)->key()); for(unsigned int i = 0; i < secondChild->numChildren(); ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(secondChild->getChild(i)->key()), (nodeStore->layout().maxChildrenPerInnerNode() + i) * nodeStore->layout().maxChildrenPerInnerNode()); + EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(secondChild->getChild(i)->key()), false, (nodeStore->layout().maxChildrenPerInnerNode() + i) * nodeStore->layout().maxChildrenPerInnerNode()); } //Traverse some leaves of the non-full threelevel tree in the third child auto thirdChild = LoadInnerNode(root->getChild(2)->key()); auto firstChildOfThirdChild = LoadInnerNode(thirdChild->getChild(0)->key()); for(unsigned int i = 0; i < firstChildOfThirdChild->numChildren()-1; ++i) { - EXPECT_TRAVERSE_LEAF(firstChildOfThirdChild->getChild(i)->key(), 2 * nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode()+i); + EXPECT_TRAVERSE_LEAF(firstChildOfThirdChild->getChild(i)->key(), false, 2 * nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode()+i); } TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode()+5, 2*nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode() -1); @@ -394,7 +394,7 @@ 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, LeafHandle leaf) { + tree->traverseLeaves(0, 2, [this] (uint32_t leafIndex, bool /*isRightBorderNode*/, LeafHandle leaf) { if (leafIndex == 0) { EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf(), leaf.node()->numBytes()); } else { @@ -409,7 +409,7 @@ 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*/, LeafHandle leaf) { + tree->traverseLeaves(0, nodeStore->layout().maxChildrenPerInnerNode()+1, [this] (uint32_t /*leafIndex*/, bool /*isRightBorderNode*/, LeafHandle leaf) { EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf(), leaf.node()->numBytes()); }, [this] (uint32_t /*nodeIndex*/) -> Data { return Data(1);