Implement tree shrinking and some test cases for it

This commit is contained in:
Sebastian Messmer 2015-02-22 19:30:42 +01:00
parent 46a0bf617b
commit ab2e789dac
19 changed files with 510 additions and 70 deletions

View File

@ -78,6 +78,11 @@ void DataInnerNode::addChild(const DataNode &child) {
LastChild()->setKey(child.key());
}
void DataInnerNode::removeLastChild() {
assert(*node().Size() > 1);
*node().Size() -= 1;
}
}
}
}

View File

@ -40,6 +40,8 @@ public:
void addChild(const DataNode &child_key);
void removeLastChild();
ChildEntry *LastChild();
const ChildEntry *LastChild() const;

View File

@ -55,6 +55,22 @@ unique_ptr<DataNode> DataNodeStore::createNewNodeAsCopyFrom(const DataNode &sour
return load(std::move(newBlock));
}
unique_ptr<DataNode> DataNodeStore::overwriteNodeWith(unique_ptr<DataNode> target, const DataNode &source) {
Key key = target->key();
{
auto targetBlock = target->node().releaseBlock();
target.reset();
blockstore::utils::copyTo(targetBlock.get(), source.node().block());
}
return load(key);
}
void DataNodeStore::remove(unique_ptr<DataNode> node) {
auto block = node->node().releaseBlock();
node.reset();
_blockstore->remove(std::move(block));
}
}
}
}

View File

@ -32,6 +32,10 @@ public:
std::unique_ptr<DataNode> createNewNodeAsCopyFrom(const DataNode &source);
std::unique_ptr<DataNode> overwriteNodeWith(std::unique_ptr<DataNode> target, const DataNode &source);
void remove(std::unique_ptr<DataNode> node);
private:
std::unique_ptr<DataNode> load(std::unique_ptr<blockstore::Block> block);

View File

@ -33,11 +33,46 @@ DataTree::~DataTree() {
}
void DataTree::removeLastDataLeaf() {
auto deletePosOrNull = algorithms::GetLowestRightBorderNodeWithMoreThanOneChildOrNull(_nodeStore, _rootNode.get());
assert(deletePosOrNull.get() != nullptr); //TODO Correct exception (tree has only one leaf, can't shrink it)
deleteLastChildSubtree(deletePosOrNull.get());
ifRootHasOnlyOneChildReplaceRootWithItsChild();
}
void DataTree::ifRootHasOnlyOneChildReplaceRootWithItsChild() {
DataInnerNode *rootNode = dynamic_cast<DataInnerNode*>(_rootNode.get());
assert(rootNode != nullptr);
if (rootNode->numChildren() == 1) {
auto child = _nodeStore->load(rootNode->getChild(0)->key());
_rootNode = _nodeStore->overwriteNodeWith(std::move(_rootNode), *child);
_nodeStore->remove(std::move(child));
}
}
auto deletePosOrNull = algorithms::GetLowestRightBorderNodeWithMoreThanOneChildOrNull(_nodeStore, _rootNode.get());
//TODO ...
void DataTree::deleteLastChildSubtree(DataInnerNode *node) {
deleteSubtree(node->LastChild()->key());
node->removeLastChild();
}
void DataTree::deleteSubtree(const Key &key) {
auto node = _nodeStore->load(key);
deleteChildrenOf(*node);
_nodeStore->remove(std::move(node));
}
void DataTree::deleteChildrenOf(const DataNode &node) {
const DataInnerNode *node_inner = dynamic_cast<const DataInnerNode*>(&node);
if (node_inner != nullptr) {
deleteChildrenOf(*node_inner);
}
}
void DataTree::deleteChildrenOf(const DataInnerNode &node) {
for(int i = 0; i < node.numChildren(); ++i) {
deleteSubtree(node.getChild(i)->key());
}
}
unique_ptr<DataLeafNode> DataTree::addDataLeaf() {

View File

@ -38,6 +38,12 @@ private:
cpputils::optional_ownership_ptr<datanodestore::DataNode> createChainOfInnerNodes(unsigned int num, datanodestore::DataLeafNode *leaf);
std::unique_ptr<datanodestore::DataLeafNode> addDataLeafToFullTree();
void deleteLastChildSubtree(datanodestore::DataInnerNode *node);
void deleteSubtree(const blockstore::Key &key);
void deleteChildrenOf(const datanodestore::DataNode &node);
void deleteChildrenOf(const datanodestore::DataInnerNode &node);
void ifRootHasOnlyOneChildReplaceRootWithItsChild();
DISALLOW_COPY_AND_ASSIGN(DataTree);
};

