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.

This commit is contained in:
Sebastian Messmer 2016-07-17 10:16:09 +02:00
parent b339261924
commit bbdd8a548b
9 changed files with 84 additions and 82 deletions

View File

@ -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);
}

View File

@ -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<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf) {
void DataTree::traverseLeaves(uint32_t beginIndex, uint32_t endIndex, function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf) {
//TODO Can we allow multiple runs of traverseLeaves() in parallel? Also in parallel with resizeNumBytes()?
std::unique_lock<shared_mutex> lock(_mutex);
ASSERT(beginIndex <= endIndex, "Invalid parameters");
@ -111,7 +111,7 @@ void DataTree::traverseLeaves(uint32_t beginIndex, uint32_t endIndex, function<v
}
void DataTree::_traverseLeaves(uint32_t beginIndex, uint32_t endIndex,
function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf,
function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf,
function<Data (uint32_t index)> onCreateLeaf,
function<void (DataInnerNode *node)> 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) {

View File

@ -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<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, std::function<cpputils::Data (uint32_t index)> onCreateLeaf);
void traverseLeaves(uint32_t beginIndex, uint32_t endIndex, std::function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf, std::function<cpputils::Data (uint32_t index)> 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<void (uint32_t index, LeafHandle leaf)> onExistingLeaf,
std::function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf,
std::function<cpputils::Data (uint32_t index)> onCreateLeaf,
std::function<void (datanodestore::DataInnerNode *node)> onBacktrackFromSubtree);
uint32_t leavesPerFullChild(const datanodestore::DataInnerNode &root) const;

View File

@ -24,11 +24,11 @@ namespace blobstore {
: _nodeStore(nodeStore) {
}
unique_ref<DataNode> LeafTraverser::traverseAndReturnRoot(unique_ref<DataNode> root, uint32_t beginIndex, uint32_t endIndex, function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> onBacktrackFromSubtree) {
unique_ref<DataNode> LeafTraverser::traverseAndReturnRoot(unique_ref<DataNode> root, uint32_t beginIndex, uint32_t endIndex, function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> onBacktrackFromSubtree) {
return _traverseAndReturnRoot(std::move(root), beginIndex, endIndex, true, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree);
}
unique_ref<DataNode> LeafTraverser::_traverseAndReturnRoot(unique_ref<DataNode> root, uint32_t beginIndex, uint32_t endIndex, bool isLeftBorderOfTraversal, function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> onBacktrackFromSubtree) {
unique_ref<DataNode> LeafTraverser::_traverseAndReturnRoot(unique_ref<DataNode> root, uint32_t beginIndex, uint32_t endIndex, bool isLeftBorderOfTraversal, function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> 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<DataInnerNode*>(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<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> 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<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> 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<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> onBacktrackFromSubtree) {
void LeafTraverser::_traverseExistingSubtree(DataInnerNode *root, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool isRightBorderNode, bool growLastLeaf, function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> 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)

View File

@ -29,7 +29,7 @@ namespace blobstore {
cpputils::unique_ref<datanodestore::DataNode> traverseAndReturnRoot(
cpputils::unique_ref<datanodestore::DataNode> root, uint32_t beginIndex, uint32_t endIndex,
std::function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf,
std::function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf,
std::function<cpputils::Data (uint32_t index)> onCreateLeaf,
std::function<void (datanodestore::DataInnerNode *node)> onBacktrackFromSubtree);
@ -38,15 +38,15 @@ namespace blobstore {
cpputils::unique_ref<datanodestore::DataNode> _traverseAndReturnRoot(
cpputils::unique_ref<datanodestore::DataNode> root, uint32_t beginIndex, uint32_t endIndex, bool isLeftBorderOfTraversal,
std::function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf,
std::function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf,
std::function<cpputils::Data (uint32_t index)> onCreateLeaf,
std::function<void (datanodestore::DataInnerNode *node)> onBacktrackFromSubtree);
void _traverseExistingSubtree(datanodestore::DataInnerNode *root, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool growLastLeaf,
std::function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf,
void _traverseExistingSubtree(datanodestore::DataInnerNode *root, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool isRightBorderNode, bool growLastLeaf,
std::function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf,
std::function<cpputils::Data (uint32_t index)> onCreateLeaf,
std::function<void (datanodestore::DataInnerNode *node)> 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<void (uint32_t index, LeafHandle leaf)> 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<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf,
std::function<cpputils::Data (uint32_t index)> onCreateLeaf,
std::function<void (datanodestore::DataInnerNode *node)> onBacktrackFromSubtree);
cpputils::unique_ref<datanodestore::DataInnerNode> _increaseTreeDepth(cpputils::unique_ref<datanodestore::DataNode> root);

View File

@ -22,7 +22,7 @@ public:
return _baseTree->maxBytesPerLeaf();
}
void traverseLeaves(uint32_t beginIndex, uint32_t endIndex, std::function<void (uint32_t index, datatreestore::LeafHandle leaf)> onExistingLeaf, std::function<cpputils::Data (uint32_t index)> onCreateLeaf) {
void traverseLeaves(uint32_t beginIndex, uint32_t endIndex, std::function<void (uint32_t index, bool isRightBorderLeaf, datatreestore::LeafHandle leaf)> onExistingLeaf, std::function<cpputils::Data (uint32_t index)> onCreateLeaf) {
return _baseTree->traverseLeaves(beginIndex, endIndex, onExistingLeaf, onCreateLeaf);
}

View File

@ -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();

View File

@ -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();
}

View File

@ -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<Data>(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);