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:
parent
100268930e
commit
c9ce0d55cf
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue