2015-02-26 17:05:05 +01:00
|
|
|
#include "testutils/DataTreeTest.h"
|
2019-01-13 08:21:12 +01:00
|
|
|
#include <blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.h>
|
2016-02-11 15:19:58 +01:00
|
|
|
#include <gmock/gmock.h>
|
2015-02-25 01:31:16 +01:00
|
|
|
|
|
|
|
using ::testing::_;
|
2016-09-07 22:25:18 +02:00
|
|
|
using ::testing::Invoke;
|
|
|
|
using ::testing::Eq;
|
2015-02-25 01:31:16 +01:00
|
|
|
|
|
|
|
using blobstore::onblocks::datanodestore::DataLeafNode;
|
|
|
|
using blobstore::onblocks::datanodestore::DataInnerNode;
|
|
|
|
using blobstore::onblocks::datanodestore::DataNode;
|
2016-07-15 20:12:24 +02:00
|
|
|
using blobstore::onblocks::datatreestore::LeafHandle;
|
2019-01-13 08:21:12 +01:00
|
|
|
using blobstore::onblocks::datatreestore::LeafTraverser;
|
2017-09-17 03:07:27 +02:00
|
|
|
using blockstore::BlockId;
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2015-06-26 15:59:18 +02:00
|
|
|
using cpputils::unique_ref;
|
2016-07-10 22:57:39 +02:00
|
|
|
using cpputils::Data;
|
|
|
|
using std::shared_ptr;
|
2016-09-07 22:25:18 +02:00
|
|
|
using std::make_shared;
|
2015-02-25 16:52:17 +01:00
|
|
|
|
2015-02-25 01:31:16 +01:00
|
|
|
class TraversorMock {
|
|
|
|
public:
|
2016-07-17 10:16:09 +02:00
|
|
|
MOCK_METHOD3(calledExistingLeaf, void(DataLeafNode*, bool, uint32_t));
|
2016-07-10 22:57:39 +02:00
|
|
|
MOCK_METHOD1(calledCreateLeaf, shared_ptr<Data>(uint32_t));
|
2015-02-25 01:31:16 +01:00
|
|
|
};
|
|
|
|
|
2017-09-17 03:07:27 +02:00
|
|
|
MATCHER_P(KeyEq, expected, "node blockId equals") {
|
|
|
|
return arg->blockId() == expected;
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
class LeafTraverserTest: public DataTreeTest {
|
2015-02-25 01:31:16 +01:00
|
|
|
public:
|
2019-01-13 08:21:12 +01:00
|
|
|
LeafTraverserTest() :traversor() {}
|
2015-10-17 21:17:38 +02:00
|
|
|
|
2015-06-26 15:59:18 +02:00
|
|
|
unique_ref<DataInnerNode> CreateThreeLevel() {
|
2015-02-25 16:52:17 +01:00
|
|
|
return CreateInner({
|
|
|
|
CreateFullTwoLevel(),
|
|
|
|
CreateFullTwoLevel(),
|
|
|
|
CreateFullTwoLevel(),
|
|
|
|
CreateFullTwoLevel(),
|
|
|
|
CreateFullTwoLevel(),
|
|
|
|
CreateInner({CreateLeaf(), CreateLeaf(), CreateLeaf()})});
|
|
|
|
}
|
|
|
|
|
2015-06-26 15:59:18 +02:00
|
|
|
unique_ref<DataInnerNode> CreateFourLevel() {
|
2015-02-25 16:52:17 +01:00
|
|
|
return CreateInner({
|
|
|
|
CreateFullThreeLevel(),
|
|
|
|
CreateFullThreeLevel(),
|
|
|
|
CreateInner({CreateFullTwoLevel(), CreateInner({CreateLeaf()})})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-09-07 22:25:18 +02:00
|
|
|
void EXPECT_CREATE_LEAF(uint32_t leafIndex) {
|
|
|
|
uint64_t maxBytesPerLeaf = nodeStore->layout().maxBytesPerLeaf();
|
|
|
|
EXPECT_CALL(traversor, calledCreateLeaf(Eq(leafIndex))).Times(1).WillOnce(Invoke([maxBytesPerLeaf] (uint32_t) {
|
|
|
|
return make_shared<Data>(maxBytesPerLeaf);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2017-09-17 03:07:27 +02:00
|
|
|
void EXPECT_TRAVERSE_LEAF(const BlockId &blockId, bool isRightBorderLeaf, uint32_t leafIndex) {
|
|
|
|
EXPECT_CALL(traversor, calledExistingLeaf(KeyEq(blockId), isRightBorderLeaf, leafIndex)).Times(1);
|
2015-02-25 14:42:20 +01:00
|
|
|
}
|
|
|
|
|
2016-07-17 10:16:09 +02:00
|
|
|
void EXPECT_TRAVERSE_ALL_CHILDREN_OF(const DataInnerNode &node, bool isRightBorderNode, uint32_t firstLeafIndex) {
|
2015-05-08 02:10:40 +02:00
|
|
|
for (unsigned int i = 0; i < node.numChildren(); ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(node.readChild(i).blockId(), isRightBorderNode && i == node.numChildren()-1, firstLeafIndex+i);
|
2015-02-25 14:42:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EXPECT_DONT_TRAVERSE_ANY_LEAVES() {
|
2016-07-17 10:16:09 +02:00
|
|
|
EXPECT_CALL(traversor, calledExistingLeaf(_, _, _)).Times(0);
|
2016-07-10 22:57:39 +02:00
|
|
|
EXPECT_CALL(traversor, calledCreateLeaf(_)).Times(0);
|
2015-02-25 14:42:20 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
void TraverseLeaves(unique_ref<DataNode> root, uint32_t beginIndex, uint32_t endIndex, bool expectReadOnly) {
|
2015-02-25 01:31:16 +01:00
|
|
|
root->flush();
|
2017-09-17 03:07:27 +02:00
|
|
|
auto tree = treeStore.load(root->blockId()).value();
|
2019-01-13 08:21:12 +01:00
|
|
|
auto* old_root = root.get();
|
|
|
|
LeafTraverser(nodeStore, expectReadOnly).traverseAndUpdateRoot(&root, beginIndex, endIndex, [this] (uint32_t nodeIndex, bool isRightBorderNode,LeafHandle leaf) {
|
2016-07-17 10:16:09 +02:00
|
|
|
traversor.calledExistingLeaf(leaf.node(), isRightBorderNode, nodeIndex);
|
2016-07-10 22:57:39 +02:00
|
|
|
}, [this] (uint32_t nodeIndex) -> Data {
|
|
|
|
return traversor.calledCreateLeaf(nodeIndex)->copy();
|
2019-01-13 08:21:12 +01:00
|
|
|
}, [] (auto) {});
|
|
|
|
if (expectReadOnly) {
|
|
|
|
EXPECT_EQ(old_root, root.get());
|
|
|
|
} else {
|
|
|
|
EXPECT_NE(old_root, root.get());
|
|
|
|
}
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
2015-02-25 16:52:17 +01:00
|
|
|
|
2015-02-25 01:31:16 +01:00
|
|
|
TraversorMock traversor;
|
|
|
|
};
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseSingleLeafTree) {
|
|
|
|
unique_ref<DataNode> root = CreateLeaf();
|
2017-09-17 03:07:27 +02:00
|
|
|
EXPECT_TRAVERSE_LEAF(root->blockId(), true, 0);
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 0, 1, true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseNothingInSingleLeafTree1) {
|
|
|
|
unique_ref<DataNode> root = CreateLeaf();
|
2015-02-25 14:42:20 +01:00
|
|
|
EXPECT_DONT_TRAVERSE_ANY_LEAVES();
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 0, 0, true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseNothingInSingleLeafTree2) {
|
|
|
|
unique_ref<DataNode> root = CreateLeaf();
|
2015-02-25 14:42:20 +01:00
|
|
|
EXPECT_DONT_TRAVERSE_ANY_LEAVES();
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 1, 1, true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseFirstLeafOfFullTwolevelTree) {
|
2015-02-25 01:31:16 +01:00
|
|
|
auto root = CreateFullTwoLevel();
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(root->readChild(0).blockId(), false, 0);
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 0, 1, true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseMiddleLeafOfFullTwolevelTree) {
|
2015-02-25 01:31:16 +01:00
|
|
|
auto root = CreateFullTwoLevel();
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(root->readChild(5).blockId(), false, 5);
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 5, 6, true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseLastLeafOfFullTwolevelTree) {
|
2015-02-25 01:31:16 +01:00
|
|
|
auto root = CreateFullTwoLevel();
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(root->readChild(nodeStore->layout().maxChildrenPerInnerNode()-1).blockId(), true, nodeStore->layout().maxChildrenPerInnerNode()-1);
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), nodeStore->layout().maxChildrenPerInnerNode()-1, nodeStore->layout().maxChildrenPerInnerNode(), true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseNothingInFullTwolevelTree1) {
|
2015-02-25 01:31:16 +01:00
|
|
|
auto root = CreateFullTwoLevel();
|
2015-02-25 14:42:20 +01:00
|
|
|
EXPECT_DONT_TRAVERSE_ANY_LEAVES();
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 0, 0, true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseNothingInFullTwolevelTree2) {
|
2015-02-25 01:31:16 +01:00
|
|
|
auto root = CreateFullTwoLevel();
|
2015-02-25 14:42:20 +01:00
|
|
|
EXPECT_DONT_TRAVERSE_ANY_LEAVES();
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), nodeStore->layout().maxChildrenPerInnerNode(), nodeStore->layout().maxChildrenPerInnerNode(), true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseFirstLeafOfThreeLevelMinDataTree) {
|
2015-02-25 01:31:16 +01:00
|
|
|
auto root = CreateThreeLevelMinData();
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readChild(0).blockId())->readChild(0).blockId(), false, 0);
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 0, 1, true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseMiddleLeafOfThreeLevelMinDataTree) {
|
2015-02-25 01:31:16 +01:00
|
|
|
auto root = CreateThreeLevelMinData();
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readChild(0).blockId())->readChild(5).blockId(), false, 5);
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 5, 6, true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseLastLeafOfThreeLevelMinDataTree) {
|
2015-02-25 01:31:16 +01:00
|
|
|
auto root = CreateThreeLevelMinData();
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readChild(1).blockId())->readChild(0).blockId(), true, nodeStore->layout().maxChildrenPerInnerNode());
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), nodeStore->layout().maxChildrenPerInnerNode(), nodeStore->layout().maxChildrenPerInnerNode()+1, true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseAllLeavesOfFullTwolevelTree) {
|
2015-02-25 01:31:16 +01:00
|
|
|
auto root = CreateFullTwoLevel();
|
2016-07-17 10:16:09 +02:00
|
|
|
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*root, true, 0);
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 0, nodeStore->layout().maxChildrenPerInnerNode(), true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseAllLeavesOfThreelevelMinDataTree) {
|
2015-02-25 01:31:16 +01:00
|
|
|
auto root = CreateThreeLevelMinData();
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->readChild(0).blockId()), false, 0);
|
|
|
|
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readChild(1).blockId())->readChild(0).blockId(), true, nodeStore->layout().maxChildrenPerInnerNode());
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 0, nodeStore->layout().maxChildrenPerInnerNode()+1, true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseFirstChildOfThreelevelMinDataTree) {
|
2015-02-25 01:31:16 +01:00
|
|
|
auto root = CreateThreeLevelMinData();
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->readChild(0).blockId()), false, 0);
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 0, nodeStore->layout().maxChildrenPerInnerNode(), true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseFirstPartOfFullTwolevelTree) {
|
2015-02-25 16:52:17 +01:00
|
|
|
auto root = CreateFullTwoLevel();
|
2015-05-08 02:10:40 +02:00
|
|
|
for (unsigned int i = 0; i < 5; ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(root->readChild(i).blockId(), false, i);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 0, 5, true);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseInnerPartOfFullTwolevelTree) {
|
2015-02-25 16:52:17 +01:00
|
|
|
auto root = CreateFullTwoLevel();
|
2015-05-08 02:10:40 +02:00
|
|
|
for (unsigned int i = 5; i < 10; ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(root->readChild(i).blockId(), false, i);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 5, 10, true);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseLastPartOfFullTwolevelTree) {
|
2015-02-25 16:52:17 +01:00
|
|
|
auto root = CreateFullTwoLevel();
|
2015-05-08 02:10:40 +02:00
|
|
|
for (unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(root->readChild(i).blockId(), i==nodeStore->layout().maxChildrenPerInnerNode()-1, i);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 5, nodeStore->layout().maxChildrenPerInnerNode(), true);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseFirstPartOfThreelevelMinDataTree) {
|
2015-02-25 01:31:16 +01:00
|
|
|
auto root = CreateThreeLevelMinData();
|
2017-12-03 20:01:41 +01:00
|
|
|
auto node = LoadInnerNode(root->readChild(0).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for (unsigned int i = 0; i < 5; ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(node->readChild(i).blockId(), false, i);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 0, 5, true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseInnerPartOfThreelevelMinDataTree) {
|
2015-02-25 01:31:16 +01:00
|
|
|
auto root = CreateThreeLevelMinData();
|
2017-12-03 20:01:41 +01:00
|
|
|
auto node = LoadInnerNode(root->readChild(0).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for (unsigned int i = 5; i < 10; ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(node->readChild(i).blockId(), false, i);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 5, 10, true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseLastPartOfThreelevelMinDataTree) {
|
2015-02-25 01:31:16 +01:00
|
|
|
auto root = CreateThreeLevelMinData();
|
2017-12-03 20:01:41 +01:00
|
|
|
auto node = LoadInnerNode(root->readChild(0).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for (unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(node->readChild(i).blockId(), false, i);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readChild(1).blockId())->readChild(0).blockId(), true, nodeStore->layout().maxChildrenPerInnerNode());
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 5, nodeStore->layout().maxChildrenPerInnerNode()+1, true);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseFirstLeafOfThreelevelTree) {
|
2015-02-25 16:52:17 +01:00
|
|
|
auto root = CreateThreeLevel();
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readChild(0).blockId())->readChild(0).blockId(), false, 0);
|
2015-02-25 16:52:17 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 0, 1, true);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseLastLeafOfThreelevelTree) {
|
2015-02-25 16:52:17 +01:00
|
|
|
auto root = CreateThreeLevel();
|
2015-02-25 22:30:48 +01:00
|
|
|
uint32_t numLeaves = nodeStore->layout().maxChildrenPerInnerNode() * 5 + 3;
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readLastChild().blockId())->readLastChild().blockId(), true, numLeaves-1);
|
2015-02-25 16:52:17 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), numLeaves-1, numLeaves, true);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseMiddleLeafOfThreelevelTree) {
|
2015-02-25 16:52:17 +01:00
|
|
|
auto root = CreateThreeLevel();
|
2015-02-25 22:30:48 +01:00
|
|
|
uint32_t wantedLeafIndex = nodeStore->layout().maxChildrenPerInnerNode() * 2 + 5;
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readChild(2).blockId())->readChild(5).blockId(), false, wantedLeafIndex);
|
2015-02-25 16:52:17 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), wantedLeafIndex, wantedLeafIndex+1, true);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseFirstPartOfThreelevelTree) {
|
2015-02-25 16:52:17 +01:00
|
|
|
auto root = CreateThreeLevel();
|
|
|
|
//Traverse all leaves in the first two children of the root
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 0; i < 2; ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->readChild(i).blockId()), false, i * nodeStore->layout().maxChildrenPerInnerNode());
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
//Traverse some of the leaves in the third child of the root
|
2017-12-03 20:01:41 +01:00
|
|
|
auto child = LoadInnerNode(root->readChild(2).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 0; i < 5; ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), false, 2 * nodeStore->layout().maxChildrenPerInnerNode() + i);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 0, 2 * nodeStore->layout().maxChildrenPerInnerNode() + 5, true);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseMiddlePartOfThreelevelTree_OnlyFullChildren) {
|
2015-02-25 16:52:17 +01:00
|
|
|
auto root = CreateThreeLevel();
|
|
|
|
//Traverse some of the leaves in the second child of the root
|
2017-12-03 20:01:41 +01:00
|
|
|
auto child = LoadInnerNode(root->readChild(1).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), false, nodeStore->layout().maxChildrenPerInnerNode() + i);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
//Traverse all leaves in the third and fourth child of the root
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 2; i < 4; ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->readChild(i).blockId()),false, i * nodeStore->layout().maxChildrenPerInnerNode());
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
//Traverse some of the leaves in the fifth child of the root
|
2017-12-03 20:01:41 +01:00
|
|
|
child = LoadInnerNode(root->readChild(4).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 0; i < 5; ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), false, 4 * nodeStore->layout().maxChildrenPerInnerNode() + i);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), nodeStore->layout().maxChildrenPerInnerNode() + 5, 4 * nodeStore->layout().maxChildrenPerInnerNode() + 5, true);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseMiddlePartOfThreelevelTree_AlsoLastNonfullChild) {
|
2015-02-25 16:52:17 +01:00
|
|
|
auto root = CreateThreeLevel();
|
|
|
|
//Traverse some of the leaves in the second child of the root
|
2017-12-03 20:01:41 +01:00
|
|
|
auto child = LoadInnerNode(root->readChild(1).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), false, nodeStore->layout().maxChildrenPerInnerNode() + i);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
//Traverse all leaves in the third, fourth and fifth child of the root
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 2; i < 5; ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->readChild(i).blockId()), false, i * nodeStore->layout().maxChildrenPerInnerNode());
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
//Traverse some of the leaves in the sixth child of the root
|
2017-12-03 20:01:41 +01:00
|
|
|
child = LoadInnerNode(root->readChild(5).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 0; i < 2; ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), false, 5 * nodeStore->layout().maxChildrenPerInnerNode() + i);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), nodeStore->layout().maxChildrenPerInnerNode() + 5, 5 * nodeStore->layout().maxChildrenPerInnerNode() + 2, true);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseLastPartOfThreelevelTree) {
|
2015-02-25 16:52:17 +01:00
|
|
|
auto root = CreateThreeLevel();
|
|
|
|
//Traverse some of the leaves in the second child of the root
|
2017-12-03 20:01:41 +01:00
|
|
|
auto child = LoadInnerNode(root->readChild(1).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), false, nodeStore->layout().maxChildrenPerInnerNode() + i);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
//Traverse all leaves in the third, fourth and fifth child of the root
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 2; i < 5; ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->readChild(i).blockId()), false, i * nodeStore->layout().maxChildrenPerInnerNode());
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
//Traverse all of the leaves in the sixth child of the root
|
2017-12-03 20:01:41 +01:00
|
|
|
child = LoadInnerNode(root->readChild(5).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 0; i < child->numChildren(); ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), i == child->numChildren()-1, 5 * nodeStore->layout().maxChildrenPerInnerNode() + i);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), nodeStore->layout().maxChildrenPerInnerNode() + 5, 5 * nodeStore->layout().maxChildrenPerInnerNode() + child->numChildren(), true);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseAllLeavesOfThreelevelTree) {
|
2015-02-25 16:52:17 +01:00
|
|
|
auto root = CreateThreeLevel();
|
|
|
|
//Traverse all leaves in the third, fourth and fifth child of the root
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 0; i < 5; ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->readChild(i).blockId()), false, i * nodeStore->layout().maxChildrenPerInnerNode());
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
//Traverse all of the leaves in the sixth child of the root
|
2017-12-03 20:01:41 +01:00
|
|
|
auto child = LoadInnerNode(root->readChild(5).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 0; i < child->numChildren(); ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), i==child->numChildren()-1, 5 * nodeStore->layout().maxChildrenPerInnerNode() + i);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 0, 5 * nodeStore->layout().maxChildrenPerInnerNode() + child->numChildren(), true);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseAllLeavesOfFourLevelTree) {
|
2015-02-25 16:52:17 +01:00
|
|
|
auto root = CreateFourLevel();
|
|
|
|
//Traverse all leaves of the full threelevel tree in the first child
|
2017-12-03 20:01:41 +01:00
|
|
|
auto firstChild = LoadInnerNode(root->readChild(0).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 0; i < firstChild->numChildren(); ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(firstChild->readChild(i).blockId()), false, i * nodeStore->layout().maxChildrenPerInnerNode());
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
//Traverse all leaves of the full threelevel tree in the second child
|
2017-12-03 20:01:41 +01:00
|
|
|
auto secondChild = LoadInnerNode(root->readChild(1).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 0; i < secondChild->numChildren(); ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(secondChild->readChild(i).blockId()), false, (nodeStore->layout().maxChildrenPerInnerNode() + i) * nodeStore->layout().maxChildrenPerInnerNode());
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
|
|
|
//Traverse all leaves of the non-full threelevel tree in the third child
|
2017-12-03 20:01:41 +01:00
|
|
|
auto thirdChild = LoadInnerNode(root->readChild(2).blockId());
|
|
|
|
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(thirdChild->readChild(0).blockId()), false, 2 * nodeStore->layout().maxChildrenPerInnerNode() * nodeStore->layout().maxChildrenPerInnerNode());
|
|
|
|
EXPECT_TRAVERSE_LEAF(LoadInnerNode(thirdChild->readChild(1).blockId())->readChild(0).blockId(), true, 2 * nodeStore->layout().maxChildrenPerInnerNode() * nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode());
|
2015-02-25 16:52:17 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 0, 2*nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode() + 1, true);
|
2015-02-25 16:52:17 +01:00
|
|
|
}
|
2015-02-25 01:31:16 +01:00
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, TraverseMiddlePartOfFourLevelTree) {
|
2015-02-25 22:38:49 +01:00
|
|
|
auto root = CreateFourLevel();
|
|
|
|
//Traverse some leaves of the full threelevel tree in the first child
|
2017-12-03 20:01:41 +01:00
|
|
|
auto firstChild = LoadInnerNode(root->readChild(0).blockId());
|
|
|
|
auto secondChildOfFirstChild = LoadInnerNode(firstChild->readChild(1).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 5; i < secondChildOfFirstChild->numChildren(); ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(secondChildOfFirstChild->readChild(i).blockId(), false, nodeStore->layout().maxChildrenPerInnerNode()+i);
|
2015-02-25 22:38:49 +01:00
|
|
|
}
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 2; i < firstChild->numChildren(); ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(firstChild->readChild(i).blockId()), false, i * nodeStore->layout().maxChildrenPerInnerNode());
|
2015-02-25 22:38:49 +01:00
|
|
|
}
|
|
|
|
//Traverse all leaves of the full threelevel tree in the second child
|
2017-12-03 20:01:41 +01:00
|
|
|
auto secondChild = LoadInnerNode(root->readChild(1).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 0; i < secondChild->numChildren(); ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(secondChild->readChild(i).blockId()), false, (nodeStore->layout().maxChildrenPerInnerNode() + i) * nodeStore->layout().maxChildrenPerInnerNode());
|
2015-02-25 22:38:49 +01:00
|
|
|
}
|
|
|
|
//Traverse some leaves of the non-full threelevel tree in the third child
|
2017-12-03 20:01:41 +01:00
|
|
|
auto thirdChild = LoadInnerNode(root->readChild(2).blockId());
|
|
|
|
auto firstChildOfThirdChild = LoadInnerNode(thirdChild->readChild(0).blockId());
|
2015-05-08 02:10:40 +02:00
|
|
|
for(unsigned int i = 0; i < firstChildOfThirdChild->numChildren()-1; ++i) {
|
2017-12-03 20:01:41 +01:00
|
|
|
EXPECT_TRAVERSE_LEAF(firstChildOfThirdChild->readChild(i).blockId(), false, 2 * nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode()+i);
|
2015-02-25 22:38:49 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), nodeStore->layout().maxChildrenPerInnerNode()+5, 2*nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode() -1, true);
|
2015-02-25 22:38:49 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, LastLeafIsAlreadyResizedInCallback) {
|
|
|
|
unique_ref<DataNode> root = CreateLeaf();
|
2016-07-13 00:22:35 +02:00
|
|
|
root->flush();
|
2019-01-13 08:21:12 +01:00
|
|
|
auto* old_root = root.get();
|
2017-09-17 03:07:27 +02:00
|
|
|
auto tree = treeStore.load(root->blockId()).value();
|
2019-01-13 08:21:12 +01:00
|
|
|
LeafTraverser(nodeStore, false).traverseAndUpdateRoot(&root, 0, 2, [this] (uint32_t leafIndex, bool /*isRightBorderNode*/, LeafHandle leaf) {
|
2016-07-13 00:22:35 +02:00
|
|
|
if (leafIndex == 0) {
|
2016-07-15 20:12:24 +02:00
|
|
|
EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf(), leaf.node()->numBytes());
|
2016-07-13 00:22:35 +02:00
|
|
|
} else {
|
|
|
|
EXPECT_TRUE(false) << "only two nodes";
|
|
|
|
}
|
2017-09-16 18:45:15 +02:00
|
|
|
}, [] (uint32_t /*nodeIndex*/) -> Data {
|
2016-07-13 00:22:35 +02:00
|
|
|
return Data(1);
|
2019-01-13 08:21:12 +01:00
|
|
|
}, [] (auto) {});
|
|
|
|
EXPECT_NE(old_root, root.get()); // expect that we grew the tree
|
2016-07-13 00:22:35 +02:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, LastLeafIsAlreadyResizedInCallback_TwoLevel) {
|
|
|
|
unique_ref<DataNode> root = CreateFullTwoLevelWithLastLeafSize(5);
|
2016-07-13 00:22:35 +02:00
|
|
|
root->flush();
|
2019-01-13 08:21:12 +01:00
|
|
|
auto* old_root = root.get();
|
2017-09-17 03:07:27 +02:00
|
|
|
auto tree = treeStore.load(root->blockId()).value();
|
2019-01-13 08:21:12 +01:00
|
|
|
LeafTraverser(nodeStore, false).traverseAndUpdateRoot(&root, 0, nodeStore->layout().maxChildrenPerInnerNode()+1, [this] (uint32_t /*leafIndex*/, bool /*isRightBorderNode*/, LeafHandle leaf) {
|
2016-07-15 20:12:24 +02:00
|
|
|
EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf(), leaf.node()->numBytes());
|
2017-09-16 18:45:15 +02:00
|
|
|
}, [] (uint32_t /*nodeIndex*/) -> Data {
|
2016-07-13 00:22:35 +02:00
|
|
|
return Data(1);
|
2019-01-13 08:21:12 +01:00
|
|
|
}, [] (auto) {});
|
|
|
|
EXPECT_NE(old_root, root.get()); // expect that we grew the tree
|
2016-07-13 00:22:35 +02:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
TEST_F(LeafTraverserTest, ResizeFromOneLeafToMultipleLeaves) {
|
2016-09-07 22:25:18 +02:00
|
|
|
auto root = CreateLeaf();
|
2017-09-17 03:07:27 +02:00
|
|
|
EXPECT_TRAVERSE_LEAF(root->blockId(), false, 0);
|
2016-09-07 22:25:18 +02:00
|
|
|
//EXPECT_CALL(traversor, calledExistingLeaf(_, false, 0)).Times(1);
|
|
|
|
for (uint32_t i = 1; i < 10; ++i) {
|
|
|
|
EXPECT_CREATE_LEAF(i);
|
|
|
|
}
|
2019-01-13 08:21:12 +01:00
|
|
|
TraverseLeaves(std::move(root), 0, 10, false);
|
2016-09-07 22:25:18 +02:00
|
|
|
}
|
|
|
|
|
2019-01-13 08:21:12 +01:00
|
|
|
////TODO Refactor the test cases that are too long
|