Make block size configureable in DataNodeStore -> this greatly speeds up our test cases, because they can use smaller blocks, which means less children per inner node

This commit is contained in:
Sebastian Messmer 2015-02-25 22:30:48 +01:00
parent 100268930e
commit c9ce0d55cf
22 changed files with 246 additions and 156 deletions

View File

@ -15,8 +15,10 @@ namespace onblocks {
using datanodestore::DataNodeStore;
constexpr size_t BlobStoreOnBlocks::BLOCKSIZE_BYTES;
BlobStoreOnBlocks::BlobStoreOnBlocks(unique_ptr<BlockStore> blockStore)
: _nodes(make_unique<DataNodeStore>(std::move(blockStore))) {
: _nodes(make_unique<DataNodeStore>(std::move(blockStore), BLOCKSIZE_BYTES)) {
}
BlobStoreOnBlocks::~BlobStoreOnBlocks() {

View File

@ -13,7 +13,7 @@ class DataNodeStore;
class BlobStoreOnBlocks: public BlobStore {
public:
static constexpr size_t BLOCKSIZE = 4096;
static constexpr size_t BLOCKSIZE_BYTES = 4096;
BlobStoreOnBlocks(std::unique_ptr<blockstore::BlockStore> blockStore);
virtual ~BlobStoreOnBlocks();

View File

@ -11,8 +11,6 @@ namespace blobstore {
namespace onblocks {
namespace datanodestore {
constexpr uint32_t DataInnerNode::MAX_STORED_CHILDREN;
DataInnerNode::DataInnerNode(DataNodeView view)
: DataNode(std::move(view)) {
assert(depth() > 0);
@ -72,7 +70,7 @@ const DataInnerNode::ChildEntry *DataInnerNode::getChild(unsigned int index) con
}
void DataInnerNode::addChild(const DataNode &child) {
assert(numChildren() < DataInnerNode::MAX_STORED_CHILDREN);
assert(numChildren() < maxStoreableChildren());
assert(child.depth() == depth()-1);
*node().Size() += 1;
LastChild()->setKey(child.key());
@ -83,6 +81,10 @@ void DataInnerNode::removeLastChild() {
*node().Size() -= 1;
}
uint32_t DataInnerNode::maxStoreableChildren() const {
return node().layout().maxChildrenPerInnerNode();
}
}
}
}

View File

@ -3,6 +3,7 @@
#define BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATANODESTORE_DATAINNERNODE_H_
#include "DataNode.h"
#include "DataInnerNode_ChildEntry.h"
namespace blobstore {
namespace onblocks {
@ -15,21 +16,9 @@ public:
DataInnerNode(DataNodeView block);
virtual ~DataInnerNode();
struct ChildEntry {
public:
blockstore::Key key() const {
return blockstore::Key::FromBinary(_keydata);
}
private:
void setKey(const blockstore::Key &key) {
key.ToBinary(_keydata);
}
friend class DataInnerNode;
uint8_t _keydata[blockstore::Key::KEYLENGTH_BINARY];
DISALLOW_COPY_AND_ASSIGN(ChildEntry);
};
using ChildEntry = DataInnerNode_ChildEntry;
static constexpr uint32_t MAX_STORED_CHILDREN = DataNodeView::DATASIZE_BYTES / sizeof(ChildEntry);
uint32_t maxStoreableChildren() const;
uint8_t depth() const;

View File

@ -0,0 +1,29 @@
#pragma once
#ifndef MESSMER_BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATANODESTORE_DATAINNERNODE_CHILDENTRY_H_
#define MESSMER_BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATANODESTORE_DATAINNERNODE_CHILDENTRY_H_
#include <messmer/cpp-utils/macros.h>
namespace blobstore{
namespace onblocks{
namespace datanodestore{
struct DataInnerNode_ChildEntry {
public:
blockstore::Key key() const {
return blockstore::Key::FromBinary(_keydata);
}
private:
void setKey(const blockstore::Key &key) {
key.ToBinary(_keydata);
}
friend class DataInnerNode;
uint8_t _keydata[blockstore::Key::KEYLENGTH_BINARY];
DISALLOW_COPY_AND_ASSIGN(DataInnerNode_ChildEntry);
};
}
}
}
#endif

View File

@ -11,12 +11,10 @@ namespace blobstore {
namespace onblocks {
namespace datanodestore {
constexpr uint32_t DataLeafNode::MAX_STORED_BYTES;
DataLeafNode::DataLeafNode(DataNodeView view)
: DataNode(std::move(view)) {
assert(*node().Depth() == 0);
assert(numBytes() <= MAX_STORED_BYTES);
assert(numBytes() <= maxStoreableBytes());
}
DataLeafNode::~DataLeafNode() {
@ -43,7 +41,7 @@ uint32_t DataLeafNode::numBytes() const {
}
void DataLeafNode::resize(uint32_t new_size) {
assert(new_size <= MAX_STORED_BYTES);
assert(new_size <= maxStoreableBytes());
uint32_t old_size = *node().Size();
if (new_size < old_size) {
fillDataWithZeroesFromTo(new_size, old_size);
@ -55,6 +53,10 @@ void DataLeafNode::fillDataWithZeroesFromTo(off_t begin, off_t end) {
std::memset(node().DataBegin<uint8_t>()+begin, 0, end-begin);
}
uint32_t DataLeafNode::maxStoreableBytes() const {
return node().layout().maxBytesPerLeaf();
}
}
}
}

View File

@ -16,7 +16,7 @@ public:
DataLeafNode(DataNodeView block);
virtual ~DataLeafNode();
static constexpr uint32_t MAX_STORED_BYTES = DataNodeView::DATASIZE_BYTES;
uint32_t maxStoreableBytes() const;
void *data();
const void *data() const;

View File

@ -17,14 +17,15 @@ namespace blobstore {
namespace onblocks {
namespace datanodestore {
DataNodeStore::DataNodeStore(unique_ptr<BlockStore> blockstore)
: _blockstore(std::move(blockstore)) {
DataNodeStore::DataNodeStore(unique_ptr<BlockStore> blockstore, uint32_t blocksizeBytes)
: _blockstore(std::move(blockstore)), _layout(blocksizeBytes) {
}
DataNodeStore::~DataNodeStore() {
}
unique_ptr<DataNode> DataNodeStore::load(unique_ptr<Block> block) {
assert(block->size() == _layout.blocksizeBytes());
DataNodeView node(std::move(block));
if (*node.Depth() == 0) {
@ -37,12 +38,13 @@ unique_ptr<DataNode> DataNodeStore::load(unique_ptr<Block> block) {
}
unique_ptr<DataInnerNode> DataNodeStore::createNewInnerNode(const DataNode &first_child) {
auto block = _blockstore->create(DataNodeView::BLOCKSIZE_BYTES);
assert(first_child.node().layout().blocksizeBytes() == _layout.blocksizeBytes()); // This might be violated if source is from a different DataNodeStore
auto block = _blockstore->create(_layout.blocksizeBytes());
return DataInnerNode::InitializeNewNode(std::move(block), first_child);
}
unique_ptr<DataLeafNode> DataNodeStore::createNewLeafNode() {
auto block = _blockstore->create(DataNodeView::BLOCKSIZE_BYTES);
auto block = _blockstore->create(_layout.blocksizeBytes());
return DataLeafNode::InitializeNewNode(std::move(block));
}
@ -55,11 +57,14 @@ unique_ptr<DataNode> DataNodeStore::load(const Key &key) {
}
unique_ptr<DataNode> DataNodeStore::createNewNodeAsCopyFrom(const DataNode &source) {
assert(source.node().layout().blocksizeBytes() == _layout.blocksizeBytes()); // This might be violated if source is from a different DataNodeStore
auto newBlock = blockstore::utils::copyToNewBlock(_blockstore.get(), source.node().block());
return load(std::move(newBlock));
}
unique_ptr<DataNode> DataNodeStore::overwriteNodeWith(unique_ptr<DataNode> target, const DataNode &source) {
assert(target->node().layout().blocksizeBytes() == _layout.blocksizeBytes());
assert(source.node().layout().blocksizeBytes() == _layout.blocksizeBytes());
Key key = target->key();
{
auto targetBlock = target->node().releaseBlock();
@ -80,15 +85,19 @@ uint64_t DataNodeStore::numNodes() const {
}
void DataNodeStore::removeSubtree(unique_ptr<DataNode> node) {
DataInnerNode *inner = dynamic_cast<DataInnerNode*>(node.get());
if (inner != nullptr) {
for (int i = 0; i < inner->numChildren(); ++i) {
auto child = load(inner->getChild(i)->key());
removeSubtree(std::move(child));
}
}
remove(std::move(node));
}
DataInnerNode *inner = dynamic_cast<DataInnerNode*>(node.get());
if (inner != nullptr) {
for (int i = 0; i < inner->numChildren(); ++i) {
auto child = load(inner->getChild(i)->key());
removeSubtree(std::move(child));
}
}
remove(std::move(node));
}
DataNodeLayout DataNodeStore::layout() const {
return _layout;
}
}
}

View File

@ -4,6 +4,7 @@
#include <memory>
#include "messmer/cpp-utils/macros.h"
#include "DataNodeView.h"
namespace blockstore{
class Block;
@ -20,11 +21,13 @@ class DataInnerNode;
class DataNodeStore {
public:
DataNodeStore(std::unique_ptr<blockstore::BlockStore> blockstore);
DataNodeStore(std::unique_ptr<blockstore::BlockStore> blockstore, uint32_t blocksizeBytes);
virtual ~DataNodeStore();
static constexpr uint8_t MAX_DEPTH = 10;
DataNodeLayout layout() const;
std::unique_ptr<DataNode> load(const blockstore::Key &key);
std::unique_ptr<DataLeafNode> createNewLeafNode();
@ -45,6 +48,7 @@ private:
std::unique_ptr<DataNode> load(std::unique_ptr<blockstore::Block> block);
std::unique_ptr<blockstore::BlockStore> _blockstore;
const DataNodeLayout _layout;
DISALLOW_COPY_AND_ASSIGN(DataNodeStore);
};

View File

@ -4,39 +4,67 @@
#include "messmer/blockstore/interface/Block.h"
#include "../BlobStoreOnBlocks.h"
#include "DataInnerNode_ChildEntry.h"
#include "messmer/cpp-utils/macros.h"
#include <memory>
#include <cassert>
#include <stdexcept>
namespace blobstore {
namespace onblocks {
namespace datanodestore {
//TODO Move DataNodeLayout into own file
class DataNodeLayout {
public:
constexpr DataNodeLayout(uint32_t blocksizeBytes)
:_blocksizeBytes(
(HEADERSIZE_BYTES + 2*sizeof(DataInnerNode_ChildEntry) <= blocksizeBytes)
? blocksizeBytes
: throw std::logic_error("Blocksize too small, not enough space to store two children in an inner node")) {
}
//Total size of the header
static constexpr uint32_t HEADERSIZE_BYTES = 8;
//Where in the header is the depth field
static constexpr uint32_t DEPTH_OFFSET_BYTES = 0;
//Where in the header is the size field (for inner nodes: number of children, for leafs: content data size)
static constexpr uint32_t SIZE_OFFSET_BYTES = 4;
//Size of a block (header + data region)
constexpr uint32_t blocksizeBytes() const {
return _blocksizeBytes;
}
//Number of bytes in the data region of a node
constexpr uint32_t datasizeBytes() const {
return _blocksizeBytes - HEADERSIZE_BYTES;
}
//Maximum number of children an inner node can store
constexpr uint32_t maxChildrenPerInnerNode() const {
return datasizeBytes() / sizeof(DataInnerNode_ChildEntry);
}
//Maximum number of bytes a leaf can store
constexpr uint32_t maxBytesPerLeaf() const {
return datasizeBytes();
}
private:
uint32_t _blocksizeBytes;
};
class DataNodeView {
public:
DataNodeView(std::unique_ptr<blockstore::Block> block): _block(std::move(block)) {
assert(_block->size() == BLOCKSIZE_BYTES);
}
virtual ~DataNodeView() {}
DataNodeView(DataNodeView &&rhs) = default;
//Total size of the header
static constexpr unsigned int HEADERSIZE_BYTES = 8;
//Where in the header is the depth field
static constexpr unsigned int DEPTH_OFFSET_BYTES = 0;
//Where in the header is the size field (for inner nodes: number of children, for leafs: content data size)
static constexpr unsigned int SIZE_OFFSET_BYTES = 4;
//How big is one blob in total (header + data)
static constexpr unsigned int BLOCKSIZE_BYTES = BlobStoreOnBlocks::BLOCKSIZE;
//How much space is there for data
static constexpr unsigned int DATASIZE_BYTES = BLOCKSIZE_BYTES - HEADERSIZE_BYTES;
const uint8_t *Depth() const {
return GetOffset<DEPTH_OFFSET_BYTES, uint8_t>();
return GetOffset<DataNodeLayout::DEPTH_OFFSET_BYTES, uint8_t>();
}
uint8_t *Depth() {
@ -44,7 +72,7 @@ public:
}
const uint32_t *Size() const {
return GetOffset<SIZE_OFFSET_BYTES, uint32_t>();
return GetOffset<DataNodeLayout::SIZE_OFFSET_BYTES, uint32_t>();
}
uint32_t *Size() {
@ -53,7 +81,7 @@ public:
template<typename Entry>
const Entry *DataBegin() const {
return GetOffset<HEADERSIZE_BYTES, Entry>();
return GetOffset<DataNodeLayout::HEADERSIZE_BYTES, Entry>();
}
template<typename Entry>
@ -61,9 +89,13 @@ public:
return const_cast<Entry*>(const_cast<const DataNodeView*>(this)->DataBegin<Entry>());
}
DataNodeLayout layout() const {
return DataNodeLayout(_block->size());
}
template<typename Entry>
const Entry *DataEnd() const {
constexpr unsigned int NUM_ENTRIES = DATASIZE_BYTES / sizeof(Entry);
const unsigned int NUM_ENTRIES = layout().datasizeBytes() / sizeof(Entry);
return DataBegin<Entry>() + NUM_ENTRIES;
}

View File

@ -142,7 +142,7 @@ void DataTree::traverseLeaves(DataNode *root, uint32_t leafOffset, uint32_t begi
}
DataInnerNode *inner = dynamic_cast<DataInnerNode*>(root);
uint32_t leavesPerChild = intPow(DataInnerNode::MAX_STORED_CHILDREN, root->depth()-1);
uint32_t leavesPerChild = intPow(_nodeStore->layout().maxChildrenPerInnerNode(), root->depth()-1);
uint32_t beginChild = beginIndex/leavesPerChild;
uint32_t endChild = ceilDivision(endIndex, leavesPerChild);

View File

@ -49,7 +49,7 @@ optional_ownership_ptr<DataInnerNode> GetLowestRightBorderNodeWithMoreThanOneChi
optional_ownership_ptr<datanodestore::DataInnerNode> GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNull(datanodestore::DataNodeStore *nodeStore, datanodestore::DataNode *rootNode) {
return GetLowestInnerRightBorderNodeWithConditionOrNull(nodeStore, rootNode, [] (const datanodestore::DataInnerNode &node) {
return node.numChildren() < DataInnerNode::MAX_STORED_CHILDREN;
return node.numChildren() < node.maxStoreableChildren();
});
}

View File

@ -27,11 +27,13 @@ using std::make_unique;
class DataInnerNodeTest: public Test {
public:
static constexpr uint32_t BLOCKSIZE_BYTES = 1024;
DataInnerNodeTest() :
ZEROES(DataLeafNode::MAX_STORED_BYTES),
_blockStore(make_unique<FakeBlockStore>()),
blockStore(_blockStore.get()),
nodeStore(make_unique<DataNodeStore>(std::move(_blockStore))),
nodeStore(make_unique<DataNodeStore>(std::move(_blockStore), BLOCKSIZE_BYTES)),
ZEROES(nodeStore->layout().maxBytesPerLeaf()),
leaf(nodeStore->createNewLeafNode()),
node(nodeStore->createNewInnerNode(*leaf)) {
@ -93,21 +95,23 @@ public:
}
Key InitializeInnerNodeAddLeafReturnKey() {
auto node = DataInnerNode::InitializeNewNode(blockStore->create(DataNodeView::BLOCKSIZE_BYTES), *leaf);
auto node = DataInnerNode::InitializeNewNode(blockStore->create(BLOCKSIZE_BYTES), *leaf);
AddALeafTo(node.get());
return node->key();
}
Data ZEROES;
unique_ptr<BlockStore> _blockStore;
BlockStore *blockStore;
unique_ptr<DataNodeStore> nodeStore;
Data ZEROES;
unique_ptr<DataLeafNode> leaf;
unique_ptr<DataInnerNode> node;
};
constexpr uint32_t DataInnerNodeTest::BLOCKSIZE_BYTES;
TEST_F(DataInnerNodeTest, InitializesCorrectly) {
auto node = DataInnerNode::InitializeNewNode(blockStore->create(DataNodeView::BLOCKSIZE_BYTES), *leaf);
auto node = DataInnerNode::InitializeNewNode(blockStore->create(BLOCKSIZE_BYTES), *leaf);
EXPECT_EQ(1u, node->numChildren());
EXPECT_EQ(leaf->key(), node->getChild(0)->key());
@ -177,7 +181,7 @@ TEST_F(DataInnerNodeTest, ConvertToInternalNodeZeroesOutChildrenRegion) {
Key key = CreateNodeWithDataConvertItToInnerNodeAndReturnKey();
auto block = blockStore->load(key);
EXPECT_EQ(0, std::memcmp(ZEROES.data(), (uint8_t*)block->data()+DataNodeView::HEADERSIZE_BYTES+sizeof(DataInnerNode::ChildEntry), DataLeafNode::MAX_STORED_BYTES-sizeof(DataInnerNode::ChildEntry)));
EXPECT_EQ(0, std::memcmp(ZEROES.data(), (uint8_t*)block->data()+DataNodeLayout::HEADERSIZE_BYTES+sizeof(DataInnerNode::ChildEntry), nodeStore->layout().maxBytesPerLeaf()-sizeof(DataInnerNode::ChildEntry)));
}
TEST_F(DataInnerNodeTest, CopyingCreatesNewNode) {

View File

@ -33,17 +33,19 @@ using namespace blobstore::onblocks::datanodestore;
class DataLeafNodeTest: public Test {
public:
static constexpr uint32_t BLOCKSIZE_BYTES = 1024;
DataLeafNodeTest():
ZEROES(DataLeafNode::MAX_STORED_BYTES),
randomData(DataLeafNode::MAX_STORED_BYTES),
_blockStore(make_unique<FakeBlockStore>()),
blockStore(_blockStore.get()),
nodeStore(make_unique<DataNodeStore>(std::move(_blockStore))),
nodeStore(make_unique<DataNodeStore>(std::move(_blockStore), BLOCKSIZE_BYTES)),
randomData(nodeStore->layout().maxBytesPerLeaf()),
ZEROES(nodeStore->layout().maxBytesPerLeaf()),
leaf(nodeStore->createNewLeafNode()) {
ZEROES.FillWithZeroes();
DataBlockFixture dataFixture(DataLeafNode::MAX_STORED_BYTES);
DataBlockFixture dataFixture(nodeStore->layout().maxBytesPerLeaf());
std::memcpy(randomData.data(), dataFixture.data(), randomData.size());
}
@ -89,21 +91,23 @@ public:
}
Key InitializeLeafGrowAndReturnKey() {
auto leaf = DataLeafNode::InitializeNewNode(blockStore->create(DataNodeView::BLOCKSIZE_BYTES));
auto leaf = DataLeafNode::InitializeNewNode(blockStore->create(BLOCKSIZE_BYTES));
leaf->resize(5);
return leaf->key();
}
Data ZEROES;
Data randomData;
unique_ptr<BlockStore> _blockStore;
BlockStore *blockStore;
unique_ptr<DataNodeStore> nodeStore;
Data ZEROES;
Data randomData;
unique_ptr<DataLeafNode> leaf;
};
constexpr uint32_t DataLeafNodeTest::BLOCKSIZE_BYTES;
TEST_F(DataLeafNodeTest, InitializesCorrectly) {
auto leaf = DataLeafNode::InitializeNewNode(blockStore->create(DataNodeView::BLOCKSIZE_BYTES));
auto leaf = DataLeafNode::InitializeNewNode(blockStore->create(BLOCKSIZE_BYTES));
EXPECT_EQ(0u, leaf->numBytes());
}
@ -141,7 +145,7 @@ public:
return leaf->key();
}
};
INSTANTIATE_TEST_CASE_P(DataLeafNodeSizeTest, DataLeafNodeSizeTest, Values(0, 1, 5, 16, 32, 512, DataLeafNode::MAX_STORED_BYTES));
INSTANTIATE_TEST_CASE_P(DataLeafNodeSizeTest, DataLeafNodeSizeTest, Values(0, 1, 5, 16, 32, 512, DataNodeLayout(DataLeafNodeTest::BLOCKSIZE_BYTES).maxBytesPerLeaf()));
TEST_P(DataLeafNodeSizeTest, ResizeNode_ReadSizeImmediately) {
leaf->resize(GetParam());
@ -177,14 +181,14 @@ TEST_F(DataLeafNodeTest, DataGetsZeroFilledWhenShrinking) {
{
//At first, we expect there to be random data in the underlying data block
auto block = blockStore->load(key);
EXPECT_EQ(0, std::memcmp((char*)randomData.data()+smaller_size, (uint8_t*)block->data()+DataNodeView::HEADERSIZE_BYTES+smaller_size, 100));
EXPECT_EQ(0, std::memcmp((char*)randomData.data()+smaller_size, (uint8_t*)block->data()+DataNodeLayout::HEADERSIZE_BYTES+smaller_size, 100));
}
//After shrinking, we expect there to be zeroes in the underlying data block
ResizeLeaf(key, smaller_size);
{
auto block = blockStore->load(key);
EXPECT_EQ(0, std::memcmp(ZEROES.data(), (uint8_t*)block->data()+DataNodeView::HEADERSIZE_BYTES+smaller_size, 100));
EXPECT_EQ(0, std::memcmp(ZEROES.data(), (uint8_t*)block->data()+DataNodeLayout::HEADERSIZE_BYTES+smaller_size, 100));
}
}
@ -211,7 +215,7 @@ TEST_F(DataLeafNodeTest, ConvertToInternalNodeZeroesOutChildrenRegion) {
Key key = CreateLeafWithDataConvertItToInnerNodeAndReturnKey();
auto block = blockStore->load(key);
EXPECT_EQ(0, std::memcmp(ZEROES.data(), (uint8_t*)block->data()+DataNodeView::HEADERSIZE_BYTES+sizeof(DataInnerNode::ChildEntry), DataLeafNode::MAX_STORED_BYTES-sizeof(DataInnerNode::ChildEntry)));
EXPECT_EQ(0, std::memcmp(ZEROES.data(), (uint8_t*)block->data()+DataNodeLayout::HEADERSIZE_BYTES+sizeof(DataInnerNode::ChildEntry), nodeStore->layout().maxBytesPerLeaf()-sizeof(DataInnerNode::ChildEntry)));
}
TEST_F(DataLeafNodeTest, CopyingCreatesANewLeaf) {

View File

@ -22,11 +22,15 @@ using namespace blobstore::onblocks::datanodestore;
class DataNodeStoreTest: public Test {
public:
static constexpr uint32_t BLOCKSIZE_BYTES = 1024;
unique_ptr<BlockStore> _blockStore = make_unique<FakeBlockStore>();
BlockStore *blockStore = _blockStore.get();
unique_ptr<DataNodeStore> nodeStore = make_unique<DataNodeStore>(std::move(_blockStore));
unique_ptr<DataNodeStore> nodeStore = make_unique<DataNodeStore>(std::move(_blockStore), BLOCKSIZE_BYTES);
};
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) {
@ -69,7 +73,7 @@ TEST_F(DataNodeStoreTest, InnerNodeWithDepth2IsRecognizedAfterStoreAndLoad) {
}
TEST_F(DataNodeStoreTest, DataNodeCrashesOnLoadIfDepthIsTooHigh) {
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
auto block = blockStore->create(BLOCKSIZE_BYTES);
Key key = block->key();
{
DataNodeView view(std::move(block));

View File

@ -21,6 +21,9 @@ using namespace blobstore::onblocks::datanodestore;
class DataNodeViewTest: public Test {
public:
static constexpr uint32_t BLOCKSIZE_BYTES = 1024;
static constexpr uint32_t DATASIZE_BYTES = DataNodeLayout(DataNodeViewTest::BLOCKSIZE_BYTES).datasizeBytes();
unique_ptr<BlockStore> blockStore = make_unique<FakeBlockStore>();
};
@ -29,7 +32,7 @@ class DataNodeViewDepthTest: public DataNodeViewTest, public WithParamInterface<
INSTANTIATE_TEST_CASE_P(DataNodeViewDepthTest, DataNodeViewDepthTest, Values(0, 1, 3, 10, 100));
TEST_P(DataNodeViewDepthTest, DepthIsStored) {
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
auto block = blockStore->create(BLOCKSIZE_BYTES);
auto key = block->key();
{
DataNodeView view(std::move(block));
@ -44,7 +47,7 @@ class DataNodeViewSizeTest: public DataNodeViewTest, public WithParamInterface<u
INSTANTIATE_TEST_CASE_P(DataNodeViewSizeTest, DataNodeViewSizeTest, Values(0, 50, 64, 1024, 1024*1024*1024));
TEST_P(DataNodeViewSizeTest, SizeIsStored) {
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
auto block = blockStore->create(BLOCKSIZE_BYTES);
auto key = block->key();
{
DataNodeView view(std::move(block));
@ -55,8 +58,8 @@ TEST_P(DataNodeViewSizeTest, SizeIsStored) {
}
TEST_F(DataNodeViewTest, DataIsStored) {
DataBlockFixture randomData(DataNodeView::DATASIZE_BYTES);
auto block = blockStore->create(DataNodeView::BLOCKSIZE_BYTES);
DataBlockFixture randomData(DATASIZE_BYTES);
auto block = blockStore->create(BLOCKSIZE_BYTES);
auto key = block->key();
{
DataNodeView view(std::move(block));
@ -67,77 +70,77 @@ TEST_F(DataNodeViewTest, DataIsStored) {
}
TEST_F(DataNodeViewTest, HeaderAndBodyDontOverlap) {
DataBlockFixture randomData(DataNodeView::DATASIZE_BYTES);
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
DataBlockFixture randomData(DATASIZE_BYTES);
auto block = blockStore->create(BLOCKSIZE_BYTES);
auto key = block->key();
{
DataNodeView view(std::move(block));
*view.Depth() = 3;
*view.Size() = 1000000000u;
std::memcpy(view.DataBegin<uint8_t>(), randomData.data(), DataNodeView::DATASIZE_BYTES);
std::memcpy(view.DataBegin<uint8_t>(), randomData.data(), DATASIZE_BYTES);
}
DataNodeView view(blockStore->load(key));
EXPECT_EQ(3, *view.Depth());
EXPECT_EQ(1000000000u, *view.Size());
EXPECT_EQ(0, std::memcmp(view.DataBegin<uint8_t>(), randomData.data(), DataNodeView::DATASIZE_BYTES));
EXPECT_EQ(0, std::memcmp(view.DataBegin<uint8_t>(), randomData.data(), DATASIZE_BYTES));
}
TEST_F(DataNodeViewTest, DataBeginWorksWithOneByteEntries) {
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
auto block = blockStore->create(BLOCKSIZE_BYTES);
uint8_t *blockBegin = (uint8_t*)block->data();
DataNodeView view(std::move(block));
EXPECT_EQ(blockBegin+view.HEADERSIZE_BYTES, view.DataBegin<uint8_t>());
EXPECT_EQ(blockBegin+DataNodeLayout::HEADERSIZE_BYTES, view.DataBegin<uint8_t>());
}
TEST_F(DataNodeViewTest, DataBeginWorksWithEightByteEntries) {
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
auto block = blockStore->create(BLOCKSIZE_BYTES);
uint8_t *blockBegin = (uint8_t*)block->data();
DataNodeView view(std::move(block));
EXPECT_EQ(blockBegin+view.HEADERSIZE_BYTES, (uint8_t*)view.DataBegin<uint64_t>());
EXPECT_EQ(blockBegin+DataNodeLayout::HEADERSIZE_BYTES, (uint8_t*)view.DataBegin<uint64_t>());
}
TEST_F(DataNodeViewTest, DataEndWorksWithOneByteEntries) {
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
auto block = blockStore->create(BLOCKSIZE_BYTES);
uint8_t *blockBegin = (uint8_t*)block->data();
DataNodeView view(std::move(block));
EXPECT_EQ(blockBegin+view.BLOCKSIZE_BYTES, view.DataEnd<uint8_t>());
EXPECT_EQ(blockBegin+BLOCKSIZE_BYTES, view.DataEnd<uint8_t>());
}
TEST_F(DataNodeViewTest, DataEndWorksWithEightByteEntries) {
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
auto block = blockStore->create(BLOCKSIZE_BYTES);
uint8_t *blockBegin = (uint8_t*)block->data();
DataNodeView view(std::move(block));
EXPECT_EQ(blockBegin+view.BLOCKSIZE_BYTES, (uint8_t*)view.DataEnd<uint64_t>());
EXPECT_EQ(blockBegin+BLOCKSIZE_BYTES, (uint8_t*)view.DataEnd<uint64_t>());
}
struct SizedDataEntry {
uint8_t data[6];
};
BOOST_STATIC_ASSERT_MSG(DataNodeView::DATASIZE_BYTES % sizeof(SizedDataEntry) != 0,
BOOST_STATIC_ASSERT_MSG(DataNodeViewTest::DATASIZE_BYTES % sizeof(SizedDataEntry) != 0,
"This test case only makes sense, if the data entries don't fill up the whole space. "
"There should be some space left at the end that is not used, because it isn't enough space for a full entry. "
"If this static assertion fails, please use a different size for SizedDataEntry.");
TEST_F(DataNodeViewTest, DataBeginWorksWithStructEntries) {
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
auto block = blockStore->create(BLOCKSIZE_BYTES);
uint8_t *blockBegin = (uint8_t*)block->data();
DataNodeView view(std::move(block));
EXPECT_EQ(blockBegin+view.HEADERSIZE_BYTES, (uint8_t*)view.DataBegin<SizedDataEntry>());
EXPECT_EQ(blockBegin+DataNodeLayout::HEADERSIZE_BYTES, (uint8_t*)view.DataBegin<SizedDataEntry>());
}
TEST_F(DataNodeViewTest, DataEndWorksWithStructByteEntries) {
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
auto block = blockStore->create(BLOCKSIZE_BYTES);
uint8_t *blockBegin = (uint8_t*)block->data();
DataNodeView view(std::move(block));
unsigned int numFittingEntries = view.DATASIZE_BYTES / sizeof(SizedDataEntry);
unsigned int numFittingEntries = DATASIZE_BYTES / sizeof(SizedDataEntry);
uint8_t *dataEnd = (uint8_t*)view.DataEnd<SizedDataEntry>();
EXPECT_EQ(blockBegin+view.HEADERSIZE_BYTES + numFittingEntries * sizeof(SizedDataEntry), dataEnd);
EXPECT_LT(dataEnd, blockBegin + view.BLOCKSIZE_BYTES);
EXPECT_EQ(blockBegin+DataNodeLayout::HEADERSIZE_BYTES + numFittingEntries * sizeof(SizedDataEntry), dataEnd);
EXPECT_LT(dataEnd, blockBegin + BLOCKSIZE_BYTES);
}

View File

@ -32,7 +32,7 @@ TEST_F(DataTreeGrowingTest_Structure, GrowAThreeNodeChainedTree) {
TEST_F(DataTreeGrowingTest_Structure, GrowAFullTwoLevelTreeFromGroundUp) {
auto key = CreateLeafOnlyTree()->key();
for (int i = 1; i < DataInnerNode::MAX_STORED_CHILDREN; ++i) {
for (int i = 1; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
AddLeafTo(key);
}
EXPECT_IS_FULL_TWOLEVEL_TREE(key);
@ -62,7 +62,7 @@ TEST_F(DataTreeGrowingTest_Structure, GrowAThreeLevelTreeWithLowerLevelFull) {
TEST_F(DataTreeGrowingTest_Structure, GrowAFullThreeLevelTreeFromGroundUp) {
auto key = CreateLeafOnlyTree()->key();
for (int i = 1; i < DataInnerNode::MAX_STORED_CHILDREN * DataInnerNode::MAX_STORED_CHILDREN; ++i) {
for (int i = 1; i < nodeStore->layout().maxChildrenPerInnerNode() * nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
AddLeafTo(key);
}
EXPECT_IS_FULL_THREELEVEL_TREE(key);
@ -81,7 +81,7 @@ TEST_F(DataTreeGrowingTest_Structure, GrowAFullThreeLevelTree) {
TEST_F(DataTreeGrowingTest_Structure, GrowAThreeLevelTreeWithTwoFullSubtreesFromGroundUp) {
auto key = CreateLeafOnlyTree()->key();
for (int i = 1; i < 2 * DataInnerNode::MAX_STORED_CHILDREN; ++i) {
for (int i = 1; i < 2 * nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
AddLeafTo(key);
}

View File

@ -131,7 +131,7 @@ TEST_F(DataTreeShrinkingTest_Structure, ShrinkAThreeLevelTreeWithThreeChildrenOf
TEST_F(DataTreeShrinkingTest_Structure, ShrinkAFullTwoLevelTreeDownToOneLeaf) {
auto key = CreateFullTwoLevel()->key();
for (int i = 0; i < DataInnerNode::MAX_STORED_CHILDREN-1; ++i) {
for (int i = 0; i < nodeStore->layout().maxChildrenPerInnerNode()-1; ++i) {
Shrink(key);
}
EXPECT_IS_LEAF_NODE(key);
@ -140,7 +140,7 @@ TEST_F(DataTreeShrinkingTest_Structure, ShrinkAFullTwoLevelTreeDownToOneLeaf) {
TEST_F(DataTreeShrinkingTest_Structure, ShrinkAFullThreeLevelTreeDownToOneLeaf) {
auto key = CreateFullThreeLevel()->key();
for (int i = 0; i < DataInnerNode::MAX_STORED_CHILDREN*DataInnerNode::MAX_STORED_CHILDREN-1; ++i) {
for (int i = 0; i < nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode()-1; ++i) {
Shrink(key);
}
EXPECT_IS_LEAF_NODE(key);

View File

@ -16,8 +16,10 @@ using std::initializer_list;
using std::vector;
using cpputils::dynamic_pointer_move;
constexpr uint32_t DataTreeTest::BLOCKSIZE_BYTES;
DataTreeTest::DataTreeTest()
:_nodeStore(make_unique<DataNodeStore>(make_unique<FakeBlockStore>())),
:_nodeStore(make_unique<DataNodeStore>(make_unique<FakeBlockStore>(), BLOCKSIZE_BYTES)),
nodeStore(_nodeStore.get()),
treeStore(std::move(_nodeStore)) {
}
@ -51,13 +53,13 @@ unique_ptr<DataTree> DataTreeTest::CreateLeafOnlyTree() {
}
void DataTreeTest::FillNode(DataInnerNode *node) {
for(unsigned int i=node->numChildren(); i < DataInnerNode::MAX_STORED_CHILDREN; ++i) {
for(unsigned int i=node->numChildren(); i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
node->addChild(*CreateLeaf());
}
}
void DataTreeTest::FillNodeTwoLevel(DataInnerNode *node) {
for(unsigned int i=node->numChildren(); i < DataInnerNode::MAX_STORED_CHILDREN; ++i) {
for(unsigned int i=node->numChildren(); i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
node->addChild(*CreateFullTwoLevel());
}
}
@ -129,7 +131,7 @@ void DataTreeTest::EXPECT_IS_TWONODE_CHAIN(const Key &key) {
void DataTreeTest::EXPECT_IS_FULL_TWOLEVEL_TREE(const Key &key) {
auto node = LoadInnerNode(key);
EXPECT_EQ(DataInnerNode::MAX_STORED_CHILDREN, node->numChildren());
EXPECT_EQ(nodeStore->layout().maxChildrenPerInnerNode(), node->numChildren());
for (unsigned int i = 0; i < node->numChildren(); ++i) {
EXPECT_IS_LEAF_NODE(node->getChild(i)->key());
}
@ -137,10 +139,10 @@ void DataTreeTest::EXPECT_IS_FULL_TWOLEVEL_TREE(const Key &key) {
void DataTreeTest::EXPECT_IS_FULL_THREELEVEL_TREE(const Key &key) {
auto root = LoadInnerNode(key);
EXPECT_EQ(DataInnerNode::MAX_STORED_CHILDREN, root->numChildren());
EXPECT_EQ(nodeStore->layout().maxChildrenPerInnerNode(), root->numChildren());
for (unsigned int i = 0; i < root->numChildren(); ++i) {
auto node = LoadInnerNode(root->getChild(i)->key());
EXPECT_EQ(DataInnerNode::MAX_STORED_CHILDREN, node->numChildren());
EXPECT_EQ(nodeStore->layout().maxChildrenPerInnerNode(), node->numChildren());
for (unsigned int j = 0; j < node->numChildren(); ++j) {
EXPECT_IS_LEAF_NODE(node->getChild(j)->key());
}

View File

@ -14,6 +14,8 @@ class DataTreeTest: public ::testing::Test {
public:
DataTreeTest();
static constexpr uint32_t BLOCKSIZE_BYTES = 1024;
std::unique_ptr<blobstore::onblocks::datanodestore::DataLeafNode> CreateLeaf();
std::unique_ptr<blobstore::onblocks::datanodestore::DataInnerNode> CreateInner(std::vector<const blobstore::onblocks::datanodestore::DataNode *> children);
std::unique_ptr<blobstore::onblocks::datanodestore::DataInnerNode> CreateInner(std::initializer_list<const blobstore::onblocks::datanodestore::DataNode *> children);

View File

@ -6,6 +6,7 @@
#include <messmer/cpp-utils/pointer.h>
#include "LeafDataFixture.h"
//TODO Rename, since we now allow any number of levels
// A data fixture containing data for a two-level tree (one inner node with leaf children).
// The class can fill this data into the leaf children of a given inner node
// and given an inner node can check, whether the data stored is correct.
@ -52,9 +53,10 @@ private:
int size(int childIndex) {
if (_useFullSizeLeaves) {
return blobstore::onblocks::datanodestore::DataLeafNode::MAX_STORED_BYTES;
return _dataNodeStore->layout().maxBytesPerLeaf();
} else {
return mod(blobstore::onblocks::datanodestore::DataLeafNode::MAX_STORED_BYTES - childIndex, blobstore::onblocks::datanodestore::DataLeafNode::MAX_STORED_BYTES);
uint32_t maxBytesPerLeaf = _dataNodeStore->layout().maxBytesPerLeaf();
return mod(maxBytesPerLeaf - childIndex, maxBytesPerLeaf);
}
}

View File

@ -102,9 +102,9 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddleLeafOfFullTwolevelTree) {
TEST_F(DataTreeTest_TraverseLeaves, TraverseLastLeafOfFullTwolevelTree) {
auto root = CreateFullTwoLevel();
EXPECT_TRAVERSE_LEAF(root->getChild(DataInnerNode::MAX_STORED_CHILDREN-1)->key(), DataInnerNode::MAX_STORED_CHILDREN-1);
EXPECT_TRAVERSE_LEAF(root->getChild(nodeStore->layout().maxChildrenPerInnerNode()-1)->key(), nodeStore->layout().maxChildrenPerInnerNode()-1);
TraverseLeaves(root.get(), DataInnerNode::MAX_STORED_CHILDREN-1, DataInnerNode::MAX_STORED_CHILDREN);
TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode()-1, nodeStore->layout().maxChildrenPerInnerNode());
}
TEST_F(DataTreeTest_TraverseLeaves, TraverseNothingInFullTwolevelTree1) {
@ -118,7 +118,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseNothingInFullTwolevelTree2) {
auto root = CreateFullTwoLevel();
EXPECT_DONT_TRAVERSE_ANY_LEAVES();
TraverseLeaves(root.get(), DataInnerNode::MAX_STORED_CHILDREN, DataInnerNode::MAX_STORED_CHILDREN);
TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode(), nodeStore->layout().maxChildrenPerInnerNode());
}
TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstLeafOfThreeLevelMinDataTree) {
@ -137,31 +137,31 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddleLeafOfThreeLevelMinDataTree) {
TEST_F(DataTreeTest_TraverseLeaves, TraverseLastLeafOfThreeLevelMinDataTree) {
auto root = CreateThreeLevelMinData();
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), DataInnerNode::MAX_STORED_CHILDREN);
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), nodeStore->layout().maxChildrenPerInnerNode());
TraverseLeaves(root.get(), DataInnerNode::MAX_STORED_CHILDREN, DataInnerNode::MAX_STORED_CHILDREN+1);
TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode(), nodeStore->layout().maxChildrenPerInnerNode()+1);
}
TEST_F(DataTreeTest_TraverseLeaves, TraverseAllLeavesOfFullTwolevelTree) {
auto root = CreateFullTwoLevel();
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*root, 0);
TraverseLeaves(root.get(), 0, DataInnerNode::MAX_STORED_CHILDREN);
TraverseLeaves(root.get(), 0, nodeStore->layout().maxChildrenPerInnerNode());
}
TEST_F(DataTreeTest_TraverseLeaves, TraverseAllLeavesOfThreelevelMinDataTree) {
auto root = CreateThreeLevelMinData();
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(0)->key()), 0);
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), DataInnerNode::MAX_STORED_CHILDREN);
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), nodeStore->layout().maxChildrenPerInnerNode());
TraverseLeaves(root.get(), 0, DataInnerNode::MAX_STORED_CHILDREN+1);
TraverseLeaves(root.get(), 0, nodeStore->layout().maxChildrenPerInnerNode()+1);
}
TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstChildOfThreelevelMinDataTree) {
auto root = CreateThreeLevelMinData();
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(0)->key()), 0);
TraverseLeaves(root.get(), 0, DataInnerNode::MAX_STORED_CHILDREN);
TraverseLeaves(root.get(), 0, nodeStore->layout().maxChildrenPerInnerNode());
}
TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstPartOfFullTwolevelTree) {
@ -184,11 +184,11 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseInnerPartOfFullTwolevelTree) {
TEST_F(DataTreeTest_TraverseLeaves, TraverseLastPartOfFullTwolevelTree) {
auto root = CreateFullTwoLevel();
for (int i = 5; i < DataInnerNode::MAX_STORED_CHILDREN; ++i) {
for (int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
EXPECT_TRAVERSE_LEAF(root->getChild(i)->key(), i);
}
TraverseLeaves(root.get(), 5, DataInnerNode::MAX_STORED_CHILDREN);
TraverseLeaves(root.get(), 5, nodeStore->layout().maxChildrenPerInnerNode());
}
TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstPartOfThreelevelMinDataTree) {
@ -214,12 +214,12 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseInnerPartOfThreelevelMinDataTree) {
TEST_F(DataTreeTest_TraverseLeaves, TraverseLastPartOfThreelevelMinDataTree) {
auto root = CreateThreeLevelMinData();
auto node = LoadInnerNode(root->getChild(0)->key());
for (int i = 5; i < DataInnerNode::MAX_STORED_CHILDREN; ++i) {
for (int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
EXPECT_TRAVERSE_LEAF(node->getChild(i)->key(), i);
}
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), DataInnerNode::MAX_STORED_CHILDREN);
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), nodeStore->layout().maxChildrenPerInnerNode());
TraverseLeaves(root.get(), 5, DataInnerNode::MAX_STORED_CHILDREN+1);
TraverseLeaves(root.get(), 5, nodeStore->layout().maxChildrenPerInnerNode()+1);
}
TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstLeafOfThreelevelTree) {
@ -231,7 +231,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstLeafOfThreelevelTree) {
TEST_F(DataTreeTest_TraverseLeaves, TraverseLastLeafOfThreelevelTree) {
auto root = CreateThreeLevel();
uint32_t numLeaves = DataInnerNode::MAX_STORED_CHILDREN * 5 + 3;
uint32_t numLeaves = nodeStore->layout().maxChildrenPerInnerNode() * 5 + 3;
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->LastChild()->key())->LastChild()->key(), numLeaves-1);
TraverseLeaves(root.get(), numLeaves-1, numLeaves);
@ -239,7 +239,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseLastLeafOfThreelevelTree) {
TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddleLeafOfThreelevelTree) {
auto root = CreateThreeLevel();
uint32_t wantedLeafIndex = DataInnerNode::MAX_STORED_CHILDREN * 2 + 5;
uint32_t wantedLeafIndex = nodeStore->layout().maxChildrenPerInnerNode() * 2 + 5;
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(2)->key())->getChild(5)->key(), wantedLeafIndex);
TraverseLeaves(root.get(), wantedLeafIndex, wantedLeafIndex+1);
@ -249,90 +249,90 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstPartOfThreelevelTree) {
auto root = CreateThreeLevel();
//Traverse all leaves in the first two children of the root
for(int i = 0; i < 2; ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * DataInnerNode::MAX_STORED_CHILDREN);
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode());
}
//Traverse some of the leaves in the third child of the root
auto child = LoadInnerNode(root->getChild(2)->key());
for(int i = 0; i < 5; ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 2 * DataInnerNode::MAX_STORED_CHILDREN + i);
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 2 * nodeStore->layout().maxChildrenPerInnerNode() + i);
}
TraverseLeaves(root.get(), 0, 2 * DataInnerNode::MAX_STORED_CHILDREN + 5);
TraverseLeaves(root.get(), 0, 2 * nodeStore->layout().maxChildrenPerInnerNode() + 5);
}
TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddlePartOfThreelevelTree_OnlyFullChildren) {
auto root = CreateThreeLevel();
//Traverse some of the leaves in the second child of the root
auto child = LoadInnerNode(root->getChild(1)->key());
for(int i = 5; i < DataInnerNode::MAX_STORED_CHILDREN; ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), DataInnerNode::MAX_STORED_CHILDREN + i);
for(int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), nodeStore->layout().maxChildrenPerInnerNode() + i);
}
//Traverse all leaves in the third and fourth child of the root
for(int i = 2; i < 4; ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * DataInnerNode::MAX_STORED_CHILDREN);
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode());
}
//Traverse some of the leaves in the fifth child of the root
child = LoadInnerNode(root->getChild(4)->key());
for(int i = 0; i < 5; ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 4 * DataInnerNode::MAX_STORED_CHILDREN + i);
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 4 * nodeStore->layout().maxChildrenPerInnerNode() + i);
}
TraverseLeaves(root.get(), DataInnerNode::MAX_STORED_CHILDREN + 5, 4 * DataInnerNode::MAX_STORED_CHILDREN + 5);
TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode() + 5, 4 * nodeStore->layout().maxChildrenPerInnerNode() + 5);
}
TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddlePartOfThreelevelTree_AlsoLastNonfullChild) {
auto root = CreateThreeLevel();
//Traverse some of the leaves in the second child of the root
auto child = LoadInnerNode(root->getChild(1)->key());
for(int i = 5; i < DataInnerNode::MAX_STORED_CHILDREN; ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), DataInnerNode::MAX_STORED_CHILDREN + i);
for(int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), nodeStore->layout().maxChildrenPerInnerNode() + i);
}
//Traverse all leaves in the third, fourth and fifth child of the root
for(int i = 2; i < 5; ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * DataInnerNode::MAX_STORED_CHILDREN);
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode());
}
//Traverse some of the leaves in the sixth child of the root
child = LoadInnerNode(root->getChild(5)->key());
for(int i = 0; i < 2; ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 5 * DataInnerNode::MAX_STORED_CHILDREN + i);
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 5 * nodeStore->layout().maxChildrenPerInnerNode() + i);
}
TraverseLeaves(root.get(), DataInnerNode::MAX_STORED_CHILDREN + 5, 5 * DataInnerNode::MAX_STORED_CHILDREN + 2);
TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode() + 5, 5 * nodeStore->layout().maxChildrenPerInnerNode() + 2);
}
TEST_F(DataTreeTest_TraverseLeaves, TraverseLastPartOfThreelevelTree) {
auto root = CreateThreeLevel();
//Traverse some of the leaves in the second child of the root
auto child = LoadInnerNode(root->getChild(1)->key());
for(int i = 5; i < DataInnerNode::MAX_STORED_CHILDREN; ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), DataInnerNode::MAX_STORED_CHILDREN + i);
for(int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), nodeStore->layout().maxChildrenPerInnerNode() + i);
}
//Traverse all leaves in the third, fourth and fifth child of the root
for(int i = 2; i < 5; ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * DataInnerNode::MAX_STORED_CHILDREN);
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode());
}
//Traverse all of the leaves in the sixth child of the root
child = LoadInnerNode(root->getChild(5)->key());
for(int i = 0; i < child->numChildren(); ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 5 * DataInnerNode::MAX_STORED_CHILDREN + i);
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 5 * nodeStore->layout().maxChildrenPerInnerNode() + i);
}
TraverseLeaves(root.get(), DataInnerNode::MAX_STORED_CHILDREN + 5, 5 * DataInnerNode::MAX_STORED_CHILDREN + child->numChildren());
TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode() + 5, 5 * nodeStore->layout().maxChildrenPerInnerNode() + child->numChildren());
}
TEST_F(DataTreeTest_TraverseLeaves, TraverseAllLeavesOfThreelevelTree) {
auto root = CreateThreeLevel();
//Traverse all leaves in the third, fourth and fifth child of the root
for(int i = 0; i < 5; ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * DataInnerNode::MAX_STORED_CHILDREN);
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode());
}
//Traverse all of the leaves in the sixth child of the root
auto child = LoadInnerNode(root->getChild(5)->key());
for(int i = 0; i < child->numChildren(); ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 5 * DataInnerNode::MAX_STORED_CHILDREN + i);
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 5 * nodeStore->layout().maxChildrenPerInnerNode() + i);
}
TraverseLeaves(root.get(), 0, 5 * DataInnerNode::MAX_STORED_CHILDREN + child->numChildren());
TraverseLeaves(root.get(), 0, 5 * nodeStore->layout().maxChildrenPerInnerNode() + child->numChildren());
}
//Disabled because it takes too long
@ -341,19 +341,19 @@ TEST_F(DataTreeTest_TraverseLeaves, DISABLED_TraverseAllLeavesOfFourLevelTree) {
//Traverse all leaves of the full threelevel tree in the first child
auto firstChild = LoadInnerNode(root->getChild(0)->key());
for(int i = 0; i < firstChild->numChildren(); ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(firstChild->getChild(i)->key()), i * DataInnerNode::MAX_STORED_CHILDREN);
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(firstChild->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode());
}
//Traverse all leaves of the full threelevel tree in the second child
auto secondChild = LoadInnerNode(root->getChild(1)->key());
for(int i = 0; i < secondChild->numChildren(); ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(secondChild->getChild(i)->key()), (DataInnerNode::MAX_STORED_CHILDREN + i) * DataInnerNode::MAX_STORED_CHILDREN);
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(secondChild->getChild(i)->key()), (nodeStore->layout().maxChildrenPerInnerNode() + i) * nodeStore->layout().maxChildrenPerInnerNode());
}
//Traverse all leaves of the non-full threelevel tree in the third child
auto thirdChild = LoadInnerNode(root->getChild(2)->key());
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(thirdChild->getChild(0)->key()), 2 * DataInnerNode::MAX_STORED_CHILDREN * DataInnerNode::MAX_STORED_CHILDREN);
EXPECT_TRAVERSE_LEAF(LoadInnerNode(thirdChild->getChild(1)->key())->getChild(0)->key(), 2 * DataInnerNode::MAX_STORED_CHILDREN * DataInnerNode::MAX_STORED_CHILDREN + DataInnerNode::MAX_STORED_CHILDREN);
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(thirdChild->getChild(0)->key()), 2 * nodeStore->layout().maxChildrenPerInnerNode() * nodeStore->layout().maxChildrenPerInnerNode());
EXPECT_TRAVERSE_LEAF(LoadInnerNode(thirdChild->getChild(1)->key())->getChild(0)->key(), 2 * nodeStore->layout().maxChildrenPerInnerNode() * nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode());
TraverseLeaves(root.get(), 0, 2*DataInnerNode::MAX_STORED_CHILDREN*DataInnerNode::MAX_STORED_CHILDREN + DataInnerNode::MAX_STORED_CHILDREN + 1);
TraverseLeaves(root.get(), 0, 2*nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode() + 1);
}
//TODO Traverse inner part of four level tree