Replace magic number in DataNodeView with a depth field
This commit is contained in:
parent
fb2b511d06
commit
a97eb08224
@ -14,9 +14,10 @@ DataInnerNode::DataInnerNode(DataNodeView view)
|
||||
DataInnerNode::~DataInnerNode() {
|
||||
}
|
||||
|
||||
void DataInnerNode::InitializeNewNode() {
|
||||
*_node.MagicNumber() = _node.magicNumberNodeWithChildren;
|
||||
*_node.Size() = 0;
|
||||
void DataInnerNode::InitializeNewNode(const Key &first_child_key, const DataNodeView &first_child) {
|
||||
*_node.Depth() = *first_child.Depth() + 1;
|
||||
*_node.Size() = 1;
|
||||
first_child_key.ToBinary(ChildrenBegin()->key);
|
||||
}
|
||||
|
||||
void DataInnerNode::read(off_t offset, size_t count, Data *result) const {
|
||||
@ -47,9 +48,10 @@ uint64_t DataInnerNode::readFromChild(const ChildEntry *child, off_t inner_offse
|
||||
const DataInnerNode::ChildEntry *DataInnerNode::ChildContainingFirstByteAfterOffset(off_t offset) const {
|
||||
uint32_t offset_blocks = offset / _node.BLOCKSIZE_BYTES;
|
||||
|
||||
//TODO no binary search anymore
|
||||
return
|
||||
std::upper_bound(ChildrenBegin(), ChildrenEnd(), offset_blocks, [](uint32_t offset_blocks, const ChildEntry &child) {
|
||||
return offset_blocks < child.numBlocksInThisAndLeftwardNodes;
|
||||
return false;//return offset_blocks < child.numBlocksInThisAndLeftwardNodes;
|
||||
});
|
||||
}
|
||||
|
||||
@ -69,7 +71,12 @@ uint64_t DataInnerNode::numBytesInLeftwardSiblings(const ChildEntry *child) cons
|
||||
}
|
||||
|
||||
uint64_t DataInnerNode::numBytesInChildAndLeftwardSiblings(const ChildEntry *child) const {
|
||||
return (uint64_t)child->numBlocksInThisAndLeftwardNodes * _node.BLOCKSIZE_BYTES;
|
||||
//TODO Rewrite
|
||||
//return (uint64_t)child->numBlocksInThisAndLeftwardNodes * _node.BLOCKSIZE_BYTES;
|
||||
}
|
||||
|
||||
DataInnerNode::ChildEntry *DataInnerNode::ChildrenBegin() {
|
||||
return const_cast<ChildEntry*>(const_cast<const DataInnerNode*>(this)->ChildrenBegin());
|
||||
}
|
||||
|
||||
const DataInnerNode::ChildEntry *DataInnerNode::ChildrenBegin() const {
|
||||
|
@ -13,13 +13,12 @@ public:
|
||||
virtual ~DataInnerNode();
|
||||
|
||||
struct ChildEntry {
|
||||
uint32_t numBlocksInThisAndLeftwardNodes;
|
||||
uint8_t key[Key::KEYLENGTH_BINARY];
|
||||
};
|
||||
|
||||
static constexpr uint32_t MAX_STORED_CHILDREN = DataNodeView::DATASIZE_BYTES / sizeof(ChildEntry);
|
||||
|
||||
void InitializeNewNode();
|
||||
void InitializeNewNode(const Key &first_child_key, const DataNodeView &first_child);
|
||||
|
||||
void read(off_t offset, size_t count, blockstore::Data *result) const override;
|
||||
void write(off_t offset, size_t count, const blockstore::Data &data) override;
|
||||
@ -28,7 +27,7 @@ public:
|
||||
void resize(uint64_t newsize_bytes) override;
|
||||
|
||||
private:
|
||||
|
||||
ChildEntry *ChildrenBegin();
|
||||
const ChildEntry *ChildrenBegin() const;
|
||||
const ChildEntry *ChildrenEnd() const;
|
||||
const ChildEntry *ChildrenLast() const;
|
||||
|
@ -28,7 +28,7 @@ void DataLeafNode::write(off_t offset, size_t count, const Data &data) {
|
||||
}
|
||||
|
||||
void DataLeafNode::InitializeNewNode() {
|
||||
*_node.MagicNumber() = _node.magicNumberLeaf;
|
||||
*_node.Depth() = 0;
|
||||
*_node.Size() = 0;
|
||||
//fillDataWithZeroes(); not needed, because a newly created block will be zeroed out. DataLeafNodeTest.SpaceIsZeroFilledWhenGrowing ensures this.
|
||||
}
|
||||
|
@ -22,19 +22,18 @@ DataNode::~DataNode() {
|
||||
unique_ptr<DataNode> DataNode::load(unique_ptr<Block> block) {
|
||||
DataNodeView node(std::move(block));
|
||||
|
||||
if (*node.MagicNumber() == node.magicNumberNodeWithChildren) {
|
||||
return unique_ptr<DataInnerNode>(new DataInnerNode(std::move(node)));
|
||||
} else if (*node.MagicNumber() == node.magicNumberLeaf) {
|
||||
if (*node.Depth() == 0) {
|
||||
return unique_ptr<DataLeafNode>(new DataLeafNode(std::move(node)));
|
||||
} else if (*node.Depth() < MAX_DEPTH) {
|
||||
return unique_ptr<DataInnerNode>(new DataInnerNode(std::move(node)));
|
||||
} else {
|
||||
//TODO Better exception
|
||||
throw runtime_error("Invalid node magic number");
|
||||
throw runtime_error("Tree is to deep. Data corruption?");
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<DataNode> DataNode::createNewInnerNode(unique_ptr<Block> block) {
|
||||
unique_ptr<DataNode> DataNode::createNewInnerNode(unique_ptr<Block> block, const Key &first_child_key, const DataNode &first_child) {
|
||||
auto newNode = unique_ptr<DataInnerNode>(new DataInnerNode(std::move(block)));
|
||||
newNode->InitializeNewNode();
|
||||
newNode->InitializeNewNode(first_child_key, first_child._node);
|
||||
return std::move(newNode);
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,8 @@ class DataNode {
|
||||
public:
|
||||
virtual ~DataNode();
|
||||
|
||||
static constexpr uint8_t MAX_DEPTH = 10;
|
||||
|
||||
virtual void read(off_t offset, size_t count, blockstore::Data *result) const = 0;
|
||||
virtual void write(off_t offset, size_t count, const blockstore::Data &data) = 0;
|
||||
|
||||
@ -21,7 +23,7 @@ public:
|
||||
|
||||
static std::unique_ptr<DataNode> load(std::unique_ptr<blockstore::Block> block);
|
||||
static std::unique_ptr<DataNode> createNewLeafNode(std::unique_ptr<blockstore::Block> block);
|
||||
static std::unique_ptr<DataNode> createNewInnerNode(std::unique_ptr<blockstore::Block> block);
|
||||
static std::unique_ptr<DataNode> createNewInnerNode(std::unique_ptr<blockstore::Block> block, const Key &first_child_key, const DataNode &first_child);
|
||||
|
||||
protected:
|
||||
DataNode(DataNodeView block);
|
||||
|
@ -24,8 +24,8 @@ public:
|
||||
|
||||
//Total size of the header
|
||||
static constexpr unsigned int HEADERSIZE_BYTES = 8;
|
||||
//Where in the header is the magic number
|
||||
static constexpr unsigned int MAGICNUMBER_OFFSET_BYTES = 0;
|
||||
//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;
|
||||
|
||||
@ -34,17 +34,12 @@ public:
|
||||
//How much space is there for data
|
||||
static constexpr unsigned int DATASIZE_BYTES = BLOCKSIZE_BYTES - HEADERSIZE_BYTES;
|
||||
|
||||
static constexpr unsigned char magicNumberNodeWithChildren = 0x01;
|
||||
static constexpr unsigned char magicNumberLeaf = 0x02;
|
||||
static constexpr unsigned char magicNumberRootWithChildren = 0x03;
|
||||
static constexpr unsigned char magicNumberRootLeaf = 0x04;
|
||||
|
||||
const uint8_t *MagicNumber() const {
|
||||
return GetOffset<MAGICNUMBER_OFFSET_BYTES, uint8_t>();
|
||||
const uint8_t *Depth() const {
|
||||
return GetOffset<DEPTH_OFFSET_BYTES, uint8_t>();
|
||||
}
|
||||
|
||||
uint8_t *MagicNumber() {
|
||||
return const_cast<uint8_t*>(const_cast<const DataNodeView*>(this)->MagicNumber());
|
||||
uint8_t *Depth() {
|
||||
return const_cast<uint8_t*>(const_cast<const DataNodeView*>(this)->Depth());
|
||||
}
|
||||
|
||||
const uint32_t *Size() const {
|
||||
|
@ -31,8 +31,11 @@ TEST_F(DataNodeTest, CreateLeafNodeCreatesLeafNode) {
|
||||
}
|
||||
|
||||
TEST_F(DataNodeTest, CreateInnerNodeCreatesInnerNode) {
|
||||
auto leafblock = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
|
||||
auto leaf = DataNode::createNewLeafNode(std::move(leafblock.block));
|
||||
|
||||
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
|
||||
auto node = DataNode::createNewInnerNode(std::move(block.block));
|
||||
auto node = DataNode::createNewInnerNode(std::move(block.block), leafblock.key, *leaf);
|
||||
EXPECT_IS_PTR_TYPE(DataInnerNode, node.get());
|
||||
}
|
||||
|
||||
@ -48,11 +51,13 @@ TEST_F(DataNodeTest, LeafNodeIsRecognizedAfterStoreAndLoad) {
|
||||
EXPECT_IS_PTR_TYPE(DataLeafNode, loaded_node.get());
|
||||
}
|
||||
|
||||
TEST_F(DataNodeTest, InnerNodeIsRecognizedAfterStoreAndLoad) {
|
||||
TEST_F(DataNodeTest, InnerNodeWithDepth1IsRecognizedAfterStoreAndLoad) {
|
||||
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
|
||||
Key key = block.key;
|
||||
{
|
||||
DataNode::createNewInnerNode(std::move(block.block));
|
||||
auto leafblock = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
|
||||
auto leaf = DataNode::createNewLeafNode(std::move(leafblock.block));
|
||||
DataNode::createNewInnerNode(std::move(block.block), leafblock.key, *leaf);
|
||||
}
|
||||
|
||||
auto loaded_node = DataNode::load(blockStore->load(key));
|
||||
@ -60,12 +65,28 @@ TEST_F(DataNodeTest, InnerNodeIsRecognizedAfterStoreAndLoad) {
|
||||
EXPECT_IS_PTR_TYPE(DataInnerNode, loaded_node.get());
|
||||
}
|
||||
|
||||
TEST_F(DataNodeTest, DataNodeCrashesOnLoadIfMagicNumberIsWrong) {
|
||||
TEST_F(DataNodeTest, InnerNodeWithDepth2IsRecognizedAfterStoreAndLoad) {
|
||||
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
|
||||
Key key = block.key;
|
||||
{
|
||||
auto leafblock = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
|
||||
auto leaf = DataNode::createNewLeafNode(std::move(leafblock.block));
|
||||
auto inner1block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
|
||||
auto inner1 = DataNode::createNewInnerNode(std::move(inner1block.block), leafblock.key, *leaf);
|
||||
DataNode::createNewInnerNode(std::move(block.block), inner1block.key, *inner1);
|
||||
}
|
||||
|
||||
auto loaded_node = DataNode::load(blockStore->load(key));
|
||||
|
||||
EXPECT_IS_PTR_TYPE(DataInnerNode, loaded_node.get());
|
||||
}
|
||||
|
||||
TEST_F(DataNodeTest, DataNodeCrashesOnLoadIfDepthIsTooHigh) {
|
||||
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
|
||||
Key key = block.key;
|
||||
{
|
||||
DataNodeView view(std::move(block.block));
|
||||
*view.MagicNumber() = 0xFF; // this is an invalid magic number
|
||||
*view.Depth() = 200u; // this is an invalid depth
|
||||
}
|
||||
|
||||
auto loaded_block = blockStore->load(key);
|
||||
|
@ -28,14 +28,18 @@ public:
|
||||
unique_ptr<BlockStore> blockStore = make_unique<FakeBlockStore>();
|
||||
};
|
||||
|
||||
TEST_F(DataNodeViewTest, MagicNumberIsStored) {
|
||||
class DataNodeViewDepthTest: public DataNodeViewTest, public WithParamInterface<uint8_t> {
|
||||
};
|
||||
INSTANTIATE_TEST_CASE_P(DataNodeViewDepthTest, DataNodeViewDepthTest, Values(0, 1, 3, 10, 100));
|
||||
|
||||
TEST_P(DataNodeViewDepthTest, DepthIsStored) {
|
||||
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
|
||||
{
|
||||
DataNodeView view(std::move(block.block));
|
||||
*view.MagicNumber() = 0x3F;
|
||||
*view.Depth() = GetParam();
|
||||
}
|
||||
DataNodeView view(blockStore->load(block.key));
|
||||
EXPECT_EQ(0x3F, *view.MagicNumber());
|
||||
EXPECT_EQ(GetParam(), *view.Depth());
|
||||
}
|
||||
|
||||
class DataNodeViewSizeTest: public DataNodeViewTest, public WithParamInterface<uint32_t> {
|
||||
@ -68,12 +72,12 @@ TEST_F(DataNodeViewTest, HeaderAndBodyDontOverlap) {
|
||||
auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE);
|
||||
{
|
||||
DataNodeView view(std::move(block.block));
|
||||
*view.MagicNumber() = 0xAA;
|
||||
*view.Depth() = 3;
|
||||
*view.Size() = 1000000000u;
|
||||
std::memcpy(view.DataBegin<uint8_t>(), randomData.data(), DataNodeView::DATASIZE_BYTES);
|
||||
}
|
||||
DataNodeView view(blockStore->load(block.key));
|
||||
EXPECT_EQ(0xAA, *view.MagicNumber());
|
||||
EXPECT_EQ(3, *view.Depth());
|
||||
EXPECT_EQ(1000000000u, *view.Size());
|
||||
EXPECT_EQ(0, std::memcmp(view.DataBegin<uint8_t>(), randomData.data(), DataNodeView::DATASIZE_BYTES));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user