diff --git a/src/blobstore/implementations/onblocks/datanodestore/DataInnerNode.cpp b/src/blobstore/implementations/onblocks/datanodestore/DataInnerNode.cpp index c8ea3026..c87d8836 100644 --- a/src/blobstore/implementations/onblocks/datanodestore/DataInnerNode.cpp +++ b/src/blobstore/implementations/onblocks/datanodestore/DataInnerNode.cpp @@ -3,10 +3,12 @@ #include using blockstore::Block; +using blockstore::BlockStore; using cpputils::Data; using cpputils::unique_ref; using cpputils::make_unique_ref; using blockstore::Key; +using std::vector; namespace blobstore { namespace onblocks { @@ -23,14 +25,27 @@ DataInnerNode::DataInnerNode(DataNodeView view) DataInnerNode::~DataInnerNode() { } -unique_ref DataInnerNode::InitializeNewNode(unique_ref block, const DataNode &first_child) { - DataNodeView node(std::move(block)); - node.setFormatVersion(DataNode::FORMAT_VERSION_HEADER); - node.setDepth(first_child.depth() + 1); - node.setSize(1); - auto result = make_unique_ref(std::move(node)); - result->ChildrenBegin()->setKey(first_child.key()); - return result; +unique_ref DataInnerNode::InitializeNewNode(unique_ref block, const DataNodeLayout &layout, uint8_t depth, const vector &children) { + ASSERT(children.size() >= 1, "An inner node must have at least one child"); + Data data = _serializeChildren(children); + + return make_unique_ref(DataNodeView::initialize(std::move(block), layout, DataNode::FORMAT_VERSION_HEADER, depth, children.size(), std::move(data))); +} + +unique_ref DataInnerNode::CreateNewNode(BlockStore *blockStore, const DataNodeLayout &layout, uint8_t depth, const vector &children) { + ASSERT(children.size() >= 1, "An inner node must have at least one child"); + Data data = _serializeChildren(children); + + return make_unique_ref(DataNodeView::create(blockStore, layout, DataNode::FORMAT_VERSION_HEADER, depth, children.size(), std::move(data))); +} + +Data DataInnerNode::_serializeChildren(const vector &children) { + Data data(sizeof(ChildEntry) * children.size()); + uint32_t i = 0; + for (const Key &child : children) { + reinterpret_cast(data.data())[i++].setKey(child); + } + return data; } uint32_t DataInnerNode::numChildren() const { diff --git a/src/blobstore/implementations/onblocks/datanodestore/DataInnerNode.h b/src/blobstore/implementations/onblocks/datanodestore/DataInnerNode.h index 967d6746..72693f02 100644 --- a/src/blobstore/implementations/onblocks/datanodestore/DataInnerNode.h +++ b/src/blobstore/implementations/onblocks/datanodestore/DataInnerNode.h @@ -11,7 +11,8 @@ namespace datanodestore { class DataInnerNode final: public DataNode { public: - static cpputils::unique_ref InitializeNewNode(cpputils::unique_ref block, const DataNode &first_child_key); + static cpputils::unique_ref InitializeNewNode(cpputils::unique_ref block, const DataNodeLayout &layout, uint8_t depth, const std::vector &children); + static cpputils::unique_ref CreateNewNode(blockstore::BlockStore *blockStore, const DataNodeLayout &layout, uint8_t depth, const std::vector &children); DataInnerNode(DataNodeView block); ~DataInnerNode(); @@ -39,6 +40,8 @@ private: const ChildEntry *ChildrenBegin() const; const ChildEntry *ChildrenEnd() const; + static cpputils::Data _serializeChildren(const std::vector &children); + DISALLOW_COPY_AND_ASSIGN(DataInnerNode); }; diff --git a/src/blobstore/implementations/onblocks/datanodestore/DataLeafNode.cpp b/src/blobstore/implementations/onblocks/datanodestore/DataLeafNode.cpp index d0681950..f1d7ab13 100644 --- a/src/blobstore/implementations/onblocks/datanodestore/DataLeafNode.cpp +++ b/src/blobstore/implementations/onblocks/datanodestore/DataLeafNode.cpp @@ -5,6 +5,7 @@ using blockstore::Block; using cpputils::Data; using blockstore::Key; +using blockstore::BlockStore; using cpputils::unique_ref; using cpputils::make_unique_ref; @@ -24,13 +25,10 @@ DataLeafNode::DataLeafNode(DataNodeView view) DataLeafNode::~DataLeafNode() { } -unique_ref DataLeafNode::InitializeNewNode(unique_ref block) { - DataNodeView node(std::move(block)); - node.setFormatVersion(DataNode::FORMAT_VERSION_HEADER); - node.setDepth(0); - node.setSize(0); - //fillDataWithZeroes(); not needed, because a newly created block will be zeroed out. DataLeafNodeTest.SpaceIsZeroFilledWhenGrowing ensures this. - return make_unique_ref(std::move(node)); +unique_ref DataLeafNode::CreateNewNode(BlockStore *blockStore, const DataNodeLayout &layout, Data data) { + ASSERT(data.size() <= layout.maxBytesPerLeaf(), "Data passed in is too large for one leaf."); + uint32_t size = data.size(); + return make_unique_ref(DataNodeView::create(blockStore, layout, DataNode::FORMAT_VERSION_HEADER, 0, size, std::move(data))); } void DataLeafNode::read(void *target, uint64_t offset, uint64_t size) const { diff --git a/src/blobstore/implementations/onblocks/datanodestore/DataLeafNode.h b/src/blobstore/implementations/onblocks/datanodestore/DataLeafNode.h index d707eb44..f509a850 100644 --- a/src/blobstore/implementations/onblocks/datanodestore/DataLeafNode.h +++ b/src/blobstore/implementations/onblocks/datanodestore/DataLeafNode.h @@ -11,7 +11,8 @@ class DataInnerNode; class DataLeafNode final: public DataNode { public: - static cpputils::unique_ref InitializeNewNode(cpputils::unique_ref block); + //static cpputils::unique_ref InitializeNewNode(cpputils::unique_ref block); + static cpputils::unique_ref CreateNewNode(blockstore::BlockStore *blockStore, const DataNodeLayout &layout, cpputils::Data data); DataLeafNode(DataNodeView block); ~DataLeafNode(); diff --git a/src/blobstore/implementations/onblocks/datanodestore/DataNode.cpp b/src/blobstore/implementations/onblocks/datanodestore/DataNode.cpp index f1a1a90b..bbcf346a 100644 --- a/src/blobstore/implementations/onblocks/datanodestore/DataNode.cpp +++ b/src/blobstore/implementations/onblocks/datanodestore/DataNode.cpp @@ -39,11 +39,11 @@ uint8_t DataNode::depth() const { return _node.Depth(); } -unique_ref DataNode::convertToNewInnerNode(unique_ref node, const DataNode &first_child) { +unique_ref DataNode::convertToNewInnerNode(unique_ref node, const DataNodeLayout &layout, const DataNode &first_child) { auto block = node->_node.releaseBlock(); blockstore::utils::fillWithZeroes(block.get()); - return DataInnerNode::InitializeNewNode(std::move(block), first_child); + return DataInnerNode::InitializeNewNode(std::move(block), layout, first_child.depth()+1, {first_child.key()}); } void DataNode::flush() const { diff --git a/src/blobstore/implementations/onblocks/datanodestore/DataNode.h b/src/blobstore/implementations/onblocks/datanodestore/DataNode.h index 75de60b2..08558338 100644 --- a/src/blobstore/implementations/onblocks/datanodestore/DataNode.h +++ b/src/blobstore/implementations/onblocks/datanodestore/DataNode.h @@ -19,7 +19,7 @@ public: uint8_t depth() const; - static cpputils::unique_ref convertToNewInnerNode(cpputils::unique_ref node, const DataNode &first_child); + static cpputils::unique_ref convertToNewInnerNode(cpputils::unique_ref node, const DataNodeLayout &layout, const DataNode &first_child); void flush() const; diff --git a/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.cpp b/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.cpp index d244fcb2..82b1d80e 100644 --- a/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.cpp +++ b/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.cpp @@ -16,6 +16,7 @@ using cpputils::dynamic_pointer_move; using std::runtime_error; using boost::optional; using boost::none; +using std::vector; namespace blobstore { namespace onblocks { @@ -41,17 +42,13 @@ unique_ref DataNodeStore::load(unique_ref block) { } } -unique_ref DataNodeStore::createNewInnerNode(const DataNode &first_child) { - ASSERT(first_child.node().layout().blocksizeBytes() == _layout.blocksizeBytes(), "Source node has wrong layout. Is it from the same DataNodeStore?"); - //TODO Initialize block and then create it in the blockstore - this is more efficient than creating it and then writing to it - auto block = _blockstore->create(Data(_layout.blocksizeBytes()).FillWithZeroes()); - return DataInnerNode::InitializeNewNode(std::move(block), first_child); +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() { - //TODO Initialize block and then create it in the blockstore - this is more efficient than creating it and then writing to it - auto block = _blockstore->create(Data(_layout.blocksizeBytes()).FillWithZeroes()); - return DataLeafNode::InitializeNewNode(std::move(block)); +unique_ref DataNodeStore::createNewLeafNode(Data data) { + return DataLeafNode::CreateNewNode(_blockstore.get(), _layout, std::move(data)); } optional> DataNodeStore::load(const Key &key) { diff --git a/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.h b/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.h index f48efdfe..c9e67f6f 100644 --- a/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.h +++ b/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.h @@ -30,8 +30,8 @@ public: boost::optional> load(const blockstore::Key &key); - cpputils::unique_ref createNewLeafNode(); - cpputils::unique_ref createNewInnerNode(const DataNode &first_child); + cpputils::unique_ref createNewLeafNode(cpputils::Data data); + cpputils::unique_ref createNewInnerNode(uint8_t depth, const std::vector &children); cpputils::unique_ref createNewNodeAsCopyFrom(const DataNode &source); diff --git a/src/blobstore/implementations/onblocks/datanodestore/DataNodeView.h b/src/blobstore/implementations/onblocks/datanodestore/DataNodeView.h index ab69bbfc..57f63f76 100644 --- a/src/blobstore/implementations/onblocks/datanodestore/DataNodeView.h +++ b/src/blobstore/implementations/onblocks/datanodestore/DataNodeView.h @@ -65,6 +65,22 @@ public: } ~DataNodeView() {} + static DataNodeView create(blockstore::BlockStore *blockStore, const DataNodeLayout &layout, uint16_t formatVersion, uint8_t depth, uint32_t size, cpputils::Data data) { + ASSERT(data.size() <= layout.datasizeBytes(), "Data is too large for node"); + cpputils::Data serialized = _serialize(layout, formatVersion, depth, size, std::move(data)); + ASSERT(serialized.size() == layout.blocksizeBytes(), "Wrong block size"); + auto block = blockStore->create(std::move(serialized)); + return DataNodeView(std::move(block)); + } + + static DataNodeView initialize(cpputils::unique_ref block, const DataNodeLayout &layout, uint16_t formatVersion, uint8_t depth, uint32_t size, cpputils::Data data) { + ASSERT(data.size() <= DataNodeLayout(block->size()).datasizeBytes(), "Data is too large for node"); + cpputils::Data serialized = _serialize(layout, formatVersion, depth, size, std::move(data)); + ASSERT(serialized.size() == block->size(), "Block has wrong size"); + block->write(serialized.data(), 0, serialized.size()); + return DataNodeView(std::move(block)); + } + DataNodeView(DataNodeView &&rhs) = default; uint16_t FormatVersion() const { @@ -136,6 +152,16 @@ private: return (Type*)(((const int8_t*)_block->data())+offset); } + static cpputils::Data _serialize(const DataNodeLayout &layout, uint16_t formatVersion, uint8_t depth, uint32_t size, cpputils::Data data) { + cpputils::Data result(layout.blocksizeBytes()); + *((uint16_t*)result.dataOffset(layout.FORMAT_VERSION_OFFSET_BYTES)) = formatVersion; + *((uint8_t*)result.dataOffset(layout.DEPTH_OFFSET_BYTES)) = depth; + *((uint32_t*)result.dataOffset(layout.SIZE_OFFSET_BYTES)) = size; + std::memcpy(result.dataOffset(layout.HEADERSIZE_BYTES), data.data(), data.size()); + std::memset(result.dataOffset(layout.HEADERSIZE_BYTES+data.size()), 0, layout.datasizeBytes()-data.size()); + return result; + } + cpputils::unique_ref _block; DISALLOW_COPY_AND_ASSIGN(DataNodeView); diff --git a/src/blobstore/implementations/onblocks/datatreestore/DataTree.cpp b/src/blobstore/implementations/onblocks/datatreestore/DataTree.cpp index 0899639b..799936cc 100644 --- a/src/blobstore/implementations/onblocks/datatreestore/DataTree.cpp +++ b/src/blobstore/implementations/onblocks/datatreestore/DataTree.cpp @@ -176,7 +176,7 @@ void DataTree::resizeNumBytes(uint64_t newNumBytes) { _traverseLeaves(newNumLeaves - 1, newNumLeaves, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); _numLeavesCache = newNumLeaves; - ASSERT(newNumBytes == _numStoredBytes(), "We resized to the wrong number of bytes ("+std::to_string(numStoredBytes())+" instead of "+std::to_string(newNumBytes)+")"); + ASSERT(newNumBytes == _numStoredBytes(), "We resized to the wrong number of bytes ("+std::to_string(_numStoredBytes())+" instead of "+std::to_string(newNumBytes)+")"); } uint64_t DataTree::maxBytesPerLeaf() const { diff --git a/src/blobstore/implementations/onblocks/datatreestore/DataTreeStore.cpp b/src/blobstore/implementations/onblocks/datatreestore/DataTreeStore.cpp index cbbd344f..76a9255e 100644 --- a/src/blobstore/implementations/onblocks/datatreestore/DataTreeStore.cpp +++ b/src/blobstore/implementations/onblocks/datatreestore/DataTreeStore.cpp @@ -4,6 +4,7 @@ using cpputils::unique_ref; using cpputils::make_unique_ref; +using cpputils::Data; using boost::optional; using boost::none; @@ -30,7 +31,7 @@ optional> DataTreeStore::load(const blockstore::Key &key) { } unique_ref DataTreeStore::createNewTree() { - auto newleaf = _nodeStore->createNewLeafNode(); + auto newleaf = _nodeStore->createNewLeafNode(Data(0)); return make_unique_ref(_nodeStore.get(), std::move(newleaf)); } diff --git a/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.cpp b/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.cpp index 0f70146f..48b10b43 100644 --- a/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.cpp +++ b/src/blobstore/implementations/onblocks/datatreestore/impl/LeafTraverser.cpp @@ -57,7 +57,7 @@ namespace blobstore { unique_ref LeafTraverser::_increaseTreeDepth(unique_ref root) { auto copyOfOldRoot = _nodeStore->createNewNodeAsCopyFrom(*root); - return DataNode::convertToNewInnerNode(std::move(root), *copyOfOldRoot); + return DataNode::convertToNewInnerNode(std::move(root), _nodeStore->layout(), *copyOfOldRoot); } void LeafTraverser::_traverseExistingSubtree(DataNode *root, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool growLastLeaf, function onExistingLeaf, function onCreateLeaf, function onBacktrackFromSubtree) { @@ -68,7 +68,7 @@ namespace blobstore { DataLeafNode *leaf = dynamic_cast(root); if (leaf != nullptr) { ASSERT(beginIndex <= 1 && endIndex <= 1, "If root node is a leaf, the (sub)tree has only one leaf - access indices must be 0 or 1."); - if (growLastLeaf) { + if (growLastLeaf && leaf->numBytes() != _nodeStore->layout().maxBytesPerLeaf()) { leaf->resize(_nodeStore->layout().maxBytesPerLeaf()); } if (beginIndex == 0 && endIndex == 1) { @@ -141,12 +141,7 @@ namespace blobstore { if (0 == depth) { ASSERT(beginIndex <= 1 && endIndex == 1, "With depth 0, we can only traverse one or zero leaves (i.e. traverse one leaf or traverse a gap leaf)."); auto leafCreator = (beginIndex == 0) ? onCreateLeaf : _createMaxSizeLeaf(); - auto data = leafCreator(leafOffset); - // TODO Performance: Directly create leaf node with data. - auto node = _nodeStore->createNewLeafNode(); - node->resize(data.size()); - node->write(data.data(), 0, data.size()); - return node; + return _nodeStore->createNewLeafNode(leafCreator(leafOffset)); } uint8_t minNeededDepth = utils::ceilLog(_nodeStore->layout().maxChildrenPerInnerNode(), (uint64_t)endIndex); @@ -155,7 +150,7 @@ namespace blobstore { uint32_t beginChild = beginIndex/leavesPerChild; uint32_t endChild = utils::ceilDivision(endIndex, leavesPerChild); - vector> children; + vector children; children.reserve(endChild); // TODO Remove redundancy of following two for loops by using min/max for calculating the parameters of the recursive call. // Create gap children (i.e. children before the traversal but after the current size) @@ -164,7 +159,8 @@ namespace blobstore { auto child = _createNewSubtree(leavesPerChild, leavesPerChild, leafOffset + childOffset, depth - 1, [] (uint32_t /*index*/)->Data {ASSERT(false, "We're only creating gap leaves here, not traversing any.");}, [] (DataInnerNode* /*node*/) {}); - children.push_back(std::move(child)); + ASSERT(child->depth() == depth-1, "Created child node has wrong depth"); + children.push_back(child->key()); } // Create new children that are traversed for(uint32_t childIndex = beginChild; childIndex < endChild; ++childIndex) { @@ -172,15 +168,13 @@ namespace blobstore { uint32_t localBeginIndex = utils::maxZeroSubtraction(beginIndex, childOffset); uint32_t localEndIndex = std::min(leavesPerChild, endIndex - childOffset); auto child = _createNewSubtree(localBeginIndex, localEndIndex, leafOffset + childOffset, depth - 1, onCreateLeaf, onBacktrackFromSubtree); - children.push_back(std::move(child)); + ASSERT(child->depth() == depth-1, "Created child node has wrong depth"); + children.push_back(child->key()); } ASSERT(children.size() > 0, "No children created"); - //TODO Performance: Directly create inner node with all children - auto newNode = _nodeStore->createNewInnerNode(*children[0]); - for (auto childIter = children.begin()+1; childIter != children.end(); ++childIter) { - newNode->addChild(**childIter); - } + auto newNode = _nodeStore->createNewInnerNode(depth, children); + // This is only a backtrack, if we actually created a leaf here. if (endIndex > beginIndex) { onBacktrackFromSubtree(newNode.get()); diff --git a/src/blockstore/implementations/mock/MockBlockStore.h b/src/blockstore/implementations/mock/MockBlockStore.h index e30ae625..d2d5113f 100644 --- a/src/blockstore/implementations/mock/MockBlockStore.h +++ b/src/blockstore/implementations/mock/MockBlockStore.h @@ -81,22 +81,31 @@ namespace blockstore { return _createdBlocks; } - const std::vector loadedBlocks() const { + const std::vector &loadedBlocks() const { return _loadedBlocks; } - const std::vector removedBlocks() const { + const std::vector &removedBlocks() const { return _removedBlocks; } - const std::vector resizedBlocks() const { + const std::vector &resizedBlocks() const { return _resizedBlocks; } - const std::vector writtenBlocks() const { + const std::vector &writtenBlocks() const { return _writtenBlocks; } + std::vector distinctWrittenBlocks() const { + std::vector result(_writtenBlocks); + std::sort(result.begin(), result.end(), [](const Key &lhs, const Key &rhs) { + return std::memcmp(lhs.data(), rhs.data(), lhs.BINARY_LENGTH) < 0; + }); + result.erase(std::unique(result.begin(), result.end() ), result.end()); + return result; + } + private: void _increaseNumCreatedBlocks() { std::unique_lock lock(_mutex); diff --git a/test/blobstore/implementations/onblocks/datanodestore/DataInnerNodeTest.cpp b/test/blobstore/implementations/onblocks/datanodestore/DataInnerNodeTest.cpp index ce413be3..084e43f6 100644 --- a/test/blobstore/implementations/onblocks/datanodestore/DataInnerNodeTest.cpp +++ b/test/blobstore/implementations/onblocks/datanodestore/DataInnerNodeTest.cpp @@ -24,6 +24,7 @@ using namespace blobstore::onblocks::datanodestore; using cpputils::unique_ref; using cpputils::make_unique_ref; +using std::vector; class DataInnerNodeTest: public Test { public: @@ -34,8 +35,8 @@ public: blockStore(_blockStore.get()), nodeStore(make_unique_ref(std::move(_blockStore), BLOCKSIZE_BYTES)), ZEROES(nodeStore->layout().maxBytesPerLeaf()), - leaf(nodeStore->createNewLeafNode()), - node(nodeStore->createNewInnerNode(*leaf)) { + leaf(nodeStore->createNewLeafNode(Data(0))), + node(nodeStore->createNewInnerNode(1, {leaf->key()})) { ZEROES.FillWithZeroes(); } @@ -46,12 +47,12 @@ public: } Key CreateNewInnerNodeReturnKey(const DataNode &firstChild) { - return nodeStore->createNewInnerNode(firstChild)->key(); + return nodeStore->createNewInnerNode(firstChild.depth()+1, {firstChild.key()})->key(); } unique_ref CreateNewInnerNode() { - auto new_leaf = nodeStore->createNewLeafNode(); - return nodeStore->createNewInnerNode(*new_leaf); + auto new_leaf = nodeStore->createNewLeafNode(Data(0)); + return nodeStore->createNewInnerNode(1, {new_leaf->key()}); } unique_ref CreateAndLoadNewInnerNode(const DataNode &firstChild) { @@ -59,23 +60,21 @@ public: return LoadInnerNode(key); } - unique_ref CreateNewInnerNode(const DataNode &firstChild, const DataNode &secondChild) { - auto node = nodeStore->createNewInnerNode(firstChild); - node->addChild(secondChild); - return node; + unique_ref CreateNewInnerNode(uint8_t depth, const vector &children) { + return nodeStore->createNewInnerNode(depth, children); } - Key CreateNewInnerNodeReturnKey(const DataNode &firstChild, const DataNode &secondChild) { - return CreateNewInnerNode(firstChild, secondChild)->key(); + Key CreateNewInnerNodeReturnKey(uint8_t depth, const vector &children) { + return CreateNewInnerNode(depth, children)->key(); } - unique_ref CreateAndLoadNewInnerNode(const DataNode &firstChild, const DataNode &secondChild) { - auto key = CreateNewInnerNodeReturnKey(firstChild, secondChild); + unique_ref CreateAndLoadNewInnerNode(uint8_t depth, const vector &children) { + auto key = CreateNewInnerNodeReturnKey(depth, children); return LoadInnerNode(key); } Key AddALeafTo(DataInnerNode *node) { - auto leaf2 = nodeStore->createNewLeafNode(); + auto leaf2 = nodeStore->createNewLeafNode(Data(0)); node->addChild(*leaf2); return leaf2->key(); } @@ -84,8 +83,8 @@ public: auto node = CreateNewInnerNode(); AddALeafTo(node.get()); AddALeafTo(node.get()); - auto child = nodeStore->createNewLeafNode(); - unique_ref converted = DataNode::convertToNewInnerNode(std::move(node), *child); + auto child = nodeStore->createNewLeafNode(Data(0)); + unique_ref converted = DataNode::convertToNewInnerNode(std::move(node), nodeStore->layout(), *child); return converted->key(); } @@ -95,7 +94,7 @@ public: } Key InitializeInnerNodeAddLeafReturnKey() { - auto node = DataInnerNode::InitializeNewNode(blockStore->create(Data(BLOCKSIZE_BYTES)), *leaf); + auto node = DataInnerNode::CreateNewNode(blockStore, nodeStore->layout(), 1, {leaf->key()}); AddALeafTo(node.get()); return node->key(); } @@ -114,32 +113,23 @@ private: constexpr uint32_t DataInnerNodeTest::BLOCKSIZE_BYTES; -TEST_F(DataInnerNodeTest, CorrectKeyReturnedAfterInitialization) { - auto block = blockStore->create(Data(BLOCKSIZE_BYTES)); - Key key = block->key(); - auto node = DataInnerNode::InitializeNewNode(std::move(block), *leaf); - EXPECT_EQ(key, node->key()); -} - TEST_F(DataInnerNodeTest, CorrectKeyReturnedAfterLoading) { - auto block = blockStore->create(Data(BLOCKSIZE_BYTES)); - Key key = block->key(); - DataInnerNode::InitializeNewNode(std::move(block), *leaf); + Key key = DataInnerNode::CreateNewNode(blockStore, nodeStore->layout(), 1, {leaf->key()})->key(); auto loaded = nodeStore->load(key).value(); EXPECT_EQ(key, loaded->key()); } TEST_F(DataInnerNodeTest, InitializesCorrectly) { - auto node = DataInnerNode::InitializeNewNode(blockStore->create(Data(BLOCKSIZE_BYTES)), *leaf); + auto node = DataInnerNode::CreateNewNode(blockStore, nodeStore->layout(), 1, {leaf->key()}); EXPECT_EQ(1u, node->numChildren()); EXPECT_EQ(leaf->key(), node->getChild(0)->key()); } TEST_F(DataInnerNodeTest, ReinitializesCorrectly) { - auto key = InitializeInnerNodeAddLeafReturnKey(); - auto node = DataInnerNode::InitializeNewNode(blockStore->load(key).value(), *leaf); + auto key = DataLeafNode::CreateNewNode(blockStore, nodeStore->layout(), Data(0))->key(); + auto node = DataInnerNode::InitializeNewNode(blockStore->load(key).value(), nodeStore->layout(), 1, {leaf->key()}); EXPECT_EQ(1u, node->numChildren()); EXPECT_EQ(leaf->key(), node->getChild(0)->key()); @@ -161,8 +151,8 @@ TEST_F(DataInnerNodeTest, AddingASecondLeaf) { } TEST_F(DataInnerNodeTest, AddingASecondLeafAndReload) { - auto leaf2 = nodeStore->createNewLeafNode(); - auto loaded = CreateAndLoadNewInnerNode(*leaf, *leaf2); + auto leaf2 = nodeStore->createNewLeafNode(Data(0)); + auto loaded = CreateAndLoadNewInnerNode(1, {leaf->key(), leaf2->key()}); EXPECT_EQ(2u, loaded->numChildren()); EXPECT_EQ(leaf->key(), loaded->getChild(0)->key()); @@ -171,7 +161,7 @@ TEST_F(DataInnerNodeTest, AddingASecondLeafAndReload) { TEST_F(DataInnerNodeTest, BuildingAThreeLevelTree) { auto node2 = CreateNewInnerNode(); - auto parent = CreateNewInnerNode(*node, *node2); + auto parent = CreateNewInnerNode(node->depth()+1, {node->key(), node2->key()}); EXPECT_EQ(2u, parent->numChildren()); EXPECT_EQ(node->key(), parent->getChild(0)->key()); @@ -180,7 +170,7 @@ TEST_F(DataInnerNodeTest, BuildingAThreeLevelTree) { TEST_F(DataInnerNodeTest, BuildingAThreeLevelTreeAndReload) { auto node2 = CreateNewInnerNode(); - auto parent = CreateAndLoadNewInnerNode(*node, *node2); + auto parent = CreateAndLoadNewInnerNode(node->depth()+1, {node->key(), node2->key()}); EXPECT_EQ(2u, parent->numChildren()); EXPECT_EQ(node->key(), parent->getChild(0)->key()); @@ -188,9 +178,9 @@ TEST_F(DataInnerNodeTest, BuildingAThreeLevelTreeAndReload) { } TEST_F(DataInnerNodeTest, ConvertToInternalNode) { - auto child = nodeStore->createNewLeafNode(); + auto child = nodeStore->createNewLeafNode(Data(0)); Key node_key = node->key(); - unique_ref converted = DataNode::convertToNewInnerNode(std::move(node), *child); + unique_ref converted = DataNode::convertToNewInnerNode(std::move(node), nodeStore->layout(), *child); EXPECT_EQ(1u, converted->numChildren()); EXPECT_EQ(child->key(), converted->getChild(0)->key()); diff --git a/test/blobstore/implementations/onblocks/datanodestore/DataLeafNodeTest.cpp b/test/blobstore/implementations/onblocks/datanodestore/DataLeafNodeTest.cpp index a53df1a9..bfcd7fbe 100644 --- a/test/blobstore/implementations/onblocks/datanodestore/DataLeafNodeTest.cpp +++ b/test/blobstore/implementations/onblocks/datanodestore/DataLeafNodeTest.cpp @@ -45,7 +45,7 @@ public: nodeStore(make_unique_ref(std::move(_blockStore), BLOCKSIZE_BYTES)), ZEROES(nodeStore->layout().maxBytesPerLeaf()), randomData(nodeStore->layout().maxBytesPerLeaf()), - leaf(nodeStore->createNewLeafNode()) { + leaf(nodeStore->createNewLeafNode(Data(0))) { ZEROES.FillWithZeroes(); @@ -61,7 +61,7 @@ public: } Key WriteDataToNewLeafBlockAndReturnKey() { - auto newleaf = nodeStore->createNewLeafNode(); + auto newleaf = nodeStore->createNewLeafNode(Data(0)); newleaf->resize(randomData.size()); newleaf->write(randomData.data(), 0, randomData.size()); return newleaf->key(); @@ -88,10 +88,10 @@ public: } Key CreateLeafWithDataConvertItToInnerNodeAndReturnKey() { - auto leaf = nodeStore->createNewLeafNode(); + auto leaf = nodeStore->createNewLeafNode(Data(0)); FillLeafBlockWithData(leaf.get()); - auto child = nodeStore->createNewLeafNode(); - unique_ref converted = DataNode::convertToNewInnerNode(std::move(leaf), *child); + auto child = nodeStore->createNewLeafNode(Data(0)); + unique_ref converted = DataNode::convertToNewInnerNode(std::move(leaf), LAYOUT, *child); return converted->key(); } @@ -101,7 +101,7 @@ public: } Key InitializeLeafGrowAndReturnKey() { - auto leaf = DataLeafNode::InitializeNewNode(blockStore->create(Data(BLOCKSIZE_BYTES))); + auto leaf = DataLeafNode::CreateNewNode(blockStore, LAYOUT, Data(LAYOUT.maxBytesPerLeaf())); leaf->resize(5); return leaf->key(); } @@ -120,31 +120,16 @@ private: constexpr uint32_t DataLeafNodeTest::BLOCKSIZE_BYTES; constexpr DataNodeLayout DataLeafNodeTest::LAYOUT; -TEST_F(DataLeafNodeTest, CorrectKeyReturnedAfterInitialization) { - auto block = blockStore->create(Data(BLOCKSIZE_BYTES)); - Key key = block->key(); - auto node = DataLeafNode::InitializeNewNode(std::move(block)); - EXPECT_EQ(key, node->key()); -} - TEST_F(DataLeafNodeTest, CorrectKeyReturnedAfterLoading) { - auto block = blockStore->create(Data(BLOCKSIZE_BYTES)); - Key key = block->key(); - DataLeafNode::InitializeNewNode(std::move(block)); + Key key = DataLeafNode::CreateNewNode(blockStore, LAYOUT, Data(LAYOUT.maxBytesPerLeaf()))->key(); auto loaded = nodeStore->load(key).value(); EXPECT_EQ(key, loaded->key()); } TEST_F(DataLeafNodeTest, InitializesCorrectly) { - auto leaf = DataLeafNode::InitializeNewNode(blockStore->create(Data(BLOCKSIZE_BYTES))); - EXPECT_EQ(0u, leaf->numBytes()); -} - -TEST_F(DataLeafNodeTest, ReinitializesCorrectly) { - auto key = InitializeLeafGrowAndReturnKey(); - auto leaf = DataLeafNode::InitializeNewNode(blockStore->load(key).value()); - EXPECT_EQ(0u, leaf->numBytes()); + auto leaf = DataLeafNode::CreateNewNode(blockStore, LAYOUT, Data(5)); + EXPECT_EQ(5u, leaf->numBytes()); } TEST_F(DataLeafNodeTest, ReadWrittenDataAfterReloadingBlock) { @@ -161,7 +146,7 @@ TEST_F(DataLeafNodeTest, NewLeafNodeHasSizeZero) { } TEST_F(DataLeafNodeTest, NewLeafNodeHasSizeZero_AfterLoading) { - Key key = nodeStore->createNewLeafNode()->key(); + Key key = nodeStore->createNewLeafNode(Data(0))->key(); auto leaf = LoadLeafNode(key); EXPECT_EQ(0u, leaf->numBytes()); @@ -170,7 +155,7 @@ TEST_F(DataLeafNodeTest, NewLeafNodeHasSizeZero_AfterLoading) { class DataLeafNodeSizeTest: public DataLeafNodeTest, public WithParamInterface { public: Key CreateLeafResizeItAndReturnKey() { - auto leaf = nodeStore->createNewLeafNode(); + auto leaf = nodeStore->createNewLeafNode(Data(0)); leaf->resize(GetParam()); return leaf->key(); } @@ -232,9 +217,9 @@ TEST_F(DataLeafNodeTest, ShrinkingDoesntDestroyValidDataRegion) { } TEST_F(DataLeafNodeTest, ConvertToInternalNode) { - auto child = nodeStore->createNewLeafNode(); + auto child = nodeStore->createNewLeafNode(Data(0)); Key leaf_key = leaf->key(); - unique_ref converted = DataNode::convertToNewInnerNode(std::move(leaf), *child); + unique_ref converted = DataNode::convertToNewInnerNode(std::move(leaf), LAYOUT, *child); EXPECT_EQ(1u, converted->numChildren()); EXPECT_EQ(child->key(), converted->getChild(0)->key()); @@ -290,7 +275,7 @@ public: } Key CreateLeafWriteToItAndReturnKey(const Data &to_write) { - auto newleaf = nodeStore->createNewLeafNode(); + auto newleaf = nodeStore->createNewLeafNode(Data(0)); newleaf->resize(GetParam().leafsize); newleaf->write(to_write.data(), GetParam().offset, GetParam().count); diff --git a/test/blobstore/implementations/onblocks/datanodestore/DataNodeStoreTest.cpp b/test/blobstore/implementations/onblocks/datanodestore/DataNodeStoreTest.cpp index 243d08c0..30c007c0 100644 --- a/test/blobstore/implementations/onblocks/datanodestore/DataNodeStoreTest.cpp +++ b/test/blobstore/implementations/onblocks/datanodestore/DataNodeStoreTest.cpp @@ -37,19 +37,19 @@ constexpr uint32_t DataNodeStoreTest::BLOCKSIZE_BYTES; #define EXPECT_IS_PTR_TYPE(Type, ptr) EXPECT_NE(nullptr, dynamic_cast(ptr)) << "Given pointer cannot be cast to the given type" TEST_F(DataNodeStoreTest, CreateLeafNodeCreatesLeafNode) { - auto node = nodeStore->createNewLeafNode(); + auto node = nodeStore->createNewLeafNode(Data(0)); EXPECT_IS_PTR_TYPE(DataLeafNode, node.get()); } TEST_F(DataNodeStoreTest, CreateInnerNodeCreatesInnerNode) { - auto leaf = nodeStore->createNewLeafNode(); + auto leaf = nodeStore->createNewLeafNode(Data(0)); - auto node = nodeStore->createNewInnerNode(*leaf); + auto node = nodeStore->createNewInnerNode(1, {leaf->key()}); EXPECT_IS_PTR_TYPE(DataInnerNode, node.get()); } TEST_F(DataNodeStoreTest, LeafNodeIsRecognizedAfterStoreAndLoad) { - Key key = nodeStore->createNewLeafNode()->key(); + Key key = nodeStore->createNewLeafNode(Data(0))->key(); auto loaded_node = nodeStore->load(key).value(); @@ -57,8 +57,8 @@ TEST_F(DataNodeStoreTest, LeafNodeIsRecognizedAfterStoreAndLoad) { } TEST_F(DataNodeStoreTest, InnerNodeWithDepth1IsRecognizedAfterStoreAndLoad) { - auto leaf = nodeStore->createNewLeafNode(); - Key key = nodeStore->createNewInnerNode(*leaf)->key(); + auto leaf = nodeStore->createNewLeafNode(Data(0)); + Key key = nodeStore->createNewInnerNode(1, {leaf->key()})->key(); auto loaded_node = nodeStore->load(key).value(); @@ -66,9 +66,9 @@ TEST_F(DataNodeStoreTest, InnerNodeWithDepth1IsRecognizedAfterStoreAndLoad) { } TEST_F(DataNodeStoreTest, InnerNodeWithDepth2IsRecognizedAfterStoreAndLoad) { - auto leaf = nodeStore->createNewLeafNode(); - auto inner = nodeStore->createNewInnerNode(*leaf); - Key key = nodeStore->createNewInnerNode(*inner)->key(); + auto leaf = nodeStore->createNewLeafNode(Data(0)); + auto inner = nodeStore->createNewInnerNode(1, {leaf->key()}); + Key key = nodeStore->createNewInnerNode(2, {inner->key()})->key(); auto loaded_node = nodeStore->load(key).value(); @@ -89,19 +89,19 @@ TEST_F(DataNodeStoreTest, DataNodeCrashesOnLoadIfDepthIsTooHigh) { } TEST_F(DataNodeStoreTest, CreatedInnerNodeIsInitialized) { - auto leaf = nodeStore->createNewLeafNode(); - auto node = nodeStore->createNewInnerNode(*leaf); + auto leaf = nodeStore->createNewLeafNode(Data(0)); + auto node = nodeStore->createNewInnerNode(1, {leaf->key()}); EXPECT_EQ(1u, node->numChildren()); EXPECT_EQ(leaf->key(), node->getChild(0)->key()); } TEST_F(DataNodeStoreTest, CreatedLeafNodeIsInitialized) { - auto leaf = nodeStore->createNewLeafNode(); + auto leaf = nodeStore->createNewLeafNode(Data(0)); EXPECT_EQ(0u, leaf->numBytes()); } TEST_F(DataNodeStoreTest, NodeIsNotLoadableAfterDeleting) { - auto nodekey = nodeStore->createNewLeafNode()->key(); + auto nodekey = nodeStore->createNewLeafNode(Data(0))->key(); auto node = nodeStore->load(nodekey); EXPECT_NE(none, node); nodeStore->remove(std::move(*node)); @@ -113,38 +113,38 @@ TEST_F(DataNodeStoreTest, NumNodesIsCorrectOnEmptyNodestore) { } TEST_F(DataNodeStoreTest, NumNodesIsCorrectAfterAddingOneLeafNode) { - nodeStore->createNewLeafNode(); + nodeStore->createNewLeafNode(Data(0)); EXPECT_EQ(1u, nodeStore->numNodes()); } TEST_F(DataNodeStoreTest, NumNodesIsCorrectAfterRemovingTheLastNode) { - auto leaf = nodeStore->createNewLeafNode(); + auto leaf = nodeStore->createNewLeafNode(Data(0)); nodeStore->remove(std::move(leaf)); EXPECT_EQ(0u, nodeStore->numNodes()); } TEST_F(DataNodeStoreTest, NumNodesIsCorrectAfterAddingTwoNodes) { - auto leaf = nodeStore->createNewLeafNode(); - auto node = nodeStore->createNewInnerNode(*leaf); + auto leaf = nodeStore->createNewLeafNode(Data(0)); + auto node = nodeStore->createNewInnerNode(1, {leaf->key()}); EXPECT_EQ(2u, nodeStore->numNodes()); } TEST_F(DataNodeStoreTest, NumNodesIsCorrectAfterRemovingANode) { - auto leaf = nodeStore->createNewLeafNode(); - auto node = nodeStore->createNewInnerNode(*leaf); + auto leaf = nodeStore->createNewLeafNode(Data(0)); + auto node = nodeStore->createNewInnerNode(1, {leaf->key()}); nodeStore->remove(std::move(node)); EXPECT_EQ(1u, nodeStore->numNodes()); } TEST_F(DataNodeStoreTest, PhysicalBlockSize_Leaf) { - auto leaf = nodeStore->createNewLeafNode(); + auto leaf = nodeStore->createNewLeafNode(Data(0)); auto block = blockStore->load(leaf->key()).value(); EXPECT_EQ(BLOCKSIZE_BYTES, block->size()); } TEST_F(DataNodeStoreTest, PhysicalBlockSize_Inner) { - auto leaf = nodeStore->createNewLeafNode(); - auto node = nodeStore->createNewInnerNode(*leaf); + auto leaf = nodeStore->createNewLeafNode(Data(0)); + auto node = nodeStore->createNewInnerNode(1, {leaf->key()}); auto block = blockStore->load(node->key()).value(); EXPECT_EQ(BLOCKSIZE_BYTES, block->size()); } \ No newline at end of file diff --git a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_Performance.cpp b/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_Performance.cpp index 022f77ab..999d3665 100644 --- a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_Performance.cpp +++ b/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_Performance.cpp @@ -30,6 +30,9 @@ TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Twolevel_DeleteByTree) 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()); + EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->removedBlocks().size()); + EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Twolevel_DeleteByKey) { @@ -40,6 +43,9 @@ TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Twolevel_DeleteByKey) EXPECT_EQ(1u, blockStore->loadedBlocks().size()); EXPECT_EQ(0u, blockStore->createdBlocks()); + EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->removedBlocks().size()); + EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByTree) { @@ -51,6 +57,9 @@ TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByTre EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); EXPECT_EQ(0u, blockStore->createdBlocks()); + EXPECT_EQ(1u + maxChildrenPerInnerNode + maxChildrenPerInnerNode*maxChildrenPerInnerNode, blockStore->removedBlocks().size()); + EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByKey) { @@ -61,6 +70,9 @@ TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByKey EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); EXPECT_EQ(0u, blockStore->createdBlocks()); + EXPECT_EQ(1u + maxChildrenPerInnerNode + maxChildrenPerInnerNode*maxChildrenPerInnerNode, blockStore->removedBlocks().size()); + EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_All) { @@ -72,6 +84,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_All) { 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()); + EXPECT_EQ(0u, blockStore->removedBlocks().size()); + EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_Some) { @@ -83,6 +98,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_Some) { 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()); + EXPECT_EQ(0u, blockStore->removedBlocks().size()); + EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_All) { @@ -94,6 +112,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_All) { 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()); + EXPECT_EQ(0u, blockStore->removedBlocks().size()); + EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InOneInner) { @@ -105,6 +126,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InOneInner) { 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()); + EXPECT_EQ(0u, blockStore->removedBlocks().size()); + EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InTwoInner) { @@ -116,6 +140,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InTwoInner) { 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()); + EXPECT_EQ(0u, blockStore->removedBlocks().size()); + EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_WholeInner) { @@ -127,6 +154,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_WholeInner) { 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()); + EXPECT_EQ(0u, blockStore->removedBlocks().size()); + EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingInside) { @@ -138,6 +168,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingInside) { EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old child (for growing it) EXPECT_EQ(2u, blockStore->createdBlocks()); + EXPECT_EQ(0u, blockStore->removedBlocks().size()); + EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // add children to inner node + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_TwoLevel) { @@ -149,6 +182,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_TwoL EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it EXPECT_EQ(3u, blockStore->createdBlocks()); + EXPECT_EQ(0u, blockStore->removedBlocks().size()); + EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // add child to inner node + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_ThreeLevel) { @@ -160,6 +196,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_Thre 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 + EXPECT_EQ(0u, blockStore->removedBlocks().size()); + EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // add children to existing inner node + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingAtBeginOfChild) { @@ -171,6 +210,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingAtBeginOfChi 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 + EXPECT_EQ(0u, blockStore->removedBlocks().size()); + EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // add children to existing inner node + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInOldDepth) { @@ -182,6 +224,23 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInOldDe EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it EXPECT_EQ(2 + maxChildrenPerInnerNode, blockStore->createdBlocks()); // 2x new inner node + leaves + EXPECT_EQ(0u, blockStore->removedBlocks().size()); + EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // Add children to existing inner node + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); +} + +TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInOldDepth_ResizeLastLeaf) { + auto key = CreateInner({CreateLeaf(), CreateLeafWithSize(5)})->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 + EXPECT_EQ(0u, blockStore->removedBlocks().size()); + EXPECT_EQ(2u, blockStore->distinctWrittenBlocks().size()); // Resize last leaf and add children to existing inner node + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInNewDepth) { @@ -193,4 +252,21 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInNewDe EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it EXPECT_EQ(2 + maxChildrenPerInnerNode, blockStore->createdBlocks()); // 2x new inner node + leaves + EXPECT_EQ(0u, blockStore->removedBlocks().size()); + EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // Add children to existing inner node + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); +} + +TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInNewDepth_ResizeLastLeaf) { + auto key = CreateInner({CreateLeaf(), CreateLeafWithSize(5)})->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 + EXPECT_EQ(0u, blockStore->removedBlocks().size()); + EXPECT_EQ(2u, blockStore->distinctWrittenBlocks().size()); // Resize last leaf and add children to existing inner node + EXPECT_EQ(0u, blockStore->resizedBlocks().size()); } diff --git a/test/blobstore/implementations/onblocks/datatreestore/impl/GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest.cpp b/test/blobstore/implementations/onblocks/datatreestore/impl/GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest.cpp index 11445157..d2bf827a 100644 --- a/test/blobstore/implementations/onblocks/datatreestore/impl/GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest.cpp +++ b/test/blobstore/implementations/onblocks/datatreestore/impl/GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest.cpp @@ -16,6 +16,7 @@ using blobstore::onblocks::datanodestore::DataNode; using blobstore::onblocks::datanodestore::DataInnerNode; using blockstore::testfake::FakeBlockStore; using blockstore::Key; +using cpputils::Data; using namespace blobstore::onblocks::datatreestore::algorithms; class GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest: public DataTreeTest { @@ -55,7 +56,7 @@ public: }; TEST_F(GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest, Leaf) { - auto leaf = nodeStore->createNewLeafNode(); + auto leaf = nodeStore->createNewLeafNode(Data(0)); auto result = GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNull(nodeStore, leaf.get()); EXPECT_EQ(nullptr, result.get()); } diff --git a/test/blobstore/implementations/onblocks/datatreestore/testutils/DataTreeTest.cpp b/test/blobstore/implementations/onblocks/datatreestore/testutils/DataTreeTest.cpp index c12bb071..0d014b57 100644 --- a/test/blobstore/implementations/onblocks/datatreestore/testutils/DataTreeTest.cpp +++ b/test/blobstore/implementations/onblocks/datatreestore/testutils/DataTreeTest.cpp @@ -17,6 +17,7 @@ using std::initializer_list; using std::vector; using boost::none; using cpputils::dynamic_pointer_move; +using cpputils::Data; constexpr uint32_t DataTreeTest::BLOCKSIZE_BYTES; @@ -29,7 +30,7 @@ DataTreeTest::DataTreeTest() } unique_ref DataTreeTest::CreateLeaf() { - return nodeStore->createNewLeafNode(); + return nodeStore->createNewLeafNode(Data(nodeStore->layout().maxBytesPerLeaf())); } unique_ref DataTreeTest::CreateInner(initializer_list> children) { @@ -44,10 +45,13 @@ unique_ref DataTreeTest::CreateInner(initializer_list DataTreeTest::CreateInner(vector children) { ASSERT(children.size() >= 1, "An inner node must have at least one child"); - auto node = nodeStore->createNewInnerNode(**children.begin()); - for(auto child = children.begin()+1; child != children.end(); ++child) { - node->addChild(**child); + vector childrenKeys; + childrenKeys.reserve(children.size()); + for (const DataNode *child : children) { + ASSERT(child->depth() == (*children.begin())->depth(), "Children with different depth"); + childrenKeys.push_back(child->key()); } + auto node = nodeStore->createNewInnerNode((*children.begin())->depth()+1, childrenKeys); return node; }