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:
parent
b339261924
commit
bbdd8a548b
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user