View File

@ -46,7 +46,6 @@ optional_ownership_ptr<DataInnerNode> GetLowestRightBorderNodeWithMoreThanOneChi
return node.numChildren() > 1;
});
}
//TODO Test this
optional_ownership_ptr<datanodestore::DataInnerNode> GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNull(datanodestore::DataNodeStore *nodeStore, datanodestore::DataNode *rootNode) {
return GetLowestInnerRightBorderNodeWithConditionOrNull(nodeStore, rootNode, [] (const datanodestore::DataInnerNode &node) {

View File

@ -1,6 +1,7 @@
#include "testutils/DataTreeGrowingTest.h"
#include "../../../../testutils/DataBlockFixture.h"
#include <messmer/cpp-utils/pointer.h>
using ::testing::WithParamInterface;
using ::testing::Values;

View File

@ -1,6 +1,15 @@
#include "testutils/DataTreeGrowingTest.h"
class DataTreeGrowingTest_KeyDoesntChange: public DataTreeGrowingTest {};
using blobstore::onblocks::datatreestore::DataTree;
class DataTreeGrowingTest_KeyDoesntChange: public DataTreeGrowingTest {
public:
void EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(const blockstore::Key &key) {
DataTree tree(&nodeStore, nodeStore.load(key));
tree.addDataLeaf();
EXPECT_EQ(key, tree.key());
}
};
TEST_F(DataTreeGrowingTest_KeyDoesntChange, GrowAOneNodeTree) {
auto key = CreateLeafOnlyTree()->key();

View File

@ -1,4 +1,5 @@
#include "DataTreeGrowingTest.h"
#include <messmer/cpp-utils/pointer.h>
using namespace blobstore::onblocks::datanodestore;
@ -64,56 +65,6 @@ void DataTreeGrowingTest::AddLeafTo(const Key &key) {
tree.addDataLeaf();
}
unique_ptr<DataInnerNode> DataTreeGrowingTest::LoadInnerNode(const Key &key) {
auto node = nodeStore.load(key);
auto casted = dynamic_pointer_move<DataInnerNode>(node);
EXPECT_NE(nullptr, casted.get()) << "Is not an inner node";
return casted;
}
unique_ptr<DataLeafNode> DataTreeGrowingTest::DataTreeGrowingTest::LoadLeafNode(const Key &key) {
auto node = nodeStore.load(key);
auto casted = dynamic_pointer_move<DataLeafNode>(node);
EXPECT_NE(nullptr, casted.get()) << "Is not a leaf node";
return casted;
}
void DataTreeGrowingTest::EXPECT_IS_LEAF_NODE(const Key &key) {
auto node = LoadLeafNode(key);
EXPECT_NE(nullptr, node.get());
}
void DataTreeGrowingTest::EXPECT_IS_INNER_NODE(const Key &key) {
auto node = LoadInnerNode(key);
EXPECT_NE(nullptr, node.get());
}
void DataTreeGrowingTest::EXPECT_IS_FULL_TWOLEVEL_TREE(const Key &key) {
auto node = LoadInnerNode(key);
EXPECT_EQ(DataInnerNode::MAX_STORED_CHILDREN, node->numChildren());
for (unsigned int i = 0; i < node->numChildren(); ++i) {
EXPECT_IS_LEAF_NODE(node->getChild(i)->key());
}
}
void DataTreeGrowingTest::EXPECT_IS_FULL_THREELEVEL_TREE(const Key &key) {
auto root = LoadInnerNode(key);
EXPECT_EQ(DataInnerNode::MAX_STORED_CHILDREN, root->numChildren());
for (unsigned int i = 0; i < root->numChildren(); ++i) {
auto node = LoadInnerNode(root->getChild(i)->key());
EXPECT_EQ(DataInnerNode::MAX_STORED_CHILDREN, node->numChildren());
for (unsigned int j = 0; j < node->numChildren(); ++j) {
EXPECT_IS_LEAF_NODE(node->getChild(j)->key());
}
}
}
void DataTreeGrowingTest::EXPECT_IS_TWONODE_CHAIN(const Key &key) {
auto node = LoadInnerNode(key);
EXPECT_EQ(1u, node->numChildren());
EXPECT_IS_LEAF_NODE(node->getChild(0)->key());
}
void DataTreeGrowingTest::EXPECT_IS_THREENODE_CHAIN(const Key &key) {
auto node1 = LoadInnerNode(key);
EXPECT_EQ(1u, node1->numChildren());
@ -122,12 +73,6 @@ void DataTreeGrowingTest::EXPECT_IS_THREENODE_CHAIN(const Key &key) {
EXPECT_IS_LEAF_NODE(node2->getChild(0)->key());
}
void DataTreeGrowingTest::EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(const Key &key) {
DataTree tree(&nodeStore, nodeStore.load(key));
tree.addDataLeaf();
EXPECT_EQ(key, tree.key());
}
void DataTreeGrowingTest::EXPECT_INNER_NODE_NUMBER_OF_LEAVES_IS(unsigned int expectedNumberOfLeaves, const Key &key) {
auto node = LoadInnerNode(key);
EXPECT_EQ(expectedNumberOfLeaves, node->numChildren());

View File

@ -7,8 +7,6 @@
#include "../../../../../../implementations/onblocks/datanodestore/DataLeafNode.h"
#include "../../../../../../implementations/onblocks/datanodestore/DataInnerNode.h"
#include "messmer/cpp-utils/pointer.h"
class DataTreeGrowingTest: public DataTreeTest {
public:
@ -19,16 +17,8 @@ public:
blockstore::Key CreateThreeLevelTreeWithLowerLevelFullReturnRootKey();
blockstore::Key CreateThreeLevelTreeWithTwoFullSubtrees();
void AddLeafTo(const blockstore::Key &key);
std::unique_ptr<blobstore::onblocks::datanodestore::DataInnerNode> LoadInnerNode(const blockstore::Key &key);
std::unique_ptr<blobstore::onblocks::datanodestore::DataLeafNode> LoadLeafNode(const blockstore::Key &key);
void EXPECT_IS_LEAF_NODE(const blockstore::Key &key);
void EXPECT_IS_INNER_NODE(const blockstore::Key &key);
void EXPECT_IS_FULL_TWOLEVEL_TREE(const blockstore::Key &key);
void EXPECT_IS_FULL_THREELEVEL_TREE(const blockstore::Key &key);
void EXPECT_IS_TWONODE_CHAIN(const blockstore::Key &key);
void EXPECT_IS_THREENODE_CHAIN(const blockstore::Key &key);
void EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(const blockstore::Key &key);
void EXPECT_INNER_NODE_NUMBER_OF_LEAVES_IS(unsigned int expectedNumberOfLeaves, const blockstore::Key &key);
};

View File

@ -3,6 +3,7 @@
#define BLOCKS_MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_GROWING_TESTUTILS_TWOLEVELDATAFIXTURE_H_
#include <messmer/cpp-utils/macros.h>
#include <messmer/cpp-utils/pointer.h>
// A data fixture containing data for a two-level tree (one inner node with leaf children).
// The class can fill this data into the leaf children of a given inner node

View File

@ -0,0 +1,24 @@
#include "testutils/DataTreeShrinkingTest.h"
using ::testing::WithParamInterface;
using ::testing::Values;
using std::unique_ptr;
using std::make_unique;
using cpputils::dynamic_pointer_move;
using namespace blobstore::onblocks::datatreestore;
using blobstore::onblocks::datanodestore::DataNode;
using blobstore::onblocks::datanodestore::DataNodeStore;
using blobstore::onblocks::datanodestore::DataInnerNode;
using blobstore::onblocks::datanodestore::DataLeafNode;
using blockstore::Key;
TEST_F(DataTreeShrinkingTest, ShrinkingALeafOnlyTreeCrashes) {
Key key = CreateLeafOnlyTree()->key();
auto tree = make_unique<DataTree>(&nodeStore, nodeStore.load(key));
EXPECT_DEATH(tree->removeLastDataLeaf(), "");
}
//TODO Test that blocks are actually deleted

View File

@ -0,0 +1,63 @@
#include "testutils/DataTreeShrinkingTest.h"
using blobstore::onblocks::datatreestore::DataTree;
using blockstore::Key;
class DataTreeShrinkingTest_KeyDoesntChange: public DataTreeShrinkingTest {
public:
void EXPECT_KEY_DOESNT_CHANGE_WHEN_SHRINKING(const Key &key) {
DataTree tree(&nodeStore, nodeStore.load(key));
tree.removeLastDataLeaf();
EXPECT_EQ(key, tree.key());
}
};
TEST_F(DataTreeShrinkingTest_KeyDoesntChange, ShrinkATwoLeafTree) {
auto key = CreateTwoLeafTree();
EXPECT_KEY_DOESNT_CHANGE_WHEN_SHRINKING(key);
}
TEST_F(DataTreeShrinkingTest_KeyDoesntChange, ShrinkAFourNodeThreeLeafTree) {
auto key = CreateFourNodeThreeLeafTree();
EXPECT_KEY_DOESNT_CHANGE_WHEN_SHRINKING(key);
}
TEST_F(DataTreeShrinkingTest_KeyDoesntChange, ShrinkATwoInnerNodeOneTwoLeavesTree) {
auto key = CreateTwoInnerNodeOneTwoLeavesTree();
EXPECT_KEY_DOESNT_CHANGE_WHEN_SHRINKING(key);
}
TEST_F(DataTreeShrinkingTest_KeyDoesntChange, ShrinkATwoInnerNodeTwoOneLeavesTree) {
auto key = CreateTwoInnerNodeTwoOneLeavesTree();
EXPECT_KEY_DOESNT_CHANGE_WHEN_SHRINKING(key);
}
TEST_F(DataTreeShrinkingTest_KeyDoesntChange, ShrinkAThreeLevelMinDataTree) {
auto key = CreateThreeLevelMinDataTree();
EXPECT_KEY_DOESNT_CHANGE_WHEN_SHRINKING(key);
}
TEST_F(DataTreeShrinkingTest_KeyDoesntChange, ShrinkAFourLevelMinDataTree) {
auto key = CreateFourLevelMinDataTree();
EXPECT_KEY_DOESNT_CHANGE_WHEN_SHRINKING(key);
}
TEST_F(DataTreeShrinkingTest_KeyDoesntChange, ShrinkAFourLevelTreeWithTwoSiblingLeaves1) {
auto key = CreateFourLevelTreeWithTwoSiblingLeaves1();
EXPECT_KEY_DOESNT_CHANGE_WHEN_SHRINKING(key);
}
TEST_F(DataTreeShrinkingTest_KeyDoesntChange, ShrinkAFourLevelTreeWithTwoSiblingLeaves2) {
auto key = CreateFourLevelTreeWithTwoSiblingLeaves2();
EXPECT_KEY_DOESNT_CHANGE_WHEN_SHRINKING(key);
}
TEST_F(DataTreeShrinkingTest_KeyDoesntChange, ShrinkATreeWithFirstChildOfRootFullThreelevelAndSecondChildMindataThreelevel) {
auto key = CreateTreeWithFirstChildOfRootFullThreelevelAndSecondChildMindataThreelevel();
EXPECT_KEY_DOESNT_CHANGE_WHEN_SHRINKING(key);
}
TEST_F(DataTreeShrinkingTest_KeyDoesntChange, ShrinkAThreeLevelTreeWithThreeChildrenOfRoot) {
auto key = CreateThreeLevelTreeWithThreeChildrenOfRoot();
EXPECT_KEY_DOESNT_CHANGE_WHEN_SHRINKING(key);
}

View File

@ -0,0 +1,129 @@
#include "testutils/DataTreeShrinkingTest.h"
using blobstore::onblocks::datatreestore::DataTree;
using blockstore::Key;
class DataTreeShrinkingTest_Structure: public DataTreeShrinkingTest {
public:
void EXPECT_IS_LEAF_ONLY_TREE(const Key &key) {
EXPECT_IS_LEAF_NODE(key);
}
void EXPECT_IS_TWO_LEAF_TREE(const Key &key) {
auto root = LoadInnerNode(key);
EXPECT_EQ(2, root->numChildren());
EXPECT_IS_LEAF_NODE(root->getChild(0)->key());
EXPECT_IS_LEAF_NODE(root->getChild(1)->key());
}
void EXPECT_IS_TWO_INNER_NODE_TREE_WITH_ONE_LEAF_EACH(const Key &key) {
auto root = LoadInnerNode(key);
EXPECT_EQ(2, root->numChildren());
EXPECT_IS_TWONODE_CHAIN(root->getChild(0)->key());
EXPECT_IS_TWONODE_CHAIN(root->getChild(1)->key());
}
void EXPECT_IS_THREE_NODE_CHAIN(const Key &key) {
auto root = LoadInnerNode(key);
EXPECT_EQ(1, root->numChildren());
EXPECT_IS_TWONODE_CHAIN(root->getChild(0)->key());
}
void EXPECT_IS_THREELEVEL_MINDATA_TREE(const Key &key) {
auto root = LoadInnerNode(key);
EXPECT_EQ(2, root->numChildren());
EXPECT_IS_FULL_TWOLEVEL_TREE(root->getChild(0)->key());
EXPECT_IS_TWONODE_CHAIN(root->getChild(1)->key());
}
void EXPECT_IS_FOURLEVEL_MINDATA_TREE(const Key &key) {
auto root = LoadInnerNode(key);
EXPECT_EQ(2, root->numChildren());
EXPECT_IS_FULL_THREELEVEL_TREE(root->getChild(0)->key());
EXPECT_IS_THREE_NODE_CHAIN(root->getChild(1)->key());
}
void EXPECT_IS_TREE_WITH_FIRST_CHILD_OF_ROOT_FULL_THREELEVEL_AND_SECOND_CHILD_MINDATA_THREELEVEL_TREE(const Key &key) {
auto root = LoadInnerNode(key);
EXPECT_EQ(2, root->numChildren());
EXPECT_IS_FULL_THREELEVEL_TREE(root->getChild(0)->key());
EXPECT_IS_THREELEVEL_MINDATA_TREE(root->getChild(1)->key());
}
void EXPECT_IS_TREE_WITH_FIRST_CHILD_OF_ROOT_FULL_THREELEVEL_AND_SECOND_CHILD_FULL_TWOLEVEL_TREE(const Key &key) {
auto root = LoadInnerNode(key);
EXPECT_EQ(2, root->numChildren());
EXPECT_IS_FULL_THREELEVEL_TREE(root->getChild(0)->key());
auto secondChild = LoadInnerNode(root->getChild(1)->key());
EXPECT_EQ(1, secondChild->numChildren());
EXPECT_IS_FULL_TWOLEVEL_TREE(secondChild->getChild(0)->key());
}
void EXPECT_IS_THREELEVEL_TREE_WITH_TWO_FULL_TWOLEVEL_TREES(const Key &key) {
auto root = LoadInnerNode(key);
EXPECT_EQ(2, root->numChildren());
EXPECT_IS_FULL_TWOLEVEL_TREE(root->getChild(0)->key());
EXPECT_IS_FULL_TWOLEVEL_TREE(root->getChild(1)->key());
}
};
TEST_F(DataTreeShrinkingTest_Structure, ShrinkATwoLeafTree) {
auto key = CreateTwoLeafTree();
Shrink(key);
EXPECT_IS_LEAF_ONLY_TREE(key);
}
TEST_F(DataTreeShrinkingTest_Structure, ShrinkAFourNodeThreeLeafTree) {
auto key = CreateFourNodeThreeLeafTree();
Shrink(key);
EXPECT_IS_TWO_LEAF_TREE(key);
}
TEST_F(DataTreeShrinkingTest_Structure, ShrinkATwoInnerNodeOneTwoLeavesTree) {
auto key = CreateTwoInnerNodeOneTwoLeavesTree();
Shrink(key);
EXPECT_IS_TWO_INNER_NODE_TREE_WITH_ONE_LEAF_EACH(key);
}
/*TEST_F(DataTreeShrinkingTest_Structure, ShrinkATwoInnerNodeTwoOneLeavesTree) {
auto key = CreateTwoInnerNodeTwoOneLeavesTree();
Shrink(key);
EXPECT_IS_TWO_LEAF_TREE(key);
}*/
TEST_F(DataTreeShrinkingTest_Structure, ShrinkAThreeLevelMinDataTree) {
auto key = CreateThreeLevelMinDataTree();
Shrink(key);
EXPECT_IS_FULL_TWOLEVEL_TREE(key);
}
TEST_F(DataTreeShrinkingTest_Structure, ShrinkAFourLevelMinDataTree) {
auto key = CreateFourLevelMinDataTree();
Shrink(key);
EXPECT_IS_FULL_THREELEVEL_TREE(key);
}
TEST_F(DataTreeShrinkingTest_Structure, ShrinkAFourLevelTreeWithTwoSiblingLeaves1) {
auto key = CreateFourLevelTreeWithTwoSiblingLeaves1();
Shrink(key);
EXPECT_IS_FOURLEVEL_MINDATA_TREE(key);
}
TEST_F(DataTreeShrinkingTest_Structure, ShrinkAFourLevelTreeWithTwoSiblingLeaves2) {
auto key = CreateFourLevelTreeWithTwoSiblingLeaves2();
Shrink(key);
EXPECT_IS_TREE_WITH_FIRST_CHILD_OF_ROOT_FULL_THREELEVEL_AND_SECOND_CHILD_MINDATA_THREELEVEL_TREE(key);
}
TEST_F(DataTreeShrinkingTest_Structure, ShrinkATreeWithFirstChildOfRootFullThreelevelAndSecondChildMindataThreelevel) {
auto key = CreateTreeWithFirstChildOfRootFullThreelevelAndSecondChildMindataThreelevel();
Shrink(key);
EXPECT_IS_TREE_WITH_FIRST_CHILD_OF_ROOT_FULL_THREELEVEL_AND_SECOND_CHILD_FULL_TWOLEVEL_TREE(key);
}
TEST_F(DataTreeShrinkingTest_Structure, ShrinkAThreeLevelTreeWithThreeChildrenOfRoot) {
auto key = CreateThreeLevelTreeWithThreeChildrenOfRoot();
Shrink(key);
EXPECT_IS_THREELEVEL_TREE_WITH_TWO_FULL_TWOLEVEL_TREES(key);
}

View File

@ -0,0 +1,120 @@
#include <messmer/blobstore/test/implementations/onblocks/datatreestore/shrinking/testutils/DataTreeShrinkingTest.h>
using namespace blobstore::onblocks::datanodestore;
using std::unique_ptr;
using std::make_unique;
using cpputils::dynamic_pointer_move;
using blockstore::Key;
using blobstore::onblocks::datatreestore::DataTree;
void DataTreeShrinkingTest::Shrink(const Key &key) {
DataTree tree(&nodeStore, nodeStore.load(key));
tree.removeLastDataLeaf();
}
Key DataTreeShrinkingTest::CreateTwoLeafTree() {
auto leaf1 = nodeStore.createNewLeafNode();
auto root = nodeStore.createNewInnerNode(*leaf1);
root->addChild(*nodeStore.createNewLeafNode());
return root->key();
}
Key DataTreeShrinkingTest::CreateFourNodeThreeLeafTree() {
auto leaf1 = nodeStore.createNewLeafNode();
auto root = nodeStore.createNewInnerNode(*leaf1);
root->addChild(*nodeStore.createNewLeafNode());
root->addChild(*nodeStore.createNewLeafNode());
return root->key();
}
Key DataTreeShrinkingTest::CreateTwoInnerNodeOneTwoLeavesTree() {
auto leaf1 = nodeStore.createNewLeafNode();
auto node1 = nodeStore.createNewInnerNode(*leaf1);
auto leaf2 = nodeStore.createNewLeafNode();
auto node2 = nodeStore.createNewInnerNode(*leaf2);
node2->addChild(*nodeStore.createNewLeafNode());
auto root = nodeStore.createNewInnerNode(*node1);
root->addChild(*node2);
return root->key();
}
Key DataTreeShrinkingTest::CreateTwoInnerNodeTwoOneLeavesTree() {
auto leaf1 = nodeStore.createNewLeafNode();
auto node1 = nodeStore.createNewInnerNode(*leaf1);
node1->addChild(*nodeStore.createNewLeafNode());
auto leaf2 = nodeStore.createNewLeafNode();
auto node2 = nodeStore.createNewInnerNode(*leaf2);
auto root = nodeStore.createNewInnerNode(*node1);
root->addChild(*node2);
return root->key();
}
Key DataTreeShrinkingTest::CreateThreeLevelMinDataTree() {
auto fullTwoLevelRoot = nodeStore.load(CreateFullTwoLevelTree());
auto root = nodeStore.createNewInnerNode(*fullTwoLevelRoot);
auto leaf = nodeStore.createNewLeafNode();
auto inner = nodeStore.createNewInnerNode(*leaf);
root->addChild(*inner);
return root->key();
}
Key DataTreeShrinkingTest::CreateFourLevelMinDataTree() {
auto fullThreeLevelRoot = nodeStore.load(CreateFullThreeLevelTree());
auto root = nodeStore.createNewInnerNode(*fullThreeLevelRoot);
auto leaf = nodeStore.createNewLeafNode();
auto inner = nodeStore.createNewInnerNode(*leaf);
auto nodechainRoot = nodeStore.createNewInnerNode(*inner);
root->addChild(*nodechainRoot);
return root->key();
}
Key DataTreeShrinkingTest::CreateFourLevelTreeWithTwoSiblingLeaves1() {
auto fullThreeLevelRoot = nodeStore.load(CreateFullThreeLevelTree());
auto root = nodeStore.createNewInnerNode(*fullThreeLevelRoot);
auto leaf = nodeStore.createNewLeafNode();
auto inner = nodeStore.createNewInnerNode(*leaf);
inner->addChild(*nodeStore.createNewLeafNode());
auto inner_top = nodeStore.createNewInnerNode(*inner);
root->addChild(*inner_top);
return root->key();
}
Key DataTreeShrinkingTest::CreateFourLevelTreeWithTwoSiblingLeaves2() {
auto fullThreeLevelRoot = nodeStore.load(CreateFullThreeLevelTree());
auto root = nodeStore.createNewInnerNode(*fullThreeLevelRoot);
auto leaf1 = nodeStore.createNewLeafNode();
auto inner1 = nodeStore.createNewInnerNode(*leaf1);
FillNode(inner1.get());
auto leaf2 = nodeStore.createNewLeafNode();
auto inner2 = nodeStore.createNewInnerNode(*leaf2);
inner2->addChild(*nodeStore.createNewLeafNode());
auto inner_top = nodeStore.createNewInnerNode(*inner1);
inner_top->addChild(*inner2);
root->addChild(*inner_top);
return root->key();
}
Key DataTreeShrinkingTest::CreateTreeWithFirstChildOfRootFullThreelevelAndSecondChildMindataThreelevel() {
auto fullThreeLevelRoot = nodeStore.load(CreateFullThreeLevelTree());
auto root = nodeStore.createNewInnerNode(*fullThreeLevelRoot);
auto leaf1 = nodeStore.createNewLeafNode();
auto inner1 = nodeStore.createNewInnerNode(*leaf1);
FillNode(inner1.get());
auto leaf2 = nodeStore.createNewLeafNode();
auto inner2 = nodeStore.createNewInnerNode(*leaf2);
auto inner_top = nodeStore.createNewInnerNode(*inner1);
inner_top->addChild(*inner2);
root->addChild(*inner_top);
return root->key();
}
Key DataTreeShrinkingTest::CreateThreeLevelTreeWithThreeChildrenOfRoot() {
auto fullTwoLevelTree1 = nodeStore.load(CreateFullTwoLevelTree());
auto fullTwoLevelTree2 = nodeStore.load(CreateFullTwoLevelTree());
auto twonodechain = nodeStore.createNewInnerNode(*nodeStore.createNewLeafNode());
auto root = nodeStore.createNewInnerNode(*fullTwoLevelTree1);
root->addChild(*fullTwoLevelTree2);
root->addChild(*twonodechain);
return root->key();
}

View File

@ -0,0 +1,29 @@
#pragma once
#ifndef BLOCKS_MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_GROWING_DATATREESHRINKINGTEST_H_
#define BLOCKS_MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_GROWING_DATATREESHRINKINGTEST_H_
#include "../../testutils/DataTreeTest.h"
#include "../../../../../../implementations/onblocks/datanodestore/DataLeafNode.h"
#include "../../../../../../implementations/onblocks/datanodestore/DataInnerNode.h"
#include "messmer/cpp-utils/pointer.h"
class DataTreeShrinkingTest: public DataTreeTest {
public:
void Shrink(const blockstore::Key &key);
blockstore::Key CreateTwoLeafTree();
blockstore::Key CreateFourNodeThreeLeafTree();
blockstore::Key CreateTwoInnerNodeOneTwoLeavesTree();
blockstore::Key CreateTwoInnerNodeTwoOneLeavesTree();
blockstore::Key CreateThreeLevelMinDataTree();
blockstore::Key CreateFourLevelMinDataTree();
blockstore::Key CreateFourLevelTreeWithTwoSiblingLeaves1();
blockstore::Key CreateFourLevelTreeWithTwoSiblingLeaves2();
blockstore::Key CreateTreeWithFirstChildOfRootFullThreelevelAndSecondChildMindataThreelevel();
blockstore::Key CreateThreeLevelTreeWithThreeChildrenOfRoot();
};
#endif

View File

@ -1,14 +1,17 @@
#include "DataTreeTest.h"
#include "messmer/blockstore/implementations/testfake/FakeBlockStore.h"
#include <messmer/cpp-utils/pointer.h>
using blobstore::onblocks::datanodestore::DataNodeStore;
using blobstore::onblocks::datanodestore::DataInnerNode;
using blobstore::onblocks::datanodestore::DataLeafNode;
using blobstore::onblocks::datatreestore::DataTree;
using blockstore::testfake::FakeBlockStore;
using blockstore::Key;
using std::make_unique;
using std::unique_ptr;
using cpputils::dynamic_pointer_move;
DataTreeTest::DataTreeTest()
:nodeStore(make_unique<FakeBlockStore>()) {
@ -50,3 +53,53 @@ Key DataTreeTest::CreateFullThreeLevelTree() {
FillNodeTwoLevel(root.get());
return root->key();
}
unique_ptr<DataInnerNode> DataTreeTest::LoadInnerNode(const Key &key) {
auto node = nodeStore.load(key);
auto casted = dynamic_pointer_move<DataInnerNode>(node);
EXPECT_NE(nullptr, casted.get()) << "Is not an inner node";
return casted;
}
unique_ptr<DataLeafNode> DataTreeTest::LoadLeafNode(const Key &key) {
auto node = nodeStore.load(key);
auto casted = dynamic_pointer_move<DataLeafNode>(node);
EXPECT_NE(nullptr, casted.get()) << "Is not a leaf node";
return casted;
}
void DataTreeTest::EXPECT_IS_LEAF_NODE(const Key &key) {
auto node = LoadLeafNode(key);
EXPECT_NE(nullptr, node.get());
}
void DataTreeTest::EXPECT_IS_INNER_NODE(const Key &key) {
auto node = LoadInnerNode(key);
EXPECT_NE(nullptr, node.get());
}
void DataTreeTest::EXPECT_IS_TWONODE_CHAIN(const Key &key) {
auto node = LoadInnerNode(key);
EXPECT_EQ(1u, node->numChildren());
EXPECT_IS_LEAF_NODE(node->getChild(0)->key());
}
void DataTreeTest::EXPECT_IS_FULL_TWOLEVEL_TREE(const Key &key) {
auto node = LoadInnerNode(key);
EXPECT_EQ(DataInnerNode::MAX_STORED_CHILDREN, node->numChildren());
for (unsigned int i = 0; i < node->numChildren(); ++i) {
EXPECT_IS_LEAF_NODE(node->getChild(i)->key());
}
}
void DataTreeTest::EXPECT_IS_FULL_THREELEVEL_TREE(const Key &key) {
auto root = LoadInnerNode(key);
EXPECT_EQ(DataInnerNode::MAX_STORED_CHILDREN, root->numChildren());
for (unsigned int i = 0; i < root->numChildren(); ++i) {
auto node = LoadInnerNode(root->getChild(i)->key());
EXPECT_EQ(DataInnerNode::MAX_STORED_CHILDREN, node->numChildren());
for (unsigned int j = 0; j < node->numChildren(); ++j) {
EXPECT_IS_LEAF_NODE(node->getChild(j)->key());
}
}
}

View File

@ -19,6 +19,15 @@ public:
blockstore::Key CreateFullTwoLevelTree();
blockstore::Key CreateFullThreeLevelTree();
blobstore::onblocks::datanodestore::DataNodeStore nodeStore;
std::unique_ptr<blobstore::onblocks::datanodestore::DataInnerNode> LoadInnerNode(const blockstore::Key &key);
std::unique_ptr<blobstore::onblocks::datanodestore::DataLeafNode> LoadLeafNode(const blockstore::Key &key);
void EXPECT_IS_LEAF_NODE(const blockstore::Key &key);
void EXPECT_IS_INNER_NODE(const blockstore::Key &key);
void EXPECT_IS_TWONODE_CHAIN(const blockstore::Key &key);
void EXPECT_IS_FULL_TWOLEVEL_TREE(const blockstore::Key &key);
void EXPECT_IS_FULL_THREELEVEL_TREE(const blockstore::Key &key);
};