#include "DataInnerNode.h" #include "DataLeafNode.h" #include "DataNodeStore.h" #include #include #include #include using blockstore::BlockStore; using blockstore::Block; using blockstore::BlockId; using cpputils::Data; using cpputils::unique_ref; using cpputils::make_unique_ref; using cpputils::dynamic_pointer_move; using std::runtime_error; using boost::optional; using boost::none; using std::vector; namespace blobstore { namespace onblocks { namespace datanodestore { DataNodeStore::DataNodeStore(unique_ref blockstore, uint64_t physicalBlocksizeBytes) : _blockstore(std::move(blockstore)), _layout(_blockstore->blockSizeFromPhysicalBlockSize(physicalBlocksizeBytes)) { } DataNodeStore::~DataNodeStore() { } unique_ref DataNodeStore::load(unique_ref block) { DataNodeView node(std::move(block)); if (node.Depth() == 0) { return make_unique_ref(std::move(node)); } else if (node.Depth() <= MAX_DEPTH) { return make_unique_ref(std::move(node)); } else { throw runtime_error("Tree is to deep. Data corruption?"); } } unique_ref DataNodeStore::createNewInnerNode(uint8_t depth, const vector &children) { ASSERT(children.size() >= 1, "Inner node must have at least one child"); return DataInnerNode::CreateNewNode(_blockstore.get(), _layout, depth, children); } unique_ref DataNodeStore::createNewLeafNode(Data data) { return DataLeafNode::CreateNewNode(_blockstore.get(), _layout, std::move(data)); } unique_ref DataNodeStore::overwriteLeaf(const BlockId &blockId, Data data) { return DataLeafNode::OverwriteNode(_blockstore.get(), _layout, blockId, std::move(data)); } optional> DataNodeStore::load(const BlockId &blockId) { auto block = _blockstore->load(blockId); if (block == none) { return none; } else { ASSERT((*block)->size() == _layout.blocksizeBytes(), "Loading block of wrong size"); return load(std::move(*block)); } } unique_ref DataNodeStore::createNewNodeAsCopyFrom(const DataNode &source) { ASSERT(source.node().layout().blocksizeBytes() == _layout.blocksizeBytes(), "Source node has wrong layout. Is it from the same DataNodeStore?"); auto newBlock = blockstore::utils::copyToNewBlock(_blockstore.get(), source.node().block()); return load(std::move(newBlock)); } unique_ref DataNodeStore::overwriteNodeWith(unique_ref target, const DataNode &source) { ASSERT(target->node().layout().blocksizeBytes() == _layout.blocksizeBytes(), "Target node has wrong layout. Is it from the same DataNodeStore?"); ASSERT(source.node().layout().blocksizeBytes() == _layout.blocksizeBytes(), "Source node has wrong layout. Is it from the same DataNodeStore?"); auto targetBlock = target->node().releaseBlock(); cpputils::destruct(std::move(target)); // Call destructor blockstore::utils::copyTo(targetBlock.get(), source.node().block()); return DataNodeStore::load(std::move(targetBlock)); } void DataNodeStore::remove(unique_ref node) { BlockId blockId = node->blockId(); cpputils::destruct(std::move(node)); remove(blockId); } void DataNodeStore::remove(const BlockId &blockId) { _blockstore->remove(blockId); } void DataNodeStore::removeSubtree(unique_ref node) { auto leaf = dynamic_pointer_move(node); if (leaf != none) { remove(std::move(*leaf)); return; } auto inner = dynamic_pointer_move(node); ASSERT(inner != none, "Is neither a leaf nor an inner node"); for (uint32_t i = 0; i < (*inner)->numChildren(); ++i) { removeSubtree((*inner)->depth()-1, (*inner)->readChild(i).blockId()); } remove(std::move(*inner)); } // NOLINTNEXTLINE(misc-no-recursion) void DataNodeStore::removeSubtree(uint8_t depth, const BlockId &blockId) { if (depth == 0) { remove(blockId); } else { auto node = load(blockId); ASSERT(node != none, "Node for removeSubtree not found"); auto inner = dynamic_pointer_move(*node); ASSERT(inner != none, "Is not an inner node, but depth was not zero"); ASSERT((*inner)->depth() == depth, "Wrong depth given"); for (uint32_t i = 0; i < (*inner)->numChildren(); ++i) { removeSubtree(depth-1, (*inner)->readChild(i).blockId()); } remove(std::move(*inner)); } } uint64_t DataNodeStore::numNodes() const { return _blockstore->numBlocks(); } uint64_t DataNodeStore::estimateSpaceForNumNodesLeft() const { return _blockstore->estimateNumFreeBytes() / _layout.blocksizeBytes(); } uint64_t DataNodeStore::virtualBlocksizeBytes() const { return _layout.blocksizeBytes(); } DataNodeLayout DataNodeStore::layout() const { return _layout; } void DataNodeStore::forEachNode(std::function callback) const { _blockstore->forEachBlock(std::move(callback)); } } } }