Implement tree shrinking and some test cases for it
This commit is contained in:
parent
46a0bf617b
commit
ab2e789dac
@ -78,6 +78,11 @@ void DataInnerNode::addChild(const DataNode &child) {
|
||||
LastChild()->setKey(child.key());
|
||||
}
|
||||
|
||||
void DataInnerNode::removeLastChild() {
|
||||
assert(*node().Size() > 1);
|
||||
*node().Size() -= 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,8 @@ public:
|
||||
|
||||
void addChild(const DataNode &child_key);
|
||||
|
||||
void removeLastChild();
|
||||
|
||||
ChildEntry *LastChild();
|
||||
const ChildEntry *LastChild() const;
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "testutils/DataTreeGrowingTest.h"
|
||||
|
||||
#include "../../../../testutils/DataBlockFixture.h"
|
||||
#include <messmer/cpp-utils/pointer.h>
|
||||
|
||||
using ::testing::WithParamInterface;
|
||||
using ::testing::Values;
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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();
|
||||
}
|
@ -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
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user