A block stores its key
This commit is contained in:
parent
f4398dfeec
commit
196b543cbb
@ -14,13 +14,13 @@ using std::ios;
|
||||
namespace blockstore {
|
||||
namespace inmemory {
|
||||
|
||||
InMemoryBlock::InMemoryBlock(size_t size)
|
||||
: _data(make_shared<Data>(size)) {
|
||||
InMemoryBlock::InMemoryBlock(const Key &key, size_t size)
|
||||
: Block(key), _data(make_shared<Data>(size)) {
|
||||
_data->FillWithZeroes();
|
||||
}
|
||||
|
||||
InMemoryBlock::InMemoryBlock(const InMemoryBlock &rhs)
|
||||
: _data(rhs._data) {
|
||||
: Block(rhs), _data(rhs._data) {
|
||||
}
|
||||
|
||||
InMemoryBlock::~InMemoryBlock() {
|
||||
|
@ -11,7 +11,7 @@ class InMemoryBlockStore;
|
||||
|
||||
class InMemoryBlock: public Block {
|
||||
public:
|
||||
InMemoryBlock(size_t size);
|
||||
InMemoryBlock(const Key &key, size_t size);
|
||||
InMemoryBlock(const InMemoryBlock &rhs);
|
||||
virtual ~InMemoryBlock();
|
||||
|
||||
|
@ -6,6 +6,8 @@ using std::make_unique;
|
||||
using std::string;
|
||||
using std::mutex;
|
||||
using std::lock_guard;
|
||||
using std::piecewise_construct;
|
||||
using std::make_tuple;
|
||||
|
||||
namespace blockstore {
|
||||
namespace inmemory {
|
||||
@ -14,7 +16,7 @@ InMemoryBlockStore::InMemoryBlockStore()
|
||||
: _blocks() {}
|
||||
|
||||
unique_ptr<Block> InMemoryBlockStore::create(const Key &key, size_t size) {
|
||||
auto insert_result = _blocks.emplace(key.ToString(), size);
|
||||
auto insert_result = _blocks.emplace(piecewise_construct, make_tuple(key.ToString()), make_tuple(key, size));
|
||||
|
||||
if (!insert_result.second) {
|
||||
return nullptr;
|
||||
|
@ -19,12 +19,12 @@ namespace bf = boost::filesystem;
|
||||
namespace blockstore {
|
||||
namespace ondisk {
|
||||
|
||||
OnDiskBlock::OnDiskBlock(const bf::path &filepath, size_t size)
|
||||
: _filepath(filepath), _data(size) {
|
||||
OnDiskBlock::OnDiskBlock(const Key &key, const bf::path &filepath, size_t size)
|
||||
: Block(key), _filepath(filepath), _data(size) {
|
||||
}
|
||||
|
||||
OnDiskBlock::OnDiskBlock(const bf::path &filepath, Data &&data)
|
||||
: _filepath(filepath), _data(std::move(data)) {
|
||||
OnDiskBlock::OnDiskBlock(const Key &key, const bf::path &filepath, Data &&data)
|
||||
: Block(key), _filepath(filepath), _data(std::move(data)) {
|
||||
}
|
||||
|
||||
OnDiskBlock::~OnDiskBlock() {
|
||||
@ -43,7 +43,8 @@ size_t OnDiskBlock::size() const {
|
||||
return _data.size();
|
||||
}
|
||||
|
||||
unique_ptr<OnDiskBlock> OnDiskBlock::LoadFromDisk(const bf::path &filepath) {
|
||||
unique_ptr<OnDiskBlock> OnDiskBlock::LoadFromDisk(const bf::path &rootdir, const Key &key) {
|
||||
auto filepath = rootdir / key.ToString();
|
||||
try {
|
||||
//If it isn't a file, Data::LoadFromFile() would usually also crash. We still need this extra check
|
||||
//upfront, because Data::LoadFromFile() doesn't crash if we give it the path of a directory
|
||||
@ -52,18 +53,19 @@ unique_ptr<OnDiskBlock> OnDiskBlock::LoadFromDisk(const bf::path &filepath) {
|
||||
return nullptr;
|
||||
}
|
||||
Data data = Data::LoadFromFile(filepath);
|
||||
return unique_ptr<OnDiskBlock>(new OnDiskBlock(filepath, std::move(data)));
|
||||
return unique_ptr<OnDiskBlock>(new OnDiskBlock(key, filepath, std::move(data)));
|
||||
} catch (const FileDoesntExistException &e) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<OnDiskBlock> OnDiskBlock::CreateOnDisk(const bf::path &filepath, size_t size) {
|
||||
unique_ptr<OnDiskBlock> OnDiskBlock::CreateOnDisk(const bf::path &rootdir, const Key &key, size_t size) {
|
||||
auto filepath = rootdir / key.ToString();
|
||||
if (bf::exists(filepath)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto block = unique_ptr<OnDiskBlock>(new OnDiskBlock(filepath, size));
|
||||
auto block = unique_ptr<OnDiskBlock>(new OnDiskBlock(key, filepath, size));
|
||||
block->_fillDataWithZeroes();
|
||||
block->_storeToDisk();
|
||||
return block;
|
||||
|
@ -17,8 +17,8 @@ class OnDiskBlock: public Block {
|
||||
public:
|
||||
virtual ~OnDiskBlock();
|
||||
|
||||
static std::unique_ptr<OnDiskBlock> LoadFromDisk(const boost::filesystem::path &filepath);
|
||||
static std::unique_ptr<OnDiskBlock> CreateOnDisk(const boost::filesystem::path &filepath, size_t size);
|
||||
static std::unique_ptr<OnDiskBlock> LoadFromDisk(const boost::filesystem::path &rootdir, const Key &key);
|
||||
static std::unique_ptr<OnDiskBlock> CreateOnDisk(const boost::filesystem::path &rootdir, const Key &key, size_t size);
|
||||
|
||||
void *data() override;
|
||||
const void *data() const override;
|
||||
@ -31,8 +31,8 @@ private:
|
||||
const boost::filesystem::path _filepath;
|
||||
Data _data;
|
||||
|
||||
OnDiskBlock(const boost::filesystem::path &filepath, size_t size);
|
||||
OnDiskBlock(const boost::filesystem::path &filepath, Data &&data);
|
||||
OnDiskBlock(const Key &key, const boost::filesystem::path &filepath, size_t size);
|
||||
OnDiskBlock(const Key &key, const boost::filesystem::path &filepath, Data &&data);
|
||||
|
||||
void _fillDataWithZeroes();
|
||||
void _storeToDisk() const;
|
||||
|
@ -16,8 +16,7 @@ OnDiskBlockStore::OnDiskBlockStore(const boost::filesystem::path &rootdir)
|
||||
: _rootdir(rootdir) {}
|
||||
|
||||
unique_ptr<Block> OnDiskBlockStore::create(const Key &key, size_t size) {
|
||||
auto file_path = _rootdir / key.ToString();
|
||||
auto block = OnDiskBlock::CreateOnDisk(file_path, size);
|
||||
auto block = OnDiskBlock::CreateOnDisk(_rootdir, key, size);
|
||||
|
||||
if (!block) {
|
||||
return nullptr;
|
||||
@ -26,8 +25,7 @@ unique_ptr<Block> OnDiskBlockStore::create(const Key &key, size_t size) {
|
||||
}
|
||||
|
||||
unique_ptr<Block> OnDiskBlockStore::load(const Key &key) {
|
||||
auto file_path = _rootdir / key.ToString();
|
||||
return OnDiskBlock::LoadFromDisk(file_path);
|
||||
return OnDiskBlock::LoadFromDisk(_rootdir, key);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ using std::string;
|
||||
namespace blockstore {
|
||||
namespace testfake {
|
||||
|
||||
FakeBlock::FakeBlock(FakeBlockStore *store, const string &key, shared_ptr<Data> data)
|
||||
: _store(store), _key(key), _data(data) {
|
||||
FakeBlock::FakeBlock(FakeBlockStore *store, const Key &key, shared_ptr<Data> data)
|
||||
: Block(key), _store(store), _data(data) {
|
||||
}
|
||||
|
||||
FakeBlock::~FakeBlock() {
|
||||
@ -35,7 +35,7 @@ size_t FakeBlock::size() const {
|
||||
}
|
||||
|
||||
void FakeBlock::flush() {
|
||||
_store->updateData(_key, *_data);
|
||||
_store->updateData(key(), *_data);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ class FakeBlockStore;
|
||||
|
||||
class FakeBlock: public Block {
|
||||
public:
|
||||
FakeBlock(FakeBlockStore *store, const std::string &key, std::shared_ptr<Data> data);
|
||||
FakeBlock(FakeBlockStore *store, const Key &key, std::shared_ptr<Data> data);
|
||||
virtual ~FakeBlock();
|
||||
|
||||
void *data() override;
|
||||
@ -25,7 +25,6 @@ public:
|
||||
|
||||
private:
|
||||
FakeBlockStore *_store;
|
||||
const std::string _key;
|
||||
std::shared_ptr<Data> _data;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FakeBlock);
|
||||
|
@ -30,20 +30,20 @@ unique_ptr<Block> FakeBlockStore::load(const Key &key) {
|
||||
//Return a copy of the stored data
|
||||
string key_string = key.ToString();
|
||||
try {
|
||||
return makeFakeBlockFromData(key_string, _blocks.at(key_string));
|
||||
return makeFakeBlockFromData(key, _blocks.at(key_string));
|
||||
} catch (const std::out_of_range &e) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<Block> FakeBlockStore::makeFakeBlockFromData(const std::string &key, const Data &data) {
|
||||
unique_ptr<Block> FakeBlockStore::makeFakeBlockFromData(const Key &key, const Data &data) {
|
||||
auto newdata = make_shared<Data>(data.copy());
|
||||
_used_dataregions_for_blocks.push_back(newdata);
|
||||
return make_unique<FakeBlock>(this, key, newdata);
|
||||
}
|
||||
|
||||
void FakeBlockStore::updateData(const std::string &key, const Data &data) {
|
||||
Data &stored_data = _blocks.at(key);
|
||||
void FakeBlockStore::updateData(const Key &key, const Data &data) {
|
||||
Data &stored_data = _blocks.at(key.ToString());
|
||||
assert(data.size() == stored_data.size());
|
||||
std::memcpy(stored_data.data(), data.data(), data.size());
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
std::unique_ptr<Block> create(const Key &key, size_t size) override;
|
||||
std::unique_ptr<Block> load(const Key &key) override;
|
||||
|
||||
void updateData(const std::string &key, const Data &data);
|
||||
void updateData(const Key &key, const Data &data);
|
||||
|
||||
private:
|
||||
std::map<std::string, Data> _blocks;
|
||||
@ -46,7 +46,7 @@ private:
|
||||
//We want to avoid this for the reasons mentioned above (overflow data).
|
||||
std::vector<std::shared_ptr<Data>> _used_dataregions_for_blocks;
|
||||
|
||||
std::unique_ptr<Block> makeFakeBlockFromData(const std::string &key, const Data &data);
|
||||
std::unique_ptr<Block> makeFakeBlockFromData(const Key &key, const Data &data);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FakeBlockStore);
|
||||
};
|
||||
|
@ -3,6 +3,7 @@
|
||||
#define BLOCKSTORE_INTERFACE_BLOCK_H_
|
||||
|
||||
#include <cstring>
|
||||
#include "blockstore/utils/Key.h"
|
||||
|
||||
namespace blockstore {
|
||||
|
||||
@ -16,6 +17,16 @@ public:
|
||||
virtual void flush() = 0;
|
||||
|
||||
virtual size_t size() const = 0;
|
||||
|
||||
const Key &key() const {
|
||||
return _key;
|
||||
}
|
||||
|
||||
protected:
|
||||
Block(const Key &key) : _key(key) {}
|
||||
|
||||
private:
|
||||
const Key _key;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "test/testutils/TempFile.h"
|
||||
|
||||
#include "test/testutils/TempDir.h"
|
||||
|
||||
using ::testing::Test;
|
||||
using ::testing::WithParamInterface;
|
||||
@ -20,23 +20,27 @@ class OnDiskBlockCreateTest: public Test {
|
||||
public:
|
||||
OnDiskBlockCreateTest()
|
||||
// Don't create the temp file yet (therefore pass false to the TempFile constructor)
|
||||
: file(false) {
|
||||
: dir(),
|
||||
key(Key::FromString("1491BB4932A389EE14BC7090AC772972")),
|
||||
file(dir.path() / key.ToString(), false) {
|
||||
}
|
||||
TempDir dir;
|
||||
Key key;
|
||||
TempFile file;
|
||||
};
|
||||
|
||||
TEST_F(OnDiskBlockCreateTest, CreatingBlockCreatesFile) {
|
||||
EXPECT_FALSE(bf::exists(file.path()));
|
||||
|
||||
auto block = OnDiskBlock::CreateOnDisk(file.path(), 0);
|
||||
auto block = OnDiskBlock::CreateOnDisk(dir.path(), key, 0);
|
||||
|
||||
EXPECT_TRUE(bf::exists(file.path()));
|
||||
EXPECT_TRUE(bf::is_regular_file(file.path()));
|
||||
}
|
||||
|
||||
TEST_F(OnDiskBlockCreateTest, CreatingExistingBlockReturnsNull) {
|
||||
auto block1 = OnDiskBlock::CreateOnDisk(file.path(), 0);
|
||||
auto block2 = OnDiskBlock::CreateOnDisk(file.path(), 0);
|
||||
auto block1 = OnDiskBlock::CreateOnDisk(dir.path(), key, 0);
|
||||
auto block2 = OnDiskBlock::CreateOnDisk(dir.path(), key, 0);
|
||||
EXPECT_TRUE((bool)block1);
|
||||
EXPECT_FALSE((bool)block2);
|
||||
}
|
||||
@ -47,7 +51,7 @@ public:
|
||||
Data ZEROES;
|
||||
|
||||
OnDiskBlockCreateSizeTest():
|
||||
block(OnDiskBlock::CreateOnDisk(file.path(), GetParam())),
|
||||
block(OnDiskBlock::CreateOnDisk(dir.path(), key, GetParam())),
|
||||
ZEROES(block->size())
|
||||
{
|
||||
ZEROES.FillWithZeroes();
|
||||
@ -56,6 +60,7 @@ public:
|
||||
INSTANTIATE_TEST_CASE_P(OnDiskBlockCreateSizeTest, OnDiskBlockCreateSizeTest, Values(0, 1, 5, 1024, 10*1024*1024));
|
||||
|
||||
TEST_P(OnDiskBlockCreateSizeTest, OnDiskSizeIsCorrect) {
|
||||
printf((std::string()+file.path().c_str()+"\n").c_str());
|
||||
Data fileContent = Data::LoadFromFile(file.path());
|
||||
EXPECT_EQ(GetParam(), fileContent.size());
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "test/testutils/TempFile.h"
|
||||
#include "test/testutils/TempDir.h"
|
||||
|
||||
using ::testing::Test;
|
||||
using ::testing::WithParamInterface;
|
||||
@ -20,21 +21,26 @@ class OnDiskBlockFlushTest: public Test, public WithParamInterface<size_t> {
|
||||
public:
|
||||
OnDiskBlockFlushTest()
|
||||
// Don't create the temp file yet (therefore pass false to the TempFile constructor)
|
||||
: file(false), randomData(GetParam()) {
|
||||
: dir(),
|
||||
key(Key::FromString("1491BB4932A389EE14BC7090AC772972")),
|
||||
file(dir.path() / key.ToString(), false),
|
||||
randomData(GetParam()) {
|
||||
}
|
||||
TempDir dir;
|
||||
Key key;
|
||||
TempFile file;
|
||||
|
||||
DataBlockFixture randomData;
|
||||
|
||||
unique_ptr<OnDiskBlock> CreateBlockAndLoadItFromDisk() {
|
||||
{
|
||||
auto block = OnDiskBlock::CreateOnDisk(file.path(), randomData.size());
|
||||
auto block = OnDiskBlock::CreateOnDisk(dir.path(), key, randomData.size());
|
||||
}
|
||||
return OnDiskBlock::LoadFromDisk(file.path());
|
||||
return OnDiskBlock::LoadFromDisk(dir.path(), key);
|
||||
}
|
||||
|
||||
unique_ptr<OnDiskBlock> CreateBlock() {
|
||||
return OnDiskBlock::CreateOnDisk(file.path(), randomData.size());
|
||||
return OnDiskBlock::CreateOnDisk(dir.path(), key, randomData.size());
|
||||
}
|
||||
|
||||
void WriteDataToBlock(const unique_ptr<OnDiskBlock> &block) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "test/testutils/TempFile.h"
|
||||
#include "test/testutils/TempDir.h"
|
||||
#include <fstream>
|
||||
|
||||
using ::testing::Test;
|
||||
@ -22,6 +23,13 @@ namespace bf = boost::filesystem;
|
||||
|
||||
class OnDiskBlockLoadTest: public Test, public WithParamInterface<size_t> {
|
||||
public:
|
||||
OnDiskBlockLoadTest():
|
||||
dir(),
|
||||
key(Key::FromString("1491BB4932A389EE14BC7090AC772972")),
|
||||
file(dir.path() / key.ToString()) {
|
||||
}
|
||||
TempDir dir;
|
||||
Key key;
|
||||
TempFile file;
|
||||
|
||||
void SetFileSize(size_t size) {
|
||||
@ -37,7 +45,7 @@ public:
|
||||
}
|
||||
|
||||
unique_ptr<OnDiskBlock> LoadBlock() {
|
||||
return OnDiskBlock::LoadFromDisk(file.path());
|
||||
return OnDiskBlock::LoadFromDisk(dir.path(), key);
|
||||
}
|
||||
|
||||
void EXPECT_BLOCK_DATA_EQ(const DataBlockFixture &expected, const OnDiskBlock &actual) {
|
||||
@ -65,8 +73,8 @@ TEST_P(OnDiskBlockLoadTest, LoadedDataIsCorrect) {
|
||||
}
|
||||
|
||||
TEST_F(OnDiskBlockLoadTest, LoadNotExistingBlock) {
|
||||
TempFile file2(false); // Pass false, so the file isn't created.
|
||||
Key key2 = Key::FromString("272EE5517627CFA147A971A8E6E747E0");
|
||||
EXPECT_FALSE(
|
||||
(bool)OnDiskBlock::LoadFromDisk(file2.path())
|
||||
(bool)OnDiskBlock::LoadFromDisk(dir.path(), key2)
|
||||
);
|
||||
}
|
||||
|
@ -28,10 +28,12 @@ public:
|
||||
|
||||
class BlockMock: public Block {
|
||||
public:
|
||||
BlockMock(): Block(Key::CreateRandomKey()) {}
|
||||
MOCK_METHOD0(data, void*());
|
||||
MOCK_CONST_METHOD0(data, const void*());
|
||||
MOCK_METHOD0(flush, void());
|
||||
MOCK_CONST_METHOD0(size, size_t());
|
||||
MOCK_CONST_METHOD0(key, const Key&());
|
||||
};
|
||||
|
||||
class BlockStoreWithRandomKeysTest: public Test {
|
||||
|
Loading…
x
Reference in New Issue
Block a user