Add test cases for traverse performance
This commit is contained in:
parent
4e689f2411
commit
622416bc4d
@ -14,31 +14,183 @@ 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*/, DataLeafNode* /*leaf*/) {}, [this] (uint32_t /*index*/) -> Data {return Data(maxChildrenPerInnerNode).FillWithZeroes();});
|
||||
}
|
||||
|
||||
uint64_t maxChildrenPerInnerNode = nodeStore->layout().maxChildrenPerInnerNode();
|
||||
};
|
||||
|
||||
TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Twolevel_DeleteByTree) {
|
||||
auto key = this->CreateFullTwoLevel()->key();
|
||||
auto tree = this->treeStore.load(key).value();
|
||||
this->treeStore.remove(std::move(tree));
|
||||
EXPECT_EQ(2u, blockStore->loadedBlocks.size());
|
||||
auto key = CreateFullTwoLevel()->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
treeStore.remove(std::move(tree));
|
||||
|
||||
EXPECT_EQ(1u, blockStore->loadedBlocks.size()); // First loading is from loading the tree, second one from removing it (i.e. loading the root)
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Twolevel_DeleteByKey) {
|
||||
auto key = this->CreateFullTwoLevel()->key();
|
||||
this->treeStore.remove(key);
|
||||
auto key = CreateFullTwoLevel()->key();
|
||||
blockStore->resetCounters();
|
||||
|
||||
treeStore.remove(key);
|
||||
|
||||
EXPECT_EQ(1u, blockStore->loadedBlocks.size());
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByTree) {
|
||||
auto key = this->CreateFullThreeLevel()->key();
|
||||
auto tree = this->treeStore.load(key).value();
|
||||
this->treeStore.remove(std::move(tree));
|
||||
EXPECT_EQ(2u + nodeStore->layout().maxChildrenPerInnerNode(), blockStore->loadedBlocks.size());
|
||||
auto key = CreateFullThreeLevel()->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
treeStore.remove(std::move(tree));
|
||||
|
||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks.size());
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByKey) {
|
||||
auto key = this->CreateFullThreeLevel()->key();
|
||||
this->treeStore.remove(key);
|
||||
EXPECT_EQ(1u + nodeStore->layout().maxChildrenPerInnerNode(), blockStore->loadedBlocks.size());
|
||||
}
|
||||
auto key = CreateFullThreeLevel()->key();
|
||||
blockStore->resetCounters();
|
||||
|
||||
treeStore.remove(key);
|
||||
|
||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks.size());
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_All) {
|
||||
auto key = CreateFullTwoLevel()->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
Traverse(tree.get(), 0, maxChildrenPerInnerNode);
|
||||
|
||||
EXPECT_EQ(maxChildrenPerInnerNode, blockStore->loadedBlocks.size()); // Loads all leaves (not the root, because it is already loaded in the tree)
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_Some) {
|
||||
auto key = CreateFullTwoLevel()->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
Traverse(tree.get(), 3, 5);
|
||||
|
||||
EXPECT_EQ(2u, blockStore->loadedBlocks.size()); // Loads both leaves (not the root, because it is already loaded in the tree)
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_All) {
|
||||
auto key = CreateFullThreeLevel()->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
Traverse(tree.get(), 0, maxChildrenPerInnerNode * maxChildrenPerInnerNode);
|
||||
|
||||
EXPECT_EQ(maxChildrenPerInnerNode + maxChildrenPerInnerNode * maxChildrenPerInnerNode, blockStore->loadedBlocks.size()); // Loads inner nodes and all leaves once (not the root, because it is already loaded in the tree)
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InOneInner) {
|
||||
auto key = CreateFullThreeLevel()->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
Traverse(tree.get(), 3, 5);
|
||||
|
||||
EXPECT_EQ(3u, blockStore->loadedBlocks.size()); // Loads inner node and both leaves (not the root, because it is already loaded in the tree)
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InTwoInner) {
|
||||
auto key = CreateFullThreeLevel()->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
Traverse(tree.get(), 3, 3 + maxChildrenPerInnerNode);
|
||||
|
||||
EXPECT_EQ(2u + maxChildrenPerInnerNode, blockStore->loadedBlocks.size()); // Loads inner node and both leaves (not the root, because it is already loaded in the tree)
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_WholeInner) {
|
||||
auto key = CreateFullThreeLevel()->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
Traverse(tree.get(), maxChildrenPerInnerNode, 2*maxChildrenPerInnerNode);
|
||||
|
||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks.size()); // Loads inner node and leaves (not the root, because it is already loaded in the tree)f
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingInside) {
|
||||
auto key = CreateInner({CreateLeaf(), CreateLeaf()})->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
Traverse(tree.get(), 1, 4);
|
||||
|
||||
EXPECT_EQ(1u, blockStore->loadedBlocks.size()); // Loads last old child (for growing it)
|
||||
EXPECT_EQ(2u, blockStore->createdBlocks);
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_TwoLevel) {
|
||||
auto key = CreateInner({CreateLeaf(), CreateLeaf()})->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
Traverse(tree.get(), 4, 5);
|
||||
|
||||
EXPECT_EQ(1u, blockStore->loadedBlocks.size()); // Loads last old leaf for growing it
|
||||
EXPECT_EQ(3u, blockStore->createdBlocks);
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_ThreeLevel) {
|
||||
auto key = CreateInner({CreateFullTwoLevel(), CreateFullTwoLevel()})->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
Traverse(tree.get(), 2*maxChildrenPerInnerNode+1, 2*maxChildrenPerInnerNode+2);
|
||||
|
||||
EXPECT_EQ(2u, blockStore->loadedBlocks.size()); // Loads last old leaf (and its inner node) for growing it
|
||||
EXPECT_EQ(3u, blockStore->createdBlocks); // inner node and two leaves
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingAtBeginOfChild) {
|
||||
auto key = CreateInner({CreateFullTwoLevel(), CreateFullTwoLevel()})->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
Traverse(tree.get(), maxChildrenPerInnerNode, 3*maxChildrenPerInnerNode);
|
||||
|
||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks.size()); // Inner node and its leaves
|
||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->createdBlocks); // Creates an inner node and its leaves
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInOldDepth) {
|
||||
auto key = CreateInner({CreateLeaf(), CreateLeaf()})->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
Traverse(tree.get(), 4, maxChildrenPerInnerNode+2);
|
||||
|
||||
EXPECT_EQ(1u, blockStore->loadedBlocks.size()); // Loads last old leaf for growing it
|
||||
EXPECT_EQ(2 + maxChildrenPerInnerNode, blockStore->createdBlocks); // 2x new inner node + leaves
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInNewDepth) {
|
||||
auto key = CreateInner({CreateLeaf(), CreateLeaf()})->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
Traverse(tree.get(), maxChildrenPerInnerNode, maxChildrenPerInnerNode+2);
|
||||
|
||||
EXPECT_EQ(1u, blockStore->loadedBlocks.size()); // Loads last old leaf for growing it
|
||||
EXPECT_EQ(2 + maxChildrenPerInnerNode, blockStore->createdBlocks); // 2x new inner node + leaves
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
class MockBlockStore final : public blockstore::BlockStore {
|
||||
public:
|
||||
MockBlockStore(cpputils::unique_ref<BlockStore> baseBlockStore = cpputils::make_unique_ref<blockstore::testfake::FakeBlockStore>())
|
||||
: _baseBlockStore(std::move(baseBlockStore)) {
|
||||
: loadedBlocks(), createdBlocks(0), _mutex(), _baseBlockStore(std::move(baseBlockStore)) {
|
||||
}
|
||||
|
||||
blockstore::Key createKey() override {
|
||||
@ -17,6 +17,10 @@ public:
|
||||
}
|
||||
|
||||
boost::optional<cpputils::unique_ref<blockstore::Block>> tryCreate(const blockstore::Key &key, cpputils::Data data) override {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
createdBlocks += 1;
|
||||
}
|
||||
return _baseBlockStore->tryCreate(key, std::move(data));
|
||||
}
|
||||
|
||||
@ -52,7 +56,13 @@ public:
|
||||
return _baseBlockStore->remove(std::move(block));
|
||||
}
|
||||
|
||||
void resetCounters() {
|
||||
loadedBlocks = {};
|
||||
createdBlocks = 0;
|
||||
}
|
||||
|
||||
std::vector<blockstore::Key> loadedBlocks;
|
||||
uint64_t createdBlocks;
|
||||
|
||||
private:
|
||||
std::mutex _mutex;
|
||||
|
Loading…
Reference in New Issue
Block a user