Restrict datanodestore abstraction to a simple node store without tree operations like resizing
This commit is contained in:
parent
fbec747427
commit
99c2e353a4
@ -1,6 +1,6 @@
|
|||||||
#include <blobstore/implementations/onblocks/BlobOnBlocks.h>
|
#include <blobstore/implementations/onblocks/BlobOnBlocks.h>
|
||||||
|
|
||||||
#include "datanodestore/DataNode.h"
|
#include <blobstore/implementations/onblocks/datanodestore/DataNode.h>
|
||||||
|
|
||||||
using std::unique_ptr;
|
using std::unique_ptr;
|
||||||
|
|
||||||
@ -18,7 +18,8 @@ BlobOnBlocks::~BlobOnBlocks() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t BlobOnBlocks::size() const {
|
size_t BlobOnBlocks::size() const {
|
||||||
return _rootnode->numBytesInThisNode();
|
assert(false); //TODO Implement
|
||||||
|
//return _rootnode->numBytesInThisNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
#include <blobstore/implementations/onblocks/datanodestore/DataLeafNode.h>
|
||||||
|
#include <blobstore/implementations/onblocks/datanodestore/DataNodeStore.h>
|
||||||
#include "BlobStoreOnBlocks.h"
|
#include "BlobStoreOnBlocks.h"
|
||||||
|
|
||||||
#include "BlobOnBlocks.h"
|
#include "BlobOnBlocks.h"
|
||||||
#include "datanodestore/DataNodeStore.h"
|
|
||||||
#include "datanodestore/DataLeafNode.h"
|
|
||||||
|
|
||||||
using std::unique_ptr;
|
using std::unique_ptr;
|
||||||
using std::make_unique;
|
using std::make_unique;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
add_subdirectory(datanodestore)
|
add_subdirectory(datanodestore)
|
||||||
|
add_subdirectory(datatreestore)
|
||||||
|
|
||||||
add_library(blobstore_onblocks BlobOnBlocks.cpp BlobStoreOnBlocks.cpp)
|
add_library(blobstore_onblocks BlobOnBlocks.cpp BlobStoreOnBlocks.cpp)
|
||||||
|
|
||||||
target_link_libraries(blobstore_onblocks blobstore_onblocks_datanodestore)
|
target_link_libraries(blobstore_onblocks blobstore_onblocks_datatreestore)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include <blobstore/implementations/onblocks/datanodestore/DataInnerNode.h>
|
#include "DataInnerNode.h"
|
||||||
#include <blobstore/implementations/onblocks/datanodestore/DataNodeStore.h>
|
#include "DataNodeStore.h"
|
||||||
|
|
||||||
|
|
||||||
using std::unique_ptr;
|
using std::unique_ptr;
|
||||||
@ -11,8 +11,8 @@ namespace blobstore {
|
|||||||
namespace onblocks {
|
namespace onblocks {
|
||||||
namespace datanodestore {
|
namespace datanodestore {
|
||||||
|
|
||||||
DataInnerNode::DataInnerNode(DataNodeView view, const Key &key, DataNodeStore *nodestorage)
|
DataInnerNode::DataInnerNode(DataNodeView view, const Key &key)
|
||||||
: DataNode(std::move(view), key, nodestorage) {
|
: DataNode(std::move(view), key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DataInnerNode::~DataInnerNode() {
|
DataInnerNode::~DataInnerNode() {
|
||||||
@ -24,66 +24,10 @@ void DataInnerNode::InitializeNewNode(const DataNode &first_child) {
|
|||||||
first_child.key().ToBinary(ChildrenBegin()->key);
|
first_child.key().ToBinary(ChildrenBegin()->key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataInnerNode::read(off_t offset, size_t count, Data *result) const {
|
|
||||||
assert(count <= result->size());
|
|
||||||
const uint64_t end = offset + count;
|
|
||||||
assert(end <= numBytesInThisNode());
|
|
||||||
|
|
||||||
uint8_t *target = (uint8_t*)result->data();
|
|
||||||
|
|
||||||
const ChildEntry *child = ChildContainingFirstByteAfterOffset(offset);
|
|
||||||
uint32_t child_index = child-ChildrenBegin();
|
|
||||||
uint64_t child_first_byte_index = maxNumBytesPerChild() * child_index;
|
|
||||||
uint64_t next_child_first_byte_index = child_first_byte_index + maxNumBytesPerChild();
|
|
||||||
off_t childrelative_offset = offset - child_first_byte_index;
|
|
||||||
uint64_t already_read_bytes = readFromChild(child, childrelative_offset, count, target);
|
|
||||||
while(next_child_first_byte_index < end) { //TODO Write a test case that breaks when we're having <= instead of < here
|
|
||||||
++child;
|
|
||||||
already_read_bytes += readFromChild(child, 0, count, target + already_read_bytes);
|
|
||||||
};
|
|
||||||
assert(already_read_bytes == count);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t DataInnerNode::readFromChild(const ChildEntry *child, off_t inner_offset, size_t count, uint8_t *target) const {
|
|
||||||
//TODO This only works for non-rightmost children
|
|
||||||
uint64_t readable_bytes = std::min(count, maxNumBytesPerChild() - inner_offset);
|
|
||||||
|
|
||||||
//TODO READ...
|
|
||||||
|
|
||||||
return readable_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DataInnerNode::ChildEntry *DataInnerNode::ChildContainingFirstByteAfterOffset(off_t offset) const {
|
|
||||||
uint8_t child_index = offset/maxNumBytesPerChild();
|
|
||||||
return ChildrenBegin()+child_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t DataInnerNode::maxNumDataBlocksPerChild() const {
|
|
||||||
return std::round(std::pow(MAX_STORED_CHILDREN, *node().Depth()));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t DataInnerNode::numBytesInThisNode() const {
|
|
||||||
return numBytesInNonRightmostChildrenSum() + numBytesInRightmostChild();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t DataInnerNode::numBytesInNonRightmostChildrenSum() const {
|
|
||||||
return maxNumBytesPerChild() * (numChildren()-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t DataInnerNode::numBytesInRightmostChild() const {
|
|
||||||
Key rightmost_child_key = Key::FromBinary(RightmostChild()->key);
|
|
||||||
auto rightmost_child = storage().load(rightmost_child_key);
|
|
||||||
return rightmost_child->numBytesInThisNode();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t DataInnerNode::numChildren() const {
|
uint32_t DataInnerNode::numChildren() const {
|
||||||
return *node().Size();
|
return *node().Size();
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO This only works for non-rightmost children
|
|
||||||
uint64_t DataInnerNode::maxNumBytesPerChild() const {
|
|
||||||
return maxNumDataBlocksPerChild() * DataNodeView::DATASIZE_BYTES;
|
|
||||||
}
|
|
||||||
DataInnerNode::ChildEntry *DataInnerNode::ChildrenBegin() {
|
DataInnerNode::ChildEntry *DataInnerNode::ChildrenBegin() {
|
||||||
return const_cast<ChildEntry*>(const_cast<const DataInnerNode*>(this)->ChildrenBegin());
|
return const_cast<ChildEntry*>(const_cast<const DataInnerNode*>(this)->ChildrenBegin());
|
||||||
}
|
}
|
||||||
@ -92,23 +36,18 @@ const DataInnerNode::ChildEntry *DataInnerNode::ChildrenBegin() const {
|
|||||||
return node().DataBegin<ChildEntry>();
|
return node().DataBegin<ChildEntry>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataInnerNode::ChildEntry *DataInnerNode::ChildrenEnd() {
|
||||||
|
return const_cast<ChildEntry*>(const_cast<const DataInnerNode*>(this)->ChildrenEnd());
|
||||||
|
}
|
||||||
|
|
||||||
const DataInnerNode::ChildEntry *DataInnerNode::ChildrenEnd() const {
|
const DataInnerNode::ChildEntry *DataInnerNode::ChildrenEnd() const {
|
||||||
return ChildrenBegin() + *node().Size();
|
return ChildrenBegin() + *node().Size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const DataInnerNode::ChildEntry *DataInnerNode::RightmostChild() const{
|
const DataInnerNode::ChildEntry *DataInnerNode::RightmostExistingChild() const{
|
||||||
return ChildrenEnd()-1;
|
return ChildrenEnd()-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataInnerNode::write(off_t offset, size_t count, const Data &data) {
|
|
||||||
//TODO Implement
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataInnerNode::resize(uint64_t newsize_bytes) {
|
|
||||||
//TODO Implement
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#ifndef BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATANODESTORE_DATAINNERNODE_H_
|
#ifndef BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATANODESTORE_DATAINNERNODE_H_
|
||||||
#define BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATANODESTORE_DATAINNERNODE_H_
|
#define BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATANODESTORE_DATAINNERNODE_H_
|
||||||
|
|
||||||
#include <blobstore/implementations/onblocks/datanodestore/DataNode.h>
|
#include "DataNode.h"
|
||||||
|
|
||||||
namespace blobstore {
|
namespace blobstore {
|
||||||
namespace onblocks {
|
namespace onblocks {
|
||||||
@ -10,7 +10,7 @@ namespace datanodestore {
|
|||||||
|
|
||||||
class DataInnerNode: public DataNode {
|
class DataInnerNode: public DataNode {
|
||||||
public:
|
public:
|
||||||
DataInnerNode(DataNodeView block, const blockstore::Key &key, DataNodeStore *nodestorage);
|
DataInnerNode(DataNodeView block, const blockstore::Key &key);
|
||||||
virtual ~DataInnerNode();
|
virtual ~DataInnerNode();
|
||||||
|
|
||||||
struct ChildEntry {
|
struct ChildEntry {
|
||||||
@ -21,26 +21,14 @@ public:
|
|||||||
|
|
||||||
void InitializeNewNode(const DataNode &first_child);
|
void InitializeNewNode(const DataNode &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;
|
|
||||||
|
|
||||||
uint64_t numBytesInThisNode() const override;
|
|
||||||
void resize(uint64_t newsize_bytes) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
ChildEntry *ChildrenBegin();
|
ChildEntry *ChildrenBegin();
|
||||||
|
ChildEntry *ChildrenEnd();
|
||||||
const ChildEntry *ChildrenBegin() const;
|
const ChildEntry *ChildrenBegin() const;
|
||||||
const ChildEntry *ChildrenEnd() const;
|
const ChildEntry *ChildrenEnd() const;
|
||||||
const ChildEntry *RightmostChild() const;
|
|
||||||
|
|
||||||
uint64_t readFromChild(const ChildEntry *child, off_t inner_offset, size_t count, uint8_t *target) const;
|
const ChildEntry *RightmostExistingChild() const;
|
||||||
|
|
||||||
uint32_t numChildren() const;
|
uint32_t numChildren() const;
|
||||||
uint32_t maxNumDataBlocksPerChild() const;
|
|
||||||
uint64_t maxNumBytesPerChild() const;
|
|
||||||
uint64_t numBytesInNonRightmostChildrenSum() const;
|
|
||||||
uint64_t numBytesInRightmostChild() const;
|
|
||||||
const ChildEntry *ChildContainingFirstByteAfterOffset(off_t offset) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include <blobstore/implementations/onblocks/datanodestore/DataLeafNode.h>
|
#include "DataLeafNode.h"
|
||||||
|
|
||||||
using std::unique_ptr;
|
using std::unique_ptr;
|
||||||
using blockstore::Block;
|
using blockstore::Block;
|
||||||
@ -9,53 +9,45 @@ namespace blobstore {
|
|||||||
namespace onblocks {
|
namespace onblocks {
|
||||||
namespace datanodestore {
|
namespace datanodestore {
|
||||||
|
|
||||||
DataLeafNode::DataLeafNode(DataNodeView view, const Key &key, DataNodeStore *nodestorage)
|
DataLeafNode::DataLeafNode(DataNodeView view, const Key &key)
|
||||||
: DataNode(std::move(view), key, nodestorage) {
|
: DataNode(std::move(view), key) {
|
||||||
assert(numBytesInThisNode() <= MAX_STORED_BYTES);
|
assert(numBytes() <= MAX_STORED_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
DataLeafNode::~DataLeafNode() {
|
DataLeafNode::~DataLeafNode() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataLeafNode::read(off_t offset, size_t count, Data *result) const {
|
|
||||||
assert(count <= result->size());
|
|
||||||
assert(offset+count <= numBytesInThisNode());
|
|
||||||
std::memcpy(result->data(), node().DataBegin<unsigned char>()+offset, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataLeafNode::write(off_t offset, size_t count, const Data &data) {
|
|
||||||
assert(count <= data.size());
|
|
||||||
assert(offset+count <= numBytesInThisNode());
|
|
||||||
std::memcpy(node().DataBegin<unsigned char>()+offset, data.data(), count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataLeafNode::InitializeNewNode() {
|
void DataLeafNode::InitializeNewNode() {
|
||||||
*node().Depth() = 0;
|
*node().Depth() = 0;
|
||||||
*node().Size() = 0;
|
*node().Size() = 0;
|
||||||
//fillDataWithZeroes(); not needed, because a newly created block will be zeroed out. DataLeafNodeTest.SpaceIsZeroFilledWhenGrowing ensures this.
|
//fillDataWithZeroes(); not needed, because a newly created block will be zeroed out. DataLeafNodeTest.SpaceIsZeroFilledWhenGrowing ensures this.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *DataLeafNode::data() {
|
||||||
|
return const_cast<void*>(const_cast<const DataLeafNode*>(this)->data());
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *DataLeafNode::data() const {
|
||||||
|
return node().DataBegin<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DataLeafNode::numBytes() const {
|
||||||
|
return *node().Size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataLeafNode::resize(uint32_t new_size) {
|
||||||
|
assert(new_size <= MAX_STORED_BYTES);
|
||||||
|
uint32_t old_size = *node().Size();
|
||||||
|
if (new_size < old_size) {
|
||||||
|
fillDataWithZeroesFromTo(new_size, old_size);
|
||||||
|
}
|
||||||
|
*node().Size() = new_size;
|
||||||
|
}
|
||||||
|
|
||||||
void DataLeafNode::fillDataWithZeroesFromTo(off_t begin, off_t end) {
|
void DataLeafNode::fillDataWithZeroesFromTo(off_t begin, off_t end) {
|
||||||
std::memset(node().DataBegin<unsigned char>()+begin, 0, end-begin);
|
std::memset(node().DataBegin<unsigned char>()+begin, 0, end-begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t DataLeafNode::numBytesInThisNode() const {
|
|
||||||
return *node().Size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataLeafNode::resize(uint64_t newsize_bytes) {
|
|
||||||
assert(newsize_bytes <= MAX_STORED_BYTES);
|
|
||||||
|
|
||||||
// If we're shrinking, we want to delete the old data
|
|
||||||
// (overwrite it with zeroes).
|
|
||||||
// TODO Mention this in thesis
|
|
||||||
if (newsize_bytes < *node().Size()) {
|
|
||||||
fillDataWithZeroesFromTo(newsize_bytes, *node().Size());
|
|
||||||
}
|
|
||||||
|
|
||||||
*node().Size() = newsize_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#ifndef BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATANODESTORE_DATALEAFNODE_H_
|
#ifndef BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATANODESTORE_DATALEAFNODE_H_
|
||||||
#define BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATANODESTORE_DATALEAFNODE_H_
|
#define BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATANODESTORE_DATALEAFNODE_H_
|
||||||
|
|
||||||
#include <blobstore/implementations/onblocks/datanodestore/DataNode.h>
|
#include "DataNode.h"
|
||||||
|
|
||||||
namespace blobstore {
|
namespace blobstore {
|
||||||
namespace onblocks {
|
namespace onblocks {
|
||||||
@ -10,18 +10,19 @@ namespace datanodestore {
|
|||||||
|
|
||||||
class DataLeafNode: public DataNode {
|
class DataLeafNode: public DataNode {
|
||||||
public:
|
public:
|
||||||
DataLeafNode(DataNodeView block, const blockstore::Key &key, DataNodeStore *nodestorage);
|
DataLeafNode(DataNodeView block, const blockstore::Key &key);
|
||||||
virtual ~DataLeafNode();
|
virtual ~DataLeafNode();
|
||||||
|
|
||||||
static constexpr uint32_t MAX_STORED_BYTES = DataNodeView::DATASIZE_BYTES;
|
static constexpr uint32_t MAX_STORED_BYTES = DataNodeView::DATASIZE_BYTES;
|
||||||
|
|
||||||
void InitializeNewNode();
|
void InitializeNewNode();
|
||||||
|
|
||||||
void read(off_t offset, size_t count, blockstore::Data *result) const override;
|
void *data();
|
||||||
void write(off_t offset, size_t count, const blockstore::Data &data) override;
|
const void *data() const;
|
||||||
|
|
||||||
uint64_t numBytesInThisNode() const override;
|
uint32_t numBytes() const;
|
||||||
void resize(uint64_t newsize_bytes) override;
|
|
||||||
|
void resize(uint32_t size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void fillDataWithZeroesFromTo(off_t begin, off_t end);
|
void fillDataWithZeroesFromTo(off_t begin, off_t end);
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
#include "DataInnerNode.h"
|
#include "DataInnerNode.h"
|
||||||
#include <blobstore/implementations/onblocks/datanodestore/DataInnerNode.h>
|
#include "DataLeafNode.h"
|
||||||
#include <blobstore/implementations/onblocks/datanodestore/DataLeafNode.h>
|
#include "DataNode.h"
|
||||||
#include <blobstore/implementations/onblocks/datanodestore/DataNode.h>
|
#include "DataNodeStore.h"
|
||||||
#include <blobstore/implementations/onblocks/datanodestore/DataNodeStore.h>
|
|
||||||
|
|
||||||
using blockstore::Block;
|
using blockstore::Block;
|
||||||
using blockstore::Key;
|
using blockstore::Key;
|
||||||
@ -15,21 +14,13 @@ namespace blobstore {
|
|||||||
namespace onblocks {
|
namespace onblocks {
|
||||||
namespace datanodestore {
|
namespace datanodestore {
|
||||||
|
|
||||||
DataNode::DataNode(DataNodeView node, const Key &key, DataNodeStore *nodestorage)
|
DataNode::DataNode(DataNodeView node, const Key &key)
|
||||||
: _key(key), _node(std::move(node)), _nodestorage(nodestorage) {
|
: _key(key), _node(std::move(node)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DataNode::~DataNode() {
|
DataNode::~DataNode() {
|
||||||
}
|
}
|
||||||
|
|
||||||
DataNodeStore &DataNode::storage() {
|
|
||||||
return const_cast<DataNodeStore&>(const_cast<const DataNode*>(this)->storage());
|
|
||||||
}
|
|
||||||
|
|
||||||
const DataNodeStore &DataNode::storage() const {
|
|
||||||
return *_nodestorage;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataNodeView &DataNode::node() {
|
DataNodeView &DataNode::node() {
|
||||||
return const_cast<DataNodeView&>(const_cast<const DataNode*>(this)->node());
|
return const_cast<DataNodeView&>(const_cast<const DataNode*>(this)->node());
|
||||||
}
|
}
|
||||||
@ -43,9 +34,10 @@ const Key &DataNode::key() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t DataNode::depth() const {
|
uint8_t DataNode::depth() const {
|
||||||
return *_node.Depth();
|
return *node().Depth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#ifndef BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATANODESTORE_DATANODE_H_
|
#ifndef BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATANODESTORE_DATANODE_H_
|
||||||
#define BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATANODESTORE_DATANODE_H_
|
#define BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATANODESTORE_DATANODE_H_
|
||||||
|
|
||||||
#include <blobstore/implementations/onblocks/datanodestore/DataNodeView.h>
|
#include "DataNodeView.h"
|
||||||
#include "blockstore/utils/Data.h"
|
#include "blockstore/utils/Data.h"
|
||||||
|
|
||||||
namespace blobstore {
|
namespace blobstore {
|
||||||
@ -14,21 +14,12 @@ class DataNode {
|
|||||||
public:
|
public:
|
||||||
virtual ~DataNode();
|
virtual ~DataNode();
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
virtual void resize(uint64_t newsize_bytes) = 0;
|
|
||||||
virtual uint64_t numBytesInThisNode() const = 0;
|
|
||||||
|
|
||||||
const blockstore::Key &key() const;
|
const blockstore::Key &key() const;
|
||||||
|
|
||||||
uint8_t depth() const;
|
uint8_t depth() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
DataNode(DataNodeView block, const blockstore::Key &key, DataNodeStore *nodestorage);
|
DataNode(DataNodeView block, const blockstore::Key &key);
|
||||||
|
|
||||||
DataNodeStore &storage();
|
|
||||||
const DataNodeStore &storage() const;
|
|
||||||
|
|
||||||
DataNodeView &node();
|
DataNodeView &node();
|
||||||
const DataNodeView &node() const;
|
const DataNodeView &node() const;
|
||||||
@ -36,7 +27,6 @@ protected:
|
|||||||
private:
|
private:
|
||||||
blockstore::Key _key; //TODO Remove this and make blockstore::Block store the key
|
blockstore::Key _key; //TODO Remove this and make blockstore::Block store the key
|
||||||
DataNodeView _node;
|
DataNodeView _node;
|
||||||
DataNodeStore *_nodestorage;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(DataNode);
|
DISALLOW_COPY_AND_ASSIGN(DataNode);
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include <blobstore/implementations/onblocks/datanodestore/DataInnerNode.h>
|
#include "DataInnerNode.h"
|
||||||
#include <blobstore/implementations/onblocks/datanodestore/DataLeafNode.h>
|
#include "DataLeafNode.h"
|
||||||
#include <blobstore/implementations/onblocks/datanodestore/DataNodeStore.h>
|
#include "DataNodeStore.h"
|
||||||
#include "blockstore/interface/BlockStore.h"
|
#include "blockstore/interface/BlockStore.h"
|
||||||
#include "blockstore/interface/Block.h"
|
#include "blockstore/interface/Block.h"
|
||||||
|
|
||||||
@ -27,9 +27,9 @@ unique_ptr<DataNode> DataNodeStore::load(unique_ptr<Block> block, const Key &key
|
|||||||
DataNodeView node(std::move(block));
|
DataNodeView node(std::move(block));
|
||||||
|
|
||||||
if (*node.Depth() == 0) {
|
if (*node.Depth() == 0) {
|
||||||
return unique_ptr<DataLeafNode>(new DataLeafNode(std::move(node), key, this));
|
return unique_ptr<DataLeafNode>(new DataLeafNode(std::move(node), key));
|
||||||
} else if (*node.Depth() <= MAX_DEPTH) {
|
} else if (*node.Depth() <= MAX_DEPTH) {
|
||||||
return unique_ptr<DataInnerNode>(new DataInnerNode(std::move(node), key, this));
|
return unique_ptr<DataInnerNode>(new DataInnerNode(std::move(node), key));
|
||||||
} else {
|
} else {
|
||||||
throw runtime_error("Tree is to deep. Data corruption?");
|
throw runtime_error("Tree is to deep. Data corruption?");
|
||||||
}
|
}
|
||||||
@ -37,14 +37,14 @@ unique_ptr<DataNode> DataNodeStore::load(unique_ptr<Block> block, const Key &key
|
|||||||
|
|
||||||
unique_ptr<DataInnerNode> DataNodeStore::createNewInnerNode(const DataNode &first_child) {
|
unique_ptr<DataInnerNode> DataNodeStore::createNewInnerNode(const DataNode &first_child) {
|
||||||
auto block = _blockstore->create(DataNodeView::BLOCKSIZE_BYTES);
|
auto block = _blockstore->create(DataNodeView::BLOCKSIZE_BYTES);
|
||||||
auto newNode = make_unique<DataInnerNode>(std::move(block.block), block.key, this);
|
auto newNode = make_unique<DataInnerNode>(std::move(block.block), block.key);
|
||||||
newNode->InitializeNewNode(first_child);
|
newNode->InitializeNewNode(first_child);
|
||||||
return std::move(newNode);
|
return std::move(newNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ptr<DataLeafNode> DataNodeStore::createNewLeafNode() {
|
unique_ptr<DataLeafNode> DataNodeStore::createNewLeafNode() {
|
||||||
auto block = _blockstore->create(DataNodeView::BLOCKSIZE_BYTES);
|
auto block = _blockstore->create(DataNodeView::BLOCKSIZE_BYTES);
|
||||||
auto newNode = make_unique<DataLeafNode>(std::move(block.block), block.key, this);
|
auto newNode = make_unique<DataLeafNode>(std::move(block.block), block.key);
|
||||||
newNode->InitializeNewNode();
|
newNode->InitializeNewNode();
|
||||||
return std::move(newNode);
|
return std::move(newNode);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
#include <blobstore/implementations/onblocks/datanodestore/DataNodeStore.h>
|
#include <blobstore/implementations/onblocks/datanodestore/DataNodeStore.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "fspp/utils/pointer.h"
|
||||||
|
|
||||||
#include "blockstore/implementations/testfake/FakeBlockStore.h"
|
#include "blockstore/implementations/testfake/FakeBlockStore.h"
|
||||||
#include "blockstore/implementations/testfake/FakeBlock.h"
|
#include "blockstore/implementations/testfake/FakeBlock.h"
|
||||||
#include "blobstore/implementations/onblocks/BlobStoreOnBlocks.h"
|
#include "blobstore/implementations/onblocks/BlobStoreOnBlocks.h"
|
||||||
@ -15,6 +17,8 @@ using std::unique_ptr;
|
|||||||
using std::make_unique;
|
using std::make_unique;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
|
using fspp::dynamic_pointer_move;
|
||||||
|
|
||||||
using blockstore::BlockStore;
|
using blockstore::BlockStore;
|
||||||
using blockstore::BlockWithKey;
|
using blockstore::BlockWithKey;
|
||||||
using blockstore::Data;
|
using blockstore::Data;
|
||||||
@ -47,23 +51,22 @@ public:
|
|||||||
Key WriteDataToNewLeafBlockAndReturnKey() {
|
Key WriteDataToNewLeafBlockAndReturnKey() {
|
||||||
auto newleaf = nodeStore->createNewLeafNode();
|
auto newleaf = nodeStore->createNewLeafNode();
|
||||||
newleaf->resize(randomData.size());
|
newleaf->resize(randomData.size());
|
||||||
newleaf->write(0, randomData.size(), randomData);
|
std::memcpy(newleaf->data(), randomData.data(), randomData.size());
|
||||||
return newleaf->key();
|
return newleaf->key();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FillLeafBlockWithData() {
|
void FillLeafBlockWithData() {
|
||||||
leaf->resize(randomData.size());
|
leaf->resize(randomData.size());
|
||||||
leaf->write(0, randomData.size(), randomData);
|
std::memcpy(leaf->data(), randomData.data(), randomData.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadDataFromLoadedLeafBlock(Key key, Data *data) {
|
unique_ptr<DataLeafNode> LoadLeafNode(const Key &key) {
|
||||||
auto leaf = nodeStore->load(key);
|
auto leaf = nodeStore->load(key);
|
||||||
EXPECT_IS_PTR_TYPE(DataLeafNode, leaf.get());
|
return dynamic_pointer_move<DataLeafNode>(leaf);
|
||||||
leaf->read(0, data->size(), data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResizeLeaf(const Key &key, size_t size) {
|
void ResizeLeaf(const Key &key, size_t size) {
|
||||||
auto leaf = nodeStore->load(key);
|
auto leaf = LoadLeafNode(key);
|
||||||
EXPECT_IS_PTR_TYPE(DataLeafNode, leaf.get());
|
EXPECT_IS_PTR_TYPE(DataLeafNode, leaf.get());
|
||||||
leaf->resize(size);
|
leaf->resize(size);
|
||||||
}
|
}
|
||||||
@ -78,42 +81,33 @@ public:
|
|||||||
|
|
||||||
TEST_F(DataLeafNodeTest, InitializesCorrectly) {
|
TEST_F(DataLeafNodeTest, InitializesCorrectly) {
|
||||||
leaf->InitializeNewNode();
|
leaf->InitializeNewNode();
|
||||||
EXPECT_EQ(0u, leaf->numBytesInThisNode());
|
EXPECT_EQ(0u, leaf->numBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataLeafNodeTest, ReinitializesCorrectly) {
|
TEST_F(DataLeafNodeTest, ReinitializesCorrectly) {
|
||||||
leaf->resize(5);
|
leaf->resize(5);
|
||||||
leaf->InitializeNewNode();
|
leaf->InitializeNewNode();
|
||||||
EXPECT_EQ(0u, leaf->numBytesInThisNode());
|
EXPECT_EQ(0u, leaf->numBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataLeafNodeTest, ReadWrittenDataImmediately) {
|
TEST_F(DataLeafNodeTest, ReadWrittenDataAfterReloadingBlock) {
|
||||||
leaf->resize(randomData.size());
|
|
||||||
leaf->write(0, randomData.size(), randomData);
|
|
||||||
|
|
||||||
Data read(DataLeafNode::MAX_STORED_BYTES);
|
|
||||||
leaf->read(0, read.size(), &read);
|
|
||||||
EXPECT_EQ(0, std::memcmp(randomData.data(), read.data(), randomData.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataLeafNodeTest, ReadWrittenDataAfterReloadingBLock) {
|
|
||||||
Key key = WriteDataToNewLeafBlockAndReturnKey();
|
Key key = WriteDataToNewLeafBlockAndReturnKey();
|
||||||
|
|
||||||
Data data(DataLeafNode::MAX_STORED_BYTES);
|
auto loaded = LoadLeafNode(key);
|
||||||
ReadDataFromLoadedLeafBlock(key, &data);
|
|
||||||
|
|
||||||
EXPECT_EQ(0, std::memcmp(randomData.data(), data.data(), randomData.size()));
|
EXPECT_EQ(randomData.size(), loaded->numBytes());
|
||||||
|
EXPECT_EQ(0, std::memcmp(randomData.data(), loaded->data(), randomData.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataLeafNodeTest, NewLeafNodeHasSizeZero) {
|
TEST_F(DataLeafNodeTest, NewLeafNodeHasSizeZero) {
|
||||||
EXPECT_EQ(0u, leaf->numBytesInThisNode());
|
EXPECT_EQ(0u, leaf->numBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataLeafNodeTest, NewLeafNodeHasSizeZero_AfterLoading) {
|
TEST_F(DataLeafNodeTest, NewLeafNodeHasSizeZero_AfterLoading) {
|
||||||
Key key = nodeStore->createNewLeafNode()->key();
|
Key key = nodeStore->createNewLeafNode()->key();
|
||||||
auto leaf = nodeStore->load(key);
|
auto leaf = LoadLeafNode(key);
|
||||||
|
|
||||||
EXPECT_EQ(0u, leaf->numBytesInThisNode());
|
EXPECT_EQ(0u, leaf->numBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
class DataLeafNodeSizeTest: public DataLeafNodeTest, public WithParamInterface<unsigned int> {
|
class DataLeafNodeSizeTest: public DataLeafNodeTest, public WithParamInterface<unsigned int> {
|
||||||
@ -128,22 +122,19 @@ INSTANTIATE_TEST_CASE_P(DataLeafNodeSizeTest, DataLeafNodeSizeTest, Values(0, 1,
|
|||||||
|
|
||||||
TEST_P(DataLeafNodeSizeTest, ResizeNode_ReadSizeImmediately) {
|
TEST_P(DataLeafNodeSizeTest, ResizeNode_ReadSizeImmediately) {
|
||||||
leaf->resize(GetParam());
|
leaf->resize(GetParam());
|
||||||
EXPECT_EQ(GetParam(), leaf->numBytesInThisNode());
|
EXPECT_EQ(GetParam(), leaf->numBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(DataLeafNodeSizeTest, ResizeNode_ReadSizeAfterLoading) {
|
TEST_P(DataLeafNodeSizeTest, ResizeNode_ReadSizeAfterLoading) {
|
||||||
Key key = CreateLeafResizeItAndReturnKey();
|
Key key = CreateLeafResizeItAndReturnKey();
|
||||||
|
|
||||||
auto leaf = nodeStore->load(key);
|
auto leaf = LoadLeafNode(key);
|
||||||
EXPECT_EQ(GetParam(), leaf->numBytesInThisNode());
|
EXPECT_EQ(GetParam(), leaf->numBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataLeafNodeTest, SpaceIsZeroFilledWhenGrowing) {
|
TEST_F(DataLeafNodeTest, SpaceIsZeroFilledWhenGrowing) {
|
||||||
leaf->resize(randomData.size());
|
leaf->resize(randomData.size());
|
||||||
|
EXPECT_EQ(0, std::memcmp(ZEROES.data(), leaf->data(), randomData.size()));
|
||||||
Data read(randomData.size());
|
|
||||||
leaf->read(0, read.size(), &read);
|
|
||||||
EXPECT_EQ(0, std::memcmp(ZEROES.data(), read.data(), read.size()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataLeafNodeTest, SpaceGetsZeroFilledWhenShrinkingAndRegrowing) {
|
TEST_F(DataLeafNodeTest, SpaceGetsZeroFilledWhenShrinkingAndRegrowing) {
|
||||||
@ -154,9 +145,7 @@ TEST_F(DataLeafNodeTest, SpaceGetsZeroFilledWhenShrinkingAndRegrowing) {
|
|||||||
leaf->resize(randomData.size());
|
leaf->resize(randomData.size());
|
||||||
|
|
||||||
//Check that the space was filled with zeroes
|
//Check that the space was filled with zeroes
|
||||||
Data read(100);
|
EXPECT_EQ(0, std::memcmp(ZEROES.data(), ((uint8_t*)leaf->data())+smaller_size, 100));
|
||||||
leaf->read(smaller_size, read.size(), &read);
|
|
||||||
EXPECT_EQ(0, std::memcmp(ZEROES.data(), read.data(), read.size()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataLeafNodeTest, DataGetsZeroFilledWhenShrinking) {
|
TEST_F(DataLeafNodeTest, DataGetsZeroFilledWhenShrinking) {
|
||||||
@ -171,11 +160,27 @@ TEST_F(DataLeafNodeTest, DataGetsZeroFilledWhenShrinking) {
|
|||||||
//After shrinking, we expect there to be zeroes in the underlying data block
|
//After shrinking, we expect there to be zeroes in the underlying data block
|
||||||
ResizeLeaf(key, smaller_size);
|
ResizeLeaf(key, smaller_size);
|
||||||
{
|
{
|
||||||
auto block = blockStore->load(leaf->key());
|
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()+DataNodeView::HEADERSIZE_BYTES+smaller_size, 100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DataLeafNodeTest, ShrinkingDoesntDestroyValidDataRegion) {
|
||||||
|
FillLeafBlockWithData();
|
||||||
|
uint32_t smaller_size = randomData.size() - 100;
|
||||||
|
leaf->resize(smaller_size);
|
||||||
|
|
||||||
|
//Check that the remaining data region is unchanged
|
||||||
|
EXPECT_EQ(0, std::memcmp(randomData.data(), leaf->data(), smaller_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following test cases test reading/writing part of a leaf. This doesn't make much sense,
|
||||||
|
* since the new leaf abstraction doesn't offer read()/write() anymore, but direct data pointer access.
|
||||||
|
* However, these test cases might make sense wherever the read()/write() for a leaf will be implemented.
|
||||||
|
* In case they're not needed then, delete them.
|
||||||
|
|
||||||
struct DataRange {
|
struct DataRange {
|
||||||
DataRange(size_t leafsize_, off_t offset_, size_t count_): leafsize(leafsize_), offset(offset_), count(count_) {}
|
DataRange(size_t leafsize_, off_t offset_, size_t count_): leafsize(leafsize_), offset(offset_), count(count_) {}
|
||||||
size_t leafsize;
|
size_t leafsize;
|
||||||
@ -262,8 +267,8 @@ TEST_P(DataLeafNodeDataTest, OverwriteAndRead) {
|
|||||||
leaf->resize(GetParam().leafsize);
|
leaf->resize(GetParam().leafsize);
|
||||||
leaf->write(0, GetParam().leafsize, this->backgroundData);
|
leaf->write(0, GetParam().leafsize, this->backgroundData);
|
||||||
leaf->write(GetParam().offset, GetParam().count, this->foregroundData);
|
leaf->write(GetParam().offset, GetParam().count, this->foregroundData);
|
||||||
|
|
||||||
EXPECT_DATA_READS_AS(this->foregroundData, *leaf, GetParam().offset, GetParam().count);
|
EXPECT_DATA_READS_AS(this->foregroundData, *leaf, GetParam().offset, GetParam().count);
|
||||||
EXPECT_DATA_READS_AS_OUTSIDE_OF(this->backgroundData, *leaf, GetParam().offset, GetParam().count);
|
EXPECT_DATA_READS_AS_OUTSIDE_OF(this->backgroundData, *leaf, GetParam().offset, GetParam().count);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user