Minimize number of Block::write() calls when creating new nodes in a traversal. Also add test cases for it.

This commit is contained in:
Sebastian Messmer 2016-07-15 12:48:20 +02:00
parent d626349802
commit c428d5642a
19 changed files with 245 additions and 145 deletions

View File

@ -3,10 +3,12 @@
#include <cpp-utils/assert/assert.h>
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> DataInnerNode::InitializeNewNode(unique_ref<Block> 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<DataInnerNode>(std::move(node));
result->ChildrenBegin()->setKey(first_child.key());
return result;
unique_ref<DataInnerNode> DataInnerNode::InitializeNewNode(unique_ref<Block> block, const DataNodeLayout &layout, uint8_t depth, const vector<Key> &children) {
ASSERT(children.size() >= 1, "An inner node must have at least one child");
Data data = _serializeChildren(children);
return make_unique_ref<DataInnerNode>(DataNodeView::initialize(std::move(block), layout, DataNode::FORMAT_VERSION_HEADER, depth, children.size(), std::move(data)));
}
unique_ref<DataInnerNode> DataInnerNode::CreateNewNode(BlockStore *blockStore, const DataNodeLayout &layout, uint8_t depth, const vector<Key> &children) {
ASSERT(children.size() >= 1, "An inner node must have at least one child");
Data data = _serializeChildren(children);
return make_unique_ref<DataInnerNode>(DataNodeView::create(blockStore, layout, DataNode::FORMAT_VERSION_HEADER, depth, children.size(), std::move(data)));
}
Data DataInnerNode::_serializeChildren(const vector<Key> &children) {
Data data(sizeof(ChildEntry) * children.size());
uint32_t i = 0;
for (const Key &child : children) {
reinterpret_cast<ChildEntry*>(data.data())[i++].setKey(child);
}
return data;
}
uint32_t DataInnerNode::numChildren() const {

View File

@ -11,7 +11,8 @@ namespace datanodestore {
class DataInnerNode final: public DataNode {
public:
static cpputils::unique_ref<DataInnerNode> InitializeNewNode(cpputils::unique_ref<blockstore::Block> block, const DataNode &first_child_key);
static cpputils::unique_ref<DataInnerNode> InitializeNewNode(cpputils::unique_ref<blockstore::Block> block, const DataNodeLayout &layout, uint8_t depth, const std::vector<blockstore::Key> &children);
static cpputils::unique_ref<DataInnerNode> CreateNewNode(blockstore::BlockStore *blockStore, const DataNodeLayout &layout, uint8_t depth, const std::vector<blockstore::Key> &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<blockstore::Key> &children);
DISALLOW_COPY_AND_ASSIGN(DataInnerNode);
};

View File

@ -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> DataLeafNode::InitializeNewNode(unique_ref<Block> 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<DataLeafNode>(std::move(node));
unique_ref<DataLeafNode> 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<DataLeafNode>(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 {

View File

@ -11,7 +11,8 @@ class DataInnerNode;
class DataLeafNode final: public DataNode {
public:
static cpputils::unique_ref<DataLeafNode> InitializeNewNode(cpputils::unique_ref<blockstore::Block> block);
//static cpputils::unique_ref<DataLeafNode> InitializeNewNode(cpputils::unique_ref<blockstore::Block> block);
static cpputils::unique_ref<DataLeafNode> CreateNewNode(blockstore::BlockStore *blockStore, const DataNodeLayout &layout, cpputils::Data data);
DataLeafNode(DataNodeView block);
~DataLeafNode();

View File

@ -39,11 +39,11 @@ uint8_t DataNode::depth() const {
return _node.Depth();
}
unique_ref<DataInnerNode> DataNode::convertToNewInnerNode(unique_ref<DataNode> node, const DataNode &first_child) {
unique_ref<DataInnerNode> DataNode::convertToNewInnerNode(unique_ref<DataNode> 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 {

View File

@ -19,7 +19,7 @@ public:
uint8_t depth() const;
static cpputils::unique_ref<DataInnerNode> convertToNewInnerNode(cpputils::unique_ref<DataNode> node, const DataNode &first_child);
static cpputils::unique_ref<DataInnerNode> convertToNewInnerNode(cpputils::unique_ref<DataNode> node, const DataNodeLayout &layout, const DataNode &first_child);
void flush() const;

View File

@ -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<DataNode> DataNodeStore::load(unique_ref<Block> block) {
}
}
unique_ref<DataInnerNode> 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<DataInnerNode> DataNodeStore::createNewInnerNode(uint8_t depth, const vector<Key> &children) {
ASSERT(children.size() >= 1, "Inner node must have at least one child");
return DataInnerNode::CreateNewNode(_blockstore.get(), _layout, depth, children);
}
unique_ref<DataLeafNode> 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<DataLeafNode> DataNodeStore::createNewLeafNode(Data data) {
return DataLeafNode::CreateNewNode(_blockstore.get(), _layout, std::move(data));
}
optional<unique_ref<DataNode>> DataNodeStore::load(const Key &key) {

View File

@ -30,8 +30,8 @@ public:
boost::optional<cpputils::unique_ref<DataNode>> load(const blockstore::Key &key);
cpputils::unique_ref<DataLeafNode> createNewLeafNode();
cpputils::unique_ref<DataInnerNode> createNewInnerNode(const DataNode &first_child);
cpputils::unique_ref<DataLeafNode> createNewLeafNode(cpputils::Data data);
cpputils::unique_ref<DataInnerNode> createNewInnerNode(uint8_t depth, const std::vector<blockstore::Key> &children);
cpputils::unique_ref<DataNode> createNewNodeAsCopyFrom(const DataNode &source);

View File

@ -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<blockstore::Block> 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<blockstore::Block> _block;
DISALLOW_COPY_AND_ASSIGN(DataNodeView);

View File

@ -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 {

View File

@ -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<unique_ref<DataTree>> DataTreeStore::load(const blockstore::Key &key) {
}
unique_ref<DataTree> DataTreeStore::createNewTree() {
auto newleaf = _nodeStore->createNewLeafNode();
auto newleaf = _nodeStore->createNewLeafNode(Data(0));
return make_unique_ref<DataTree>(_nodeStore.get(), std::move(newleaf));
}

View File

@ -57,7 +57,7 @@ namespace blobstore {
unique_ref<DataInnerNode> LeafTraverser::_increaseTreeDepth(unique_ref<DataNode> 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<void (uint32_t index, DataLeafNode* leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> onBacktrackFromSubtree) {
@ -68,7 +68,7 @@ namespace blobstore {
DataLeafNode *leaf = dynamic_cast<DataLeafNode*>(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<unique_ref<DataNode>> children;
vector<blockstore::Key> 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());

View File

@ -81,22 +81,31 @@ namespace blockstore {
return _createdBlocks;
}
const std::vector<Key> loadedBlocks() const {
const std::vector<Key> &loadedBlocks() const {
return _loadedBlocks;
}
const std::vector<Key> removedBlocks() const {
const std::vector<Key> &removedBlocks() const {
return _removedBlocks;
}
const std::vector<Key> resizedBlocks() const {
const std::vector<Key> &resizedBlocks() const {
return _resizedBlocks;
}
const std::vector<Key> writtenBlocks() const {
const std::vector<Key> &writtenBlocks() const {
return _writtenBlocks;
}
std::vector<Key> distinctWrittenBlocks() const {
std::vector<Key> 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<std::mutex> lock(_mutex);

View File

@ -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<DataNodeStore>(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<DataInnerNode> 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<DataInnerNode> CreateAndLoadNewInnerNode(const DataNode &firstChild) {
@ -59,23 +60,21 @@ public:
return LoadInnerNode(key);
}
unique_ref<DataInnerNode> CreateNewInnerNode(const DataNode &firstChild, const DataNode &secondChild) {
auto node = nodeStore->createNewInnerNode(firstChild);
node->addChild(secondChild);
return node;
unique_ref<DataInnerNode> CreateNewInnerNode(uint8_t depth, const vector<blockstore::Key> &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<blockstore::Key> &children) {
return CreateNewInnerNode(depth, children)->key();
}
unique_ref<DataInnerNode> CreateAndLoadNewInnerNode(const DataNode &firstChild, const DataNode &secondChild) {
auto key = CreateNewInnerNodeReturnKey(firstChild, secondChild);
unique_ref<DataInnerNode> CreateAndLoadNewInnerNode(uint8_t depth, const vector<blockstore::Key> &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<DataInnerNode> converted = DataNode::convertToNewInnerNode(std::move(node), *child);
auto child = nodeStore->createNewLeafNode(Data(0));
unique_ref<DataInnerNode> 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<DataInnerNode> converted = DataNode::convertToNewInnerNode(std::move(node), *child);
unique_ref<DataInnerNode> converted = DataNode::convertToNewInnerNode(std::move(node), nodeStore->layout(), *child);
EXPECT_EQ(1u, converted->numChildren());
EXPECT_EQ(child->key(), converted->getChild(0)->key());

View File

@ -45,7 +45,7 @@ public:
nodeStore(make_unique_ref<DataNodeStore>(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<DataInnerNode> converted = DataNode::convertToNewInnerNode(std::move(leaf), *child);
auto child = nodeStore->createNewLeafNode(Data(0));
unique_ref<DataInnerNode> 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<unsigned int> {
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<DataInnerNode> converted = DataNode::convertToNewInnerNode(std::move(leaf), *child);
unique_ref<DataInnerNode> 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);

View File

@ -37,19 +37,19 @@ constexpr uint32_t DataNodeStoreTest::BLOCKSIZE_BYTES;
#define EXPECT_IS_PTR_TYPE(Type, ptr) EXPECT_NE(nullptr, dynamic_cast<Type*>(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());
}

View File

@ -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());
}

View File

@ -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());
}

View File

@ -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<DataLeafNode> DataTreeTest::CreateLeaf() {
return nodeStore->createNewLeafNode();
return nodeStore->createNewLeafNode(Data(nodeStore->layout().maxBytesPerLeaf()));
}
unique_ref<DataInnerNode> DataTreeTest::CreateInner(initializer_list<unique_ref<DataNode>> children) {
@ -44,10 +45,13 @@ unique_ref<DataInnerNode> DataTreeTest::CreateInner(initializer_list<const DataN
unique_ref<DataInnerNode> DataTreeTest::CreateInner(vector<const DataNode*> 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<Key> 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;
}