libcryfs/implementations/onblocks/datatreestore/DataTree.cpp
2015-02-22 19:30:42 +01:00

123 lines
3.6 KiB
C++

#include "DataTree.h"
#include "../datanodestore/DataNodeStore.h"
#include "../datanodestore/DataInnerNode.h"
#include "../datanodestore/DataLeafNode.h"
#include "impl/algorithms.h"
#include "messmer/cpp-utils/pointer.h"
using blockstore::Key;
using blobstore::onblocks::datanodestore::DataNodeStore;
using blobstore::onblocks::datanodestore::DataNode;
using blobstore::onblocks::datanodestore::DataInnerNode;
using blobstore::onblocks::datanodestore::DataLeafNode;
using std::unique_ptr;
using std::dynamic_pointer_cast;
using std::function;
using cpputils::dynamic_pointer_move;
using cpputils::optional_ownership_ptr;
namespace blobstore {
namespace onblocks {
namespace datatreestore {
DataTree::DataTree(DataNodeStore *nodeStore, unique_ptr<DataNode> rootNode)
: _nodeStore(nodeStore), _rootNode(std::move(rootNode)) {
}
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));
}
}
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() {
auto insertPosOrNull = algorithms::GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNull(_nodeStore, _rootNode.get());
if (insertPosOrNull) {
return addDataLeafAt(insertPosOrNull.get());
} else {
return addDataLeafToFullTree();
}
}
unique_ptr<DataLeafNode> DataTree::addDataLeafAt(DataInnerNode *insertPos) {
auto new_leaf = _nodeStore->createNewLeafNode();
auto chain = createChainOfInnerNodes(insertPos->depth()-1, new_leaf.get());
insertPos->addChild(*chain);
return new_leaf;
}
optional_ownership_ptr<DataNode> DataTree::createChainOfInnerNodes(unsigned int num, DataLeafNode *leaf) {
optional_ownership_ptr<DataNode> chain = cpputils::WithoutOwnership<DataNode>(leaf);
for(unsigned int i=0; i<num; ++i) {
auto newnode = _nodeStore->createNewInnerNode(*chain);
chain = cpputils::WithOwnership<DataNode>(std::move(newnode));
}
return chain;
}
unique_ptr<DataLeafNode> DataTree::addDataLeafToFullTree() {
auto copyOfOldRoot = _nodeStore->createNewNodeAsCopyFrom(*_rootNode);
auto newRootNode = DataNode::convertToNewInnerNode(std::move(_rootNode), *copyOfOldRoot);
auto newLeaf = addDataLeafAt(newRootNode.get());
_rootNode = std::move(newRootNode);
return newLeaf;
}
const Key &DataTree::key() const {
return _rootNode->key();
}
void DataTree::flush() const {
_rootNode->flush();
}
}
}
}