- BlockStore::create() gets the data of the new block as a parameter

- Fixed numBlocks() in OnDiskBlockStore, FakeBlockStore, CachingBlockStore, ...
- CachingBlockStore caches created blocks and doesn't directly create them in the underlying blockstore
This commit is contained in:
Sebastian Meßmer 2015-04-18 14:47:12 +02:00
parent 18e7d68f15
commit 417a701636
34 changed files with 392 additions and 193 deletions

View File

@ -1,4 +1,5 @@
#include "CachedBlock.h"
#include "NewBlock.h"
#include "CachingBlockStore.h"
#include "../../interface/Block.h"
@ -13,15 +14,16 @@ namespace blockstore {
namespace caching {
CachingBlockStore::CachingBlockStore(std::unique_ptr<BlockStore> baseBlockStore)
:_baseBlockStore(std::move(baseBlockStore)) {
:_baseBlockStore(std::move(baseBlockStore)), _cache(), _numNewBlocks(0) {
}
unique_ptr<Block> CachingBlockStore::create(size_t size) {
//TODO Also cache this and only write back in the destructor?
// When writing back is done efficiently in the base store (e.g. only one safe-to-disk, not one in the create() and then one in the save(), this is not supported by the current BlockStore interface),
// then the base store could actually directly create a block in the create() call, OnDiskBlockStore wouldn't have to avoid file creation in the create() call for performance reasons and I could also adapt the OnDiskBlockStore test cases and remove a lot of flush() calls there because then blocks are loadable directly after the create call() without a flush.
// Currently, OnDiskBlockStore doesn't create new blocks directly but only after they're destructed (performance reasons), but this means a newly created block can't be loaded directly.
return make_unique<CachedBlock>(_baseBlockStore->create(size), this);
Key CachingBlockStore::createKey() {
return _baseBlockStore->createKey();
}
unique_ptr<Block> CachingBlockStore::tryCreate(const Key &key, Data data) {
++_numNewBlocks;
return make_unique<CachedBlock>(make_unique<NewBlock>(key, std::move(data), this), this);
}
unique_ptr<Block> CachingBlockStore::load(const Key &key) {
@ -37,16 +39,38 @@ unique_ptr<Block> CachingBlockStore::load(const Key &key) {
}
void CachingBlockStore::remove(std::unique_ptr<Block> block) {
return _baseBlockStore->remove(std::move(dynamic_pointer_move<CachedBlock>(block)->releaseBlock()));
auto baseBlock = dynamic_pointer_move<CachedBlock>(block)->releaseBlock();
auto baseNewBlock = dynamic_pointer_move<NewBlock>(baseBlock);
if (baseNewBlock.get() != nullptr) {
if(!baseNewBlock->alreadyExistsInBaseStore()) {
--_numNewBlocks;
}
baseNewBlock->remove();
} else {
_baseBlockStore->remove(std::move(baseBlock));
}
}
uint64_t CachingBlockStore::numBlocks() const {
return _baseBlockStore->numBlocks();
//TODO Add number of NewBlock instances
return _baseBlockStore->numBlocks() + _numNewBlocks;
}
void CachingBlockStore::release(unique_ptr<Block> block) {
_cache.push(std::move(block));
}
std::unique_ptr<Block> CachingBlockStore::tryCreateInBaseStore(const Key &key, Data data) {
auto block = _baseBlockStore->tryCreate(key, std::move(data));
if (block.get() != nullptr) {
--_numNewBlocks;
}
return block;
}
void CachingBlockStore::removeFromBaseStore(std::unique_ptr<Block> block) {
_baseBlockStore->remove(std::move(block));
}
}
}

View File

@ -14,16 +14,21 @@ class CachingBlockStore: public BlockStore {
public:
CachingBlockStore(std::unique_ptr<BlockStore> baseBlockStore);
std::unique_ptr<Block> create(size_t size) override;
Key createKey() override;
std::unique_ptr<Block> tryCreate(const Key &key, Data data) override;
std::unique_ptr<Block> load(const Key &key) override;
void remove(std::unique_ptr<Block> block) override;
uint64_t numBlocks() const override;
void release(std::unique_ptr<Block> block);
std::unique_ptr<Block> tryCreateInBaseStore(const Key &key, Data data);
void removeFromBaseStore(std::unique_ptr<Block> block);
private:
std::unique_ptr<BlockStore> _baseBlockStore;
Cache _cache;
uint32_t _numNewBlocks;
DISALLOW_COPY_AND_ASSIGN(CachingBlockStore);
};

View File

@ -0,0 +1,66 @@
#include "NewBlock.h"
#include "CachingBlockStore.h"
using std::unique_ptr;
using std::make_unique;
namespace blockstore {
namespace caching {
NewBlock::NewBlock(const Key &key, Data data, CachingBlockStore *blockStore)
:Block(key),
_blockStore(blockStore),
_data(std::move(data)),
_baseBlock(nullptr),
_dataChanged(true) {
}
NewBlock::~NewBlock() {
writeToBaseBlockIfChanged();
}
const void *NewBlock::data() const {
return _data.data();
}
void NewBlock::write(const void *source, uint64_t offset, uint64_t size) {
assert(offset <= _data.size() && offset + size <= _data.size());
std::memcpy((uint8_t*)_data.data()+offset, source, size);
_dataChanged = true;
}
void NewBlock::writeToBaseBlockIfChanged() {
if (_dataChanged) {
if (_baseBlock.get() == nullptr) {
//TODO What if tryCreate fails due to a duplicate key? We should ensure we don't use duplicate keys.
//TODO _data.copy() necessary?
_baseBlock = _blockStore->tryCreateInBaseStore(key(), _data.copy());
} else {
_baseBlock->write(_data.data(), 0, _data.size());
}
_dataChanged = false;
}
}
void NewBlock::remove() {
if (_baseBlock.get() != nullptr) {
_blockStore->removeFromBaseStore(std::move(_baseBlock));
}
_dataChanged = false;
}
void NewBlock::flush() {
writeToBaseBlockIfChanged();
_baseBlock->flush();
}
size_t NewBlock::size() const {
return _data.size();
}
bool NewBlock::alreadyExistsInBaseStore() const {
return _baseBlock.get() != nullptr;
}
}
}

View File

@ -0,0 +1,50 @@
#pragma once
#ifndef BLOCKSTORE_IMPLEMENTATIONS_CACHING_NEWBLOCK_H_
#define BLOCKSTORE_IMPLEMENTATIONS_CACHING_NEWBLOCK_H_
#include "../../interface/BlockStore.h"
#include "../../utils/Data.h"
#include "messmer/cpp-utils/macros.h"
#include <memory>
namespace blockstore {
namespace caching {
class CachingBlockStore;
//TODO Does it make sense to write a general DataBackedBlock that just stores a Data object and maps the block operations to it?
// Can we reuse that object somewhere else?
// Maybe a second abstract class for BlockRefBackedBlock?
// This is a block that was created in CachingBlockStore, but doesn't exist in the base block store yet.
// It only exists in the cache and it is created in the base block store when destructed.
class NewBlock: public Block {
public:
NewBlock(const Key &key, Data data, CachingBlockStore *blockStore);
virtual ~NewBlock();
const void *data() const override;
void write(const void *source, uint64_t offset, uint64_t size) override;
void flush() override;
size_t size() const override;
void remove();
bool alreadyExistsInBaseStore() const;
private:
CachingBlockStore *_blockStore;
Data _data;
std::unique_ptr<Block> _baseBlock;
bool _dataChanged;
void writeToBaseBlockIfChanged();
DISALLOW_COPY_AND_ASSIGN(NewBlock);
};
}
}
#endif

View File

@ -15,11 +15,15 @@ namespace encrypted {
constexpr unsigned int EncryptedBlock::IV_SIZE;
std::unique_ptr<EncryptedBlock> EncryptedBlock::CreateNew(std::unique_ptr<Block> baseBlock, const EncryptionKey &encKey) {
auto block = make_unique<EncryptedBlock>(std::move(baseBlock), encKey);
//We have to explicitly fill the block with zeroes, because otherwise the encrypted version is filled with zeroes and not the plaintext version
utils::fillWithZeroes(block.get());
return block;
std::unique_ptr<EncryptedBlock> EncryptedBlock::TryCreateNew(BlockStore *baseBlockStore, const Key &key, Data data, const EncryptionKey &encKey) {
Data encrypted = _encrypt(data, encKey);
auto baseBlock = baseBlockStore->tryCreate(key, std::move(encrypted));
if (baseBlock.get() == nullptr) {
//TODO Test this code branch
return nullptr;
}
return make_unique<EncryptedBlock>(std::move(baseBlock), encKey);
}
EncryptedBlock::EncryptedBlock(std::unique_ptr<Block> baseBlock, const EncryptionKey &encKey)
@ -32,7 +36,7 @@ EncryptedBlock::EncryptedBlock(std::unique_ptr<Block> baseBlock, const Encryptio
}
EncryptedBlock::~EncryptedBlock() {
flush();
_encryptToBaseBlock();
}
const void *EncryptedBlock::data() const {
@ -63,16 +67,21 @@ void EncryptedBlock::_decryptFromBaseBlock() {
void EncryptedBlock::_encryptToBaseBlock() {
if (_dataChanged) {
FixedSizeData<IV_SIZE> iv = FixedSizeData<IV_SIZE>::CreateRandom();
auto encryption = CFB_Mode<AES>::Encryption(_encKey.data(), EncryptionKey::BINARY_LENGTH, iv.data());
//TODO More performance when not using "Data encrypted" object, but specialized CryptoPP sink
Data encrypted(_plaintextData.size());
encryption.ProcessData((byte*)encrypted.data(), (byte*)_plaintextData.data(), _plaintextData.size());
_baseBlock->write(iv.data(), 0, IV_SIZE);
_baseBlock->write(encrypted.data(), IV_SIZE, encrypted.size());
Data encrypted = _encrypt(_plaintextData, _encKey);
_baseBlock->write(encrypted.data(), 0, encrypted.size());
_dataChanged = false;
}
}
Data EncryptedBlock::_encrypt(const Data &plaintext, const EncryptionKey &encKey) {
FixedSizeData<IV_SIZE> iv = FixedSizeData<IV_SIZE>::CreateRandom();
auto encryption = CFB_Mode<AES>::Encryption(encKey.data(), EncryptionKey::BINARY_LENGTH, iv.data());
//TODO More performance when not using "Data encrypted" object, but encrypting directly to a target that was specified via a parameter using a specialized CryptoPP sink
Data encrypted(IV_SIZE + plaintext.size());
std::memcpy(encrypted.data(), iv.data(), IV_SIZE);
encryption.ProcessData((byte*)encrypted.data() + IV_SIZE, (byte*)plaintext.data(), plaintext.size());
return encrypted;
}
}
}

View File

@ -5,6 +5,7 @@
#include "../../interface/Block.h"
#include "EncryptionKey.h"
#include "../../utils/Data.h"
#include "../../interface/BlockStore.h"
#include "messmer/cpp-utils/macros.h"
#include <memory>
@ -19,7 +20,7 @@ public:
EncryptedBlock(std::unique_ptr<Block> baseBlock, const EncryptionKey &encKey);
virtual ~EncryptedBlock();
static std::unique_ptr<EncryptedBlock> CreateNew(std::unique_ptr<Block>, const EncryptionKey &encKey);
static std::unique_ptr<EncryptedBlock> TryCreateNew(BlockStore *baseBlockStore, const Key &key, Data data, const EncryptionKey &encKey);
const void *data() const override;
void write(const void *source, uint64_t offset, uint64_t size) override;
@ -49,6 +50,8 @@ private:
void _encryptToBaseBlock();
void _decryptFromBaseBlock();
static Data _encrypt(const Data &plaintext, const EncryptionKey &encKey);
DISALLOW_COPY_AND_ASSIGN(EncryptedBlock);
};

View File

@ -13,8 +13,12 @@ EncryptedBlockStore::EncryptedBlockStore(unique_ptr<BlockStore> baseBlockStore,
: _baseBlockStore(std::move(baseBlockStore)), _encKey(encKey) {
}
unique_ptr<Block> EncryptedBlockStore::create(size_t size) {
return EncryptedBlock::CreateNew(_baseBlockStore->create(EncryptedBlock::BASE_BLOCK_SIZE(size)), _encKey);
Key EncryptedBlockStore::createKey() {
return _baseBlockStore->createKey();
}
unique_ptr<Block> EncryptedBlockStore::tryCreate(const Key &key, Data data) {
return EncryptedBlock::TryCreateNew(_baseBlockStore.get(), key, std::move(data), _encKey);
}
unique_ptr<Block> EncryptedBlockStore::load(const Key &key) {
@ -33,5 +37,10 @@ uint64_t EncryptedBlockStore::numBlocks() const {
return _baseBlockStore->numBlocks();
}
unique_ptr<Block> EncryptedBlockStore::tryCreateInBaseStore(const Key &key, Data encryptedData) {
return _baseBlockStore->tryCreate(key, std::move(encryptedData));
}
}
}

View File

@ -13,11 +13,14 @@ class EncryptedBlockStore: public BlockStore {
public:
EncryptedBlockStore(std::unique_ptr<BlockStore> baseBlockStore, const EncryptionKey &encKey);
std::unique_ptr<Block> create(size_t size) override;
Key createKey() override;
std::unique_ptr<Block> tryCreate(const Key &key, Data data) override;
std::unique_ptr<Block> load(const Key &key) override;
void remove(std::unique_ptr<Block> block) override;
uint64_t numBlocks() const override;
std::unique_ptr<Block> tryCreateInBaseStore(const Key &key, Data encryptedData);
private:
std::unique_ptr<BlockStore> _baseBlockStore;
EncryptionKey _encKey;

View File

@ -13,9 +13,8 @@ using std::ios;
namespace blockstore {
namespace inmemory {
InMemoryBlock::InMemoryBlock(const Key &key, size_t size)
: Block(key), _data(make_shared<Data>(size)) {
_data->FillWithZeroes();
InMemoryBlock::InMemoryBlock(const Key &key, Data data)
: Block(key), _data(make_shared<Data>(std::move(data))) {
}
InMemoryBlock::InMemoryBlock(const InMemoryBlock &rhs)

View File

@ -11,7 +11,7 @@ class InMemoryBlockStore;
class InMemoryBlock: public Block {
public:
InMemoryBlock(const Key &key, size_t size);
InMemoryBlock(const Key &key, Data size);
InMemoryBlock(const InMemoryBlock &rhs);
virtual ~InMemoryBlock();

View File

@ -16,8 +16,8 @@ namespace inmemory {
InMemoryBlockStore::InMemoryBlockStore()
: _blocks() {}
unique_ptr<Block> InMemoryBlockStore::create(const Key &key, size_t size) {
auto insert_result = _blocks.emplace(piecewise_construct, make_tuple(key.ToString()), make_tuple(key, size));
unique_ptr<Block> InMemoryBlockStore::tryCreate(const Key &key, Data data) {
auto insert_result = _blocks.emplace(piecewise_construct, make_tuple(key.ToString()), make_tuple(key, std::move(data)));
if (!insert_result.second) {
return nullptr;

View File

@ -16,7 +16,7 @@ class InMemoryBlockStore: public BlockStoreWithRandomKeys {
public:
InMemoryBlockStore();
std::unique_ptr<Block> create(const Key &key, size_t size) override;
std::unique_ptr<Block> tryCreate(const Key &key, Data data) override;
std::unique_ptr<Block> load(const Key &key) override;
void remove(std::unique_ptr<Block> block) override;
uint64_t numBlocks() const override;

View File

@ -19,11 +19,7 @@ namespace bf = boost::filesystem;
namespace blockstore {
namespace ondisk {
OnDiskBlock::OnDiskBlock(const Key &key, const bf::path &filepath, size_t size)
: Block(key), _filepath(filepath), _data(size), _dataChanged(false) {
}
OnDiskBlock::OnDiskBlock(const Key &key, const bf::path &filepath, Data &&data)
OnDiskBlock::OnDiskBlock(const Key &key, const bf::path &filepath, Data data)
: Block(key), _filepath(filepath), _data(std::move(data)), _dataChanged(false) {
}
@ -61,14 +57,14 @@ unique_ptr<OnDiskBlock> OnDiskBlock::LoadFromDisk(const bf::path &rootdir, const
}
}
unique_ptr<OnDiskBlock> OnDiskBlock::CreateOnDisk(const bf::path &rootdir, const Key &key, size_t size) {
unique_ptr<OnDiskBlock> OnDiskBlock::CreateOnDisk(const bf::path &rootdir, const Key &key, Data data) {
auto filepath = rootdir / key.ToString();
if (bf::exists(filepath)) {
return nullptr;
}
auto block = unique_ptr<OnDiskBlock>(new OnDiskBlock(key, filepath, size));
block->_fillDataWithZeroes();
auto block = unique_ptr<OnDiskBlock>(new OnDiskBlock(key, filepath, std::move(data)));
block->_storeToDisk();
return block;
}

View File

@ -18,7 +18,7 @@ public:
virtual ~OnDiskBlock();
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);
static std::unique_ptr<OnDiskBlock> CreateOnDisk(const boost::filesystem::path &rootdir, const Key &key, Data data);
static void RemoveFromDisk(const boost::filesystem::path &rootdir, const Key &key);
const void *data() const override;
@ -33,8 +33,7 @@ private:
Data _data;
bool _dataChanged;
OnDiskBlock(const Key &key, const boost::filesystem::path &filepath, size_t size);
OnDiskBlock(const Key &key, const boost::filesystem::path &filepath, Data &&data);
OnDiskBlock(const Key &key, const boost::filesystem::path &filepath, Data data);
void _fillDataWithZeroes();
void _storeToDisk() const;

View File

@ -13,8 +13,8 @@ namespace ondisk {
OnDiskBlockStore::OnDiskBlockStore(const boost::filesystem::path &rootdir)
: _rootdir(rootdir) {}
unique_ptr<Block> OnDiskBlockStore::create(const Key &key, size_t size) {
auto block = OnDiskBlock::CreateOnDisk(_rootdir, key, size);
unique_ptr<Block> OnDiskBlockStore::tryCreate(const Key &key, Data data) {
auto block = OnDiskBlock::CreateOnDisk(_rootdir, key, std::move(data));
if (!block) {
return nullptr;

View File

@ -14,7 +14,7 @@ class OnDiskBlockStore: public BlockStoreWithRandomKeys {
public:
OnDiskBlockStore(const boost::filesystem::path &rootdir);
std::unique_ptr<Block> create(const Key &key, size_t size) override;
std::unique_ptr<Block> tryCreate(const Key &key, Data data) override;
std::unique_ptr<Block> load(const Key &key) override;
void remove(std::unique_ptr<Block> block) override;
uint64_t numBlocks() const override;

View File

@ -20,9 +20,16 @@ ParallelAccessBlockStore::ParallelAccessBlockStore(unique_ptr<BlockStore> baseBl
: _baseBlockStore(std::move(baseBlockStore)), _parallelAccessStore(make_unique<ParallelAccessBlockStoreAdapter>(_baseBlockStore.get())) {
}
unique_ptr<Block> ParallelAccessBlockStore::create(size_t size) {
auto block = _baseBlockStore->create(size);
Key key = block->key();
Key ParallelAccessBlockStore::createKey() {
return _baseBlockStore->createKey();
}
unique_ptr<Block> ParallelAccessBlockStore::tryCreate(const Key &key, Data data) {
auto block = _baseBlockStore->tryCreate(key, std::move(data));
if (block.get() == nullptr) {
//TODO Test this code branch
return nullptr;
}
return _parallelAccessStore.add(key, std::move(block));
}

View File

@ -14,7 +14,8 @@ class ParallelAccessBlockStore: public BlockStore {
public:
ParallelAccessBlockStore(std::unique_ptr<BlockStore> baseBlockStore);
std::unique_ptr<Block> create(size_t size) override;
Key createKey() override;
std::unique_ptr<Block> tryCreate(const Key &key, Data data) override;
std::unique_ptr<Block> load(const Key &key) override;
void remove(std::unique_ptr<Block> block) override;
uint64_t numBlocks() const override;

View File

@ -14,13 +14,15 @@ namespace testfake {
FakeBlockStore::FakeBlockStore()
: _blocks(), _used_dataregions_for_blocks() {}
unique_ptr<Block> FakeBlockStore::create(const Key &key, size_t size) {
if (_blocks.find(key.ToString()) != _blocks.end()) {
unique_ptr<Block> FakeBlockStore::tryCreate(const Key &key, Data data) {
auto insert_result = _blocks.emplace(key.ToString(), std::move(data));
if (!insert_result.second) {
return nullptr;
}
Data data(size);
data.FillWithZeroes();
return makeFakeBlockFromData(key, data, true);
//Return a copy of the stored data
return load(key);
}
unique_ptr<Block> FakeBlockStore::load(const Key &key) {
@ -49,7 +51,7 @@ unique_ptr<Block> FakeBlockStore::makeFakeBlockFromData(const Key &key, const Da
void FakeBlockStore::updateData(const Key &key, const Data &data) {
auto found = _blocks.find(key.ToString());
if (found == _blocks.end()) {
auto insertResult = _blocks.emplace(key.ToString(), data.size());
auto insertResult = _blocks.emplace(key.ToString(), data.copy());
assert(true == insertResult.second);
found = insertResult.first;
}

View File

@ -31,7 +31,7 @@ class FakeBlockStore: public BlockStoreWithRandomKeys {
public:
FakeBlockStore();
std::unique_ptr<Block> create(const Key &key, size_t size) override;
std::unique_ptr<Block> tryCreate(const Key &key, Data data) override;
std::unique_ptr<Block> load(const Key &key) override;
void remove(std::unique_ptr<Block> block) override;
uint64_t numBlocks() const override;

View File

@ -5,7 +5,7 @@
#include "Block.h"
#include <string>
#include <memory>
#include "../utils/Data.h"
namespace blockstore {
@ -13,12 +13,23 @@ class BlockStore {
public:
virtual ~BlockStore() {}
virtual std::unique_ptr<Block> create(size_t size) = 0;
virtual Key createKey() = 0;
//Returns nullptr if key already exists
virtual std::unique_ptr<Block> tryCreate(const Key &key, Data data) = 0;
//TODO Use boost::optional (if key doesn't exist)
// Return nullptr if block with this key doesn't exists
virtual std::unique_ptr<Block> load(const Key &key) = 0;
virtual void remove(std::unique_ptr<Block> block) = 0;
virtual uint64_t numBlocks() const = 0;
std::unique_ptr<Block> create(const Data &data) {
std::unique_ptr<Block> block(nullptr);
while(block.get() == nullptr) {
//TODO Copy necessary?
block = tryCreate(createKey(), data.copy());
}
return block;
}
};
}

View File

@ -1,20 +1 @@
#include "BlockStoreWithRandomKeys.h"
using namespace blockstore;
using std::string;
using std::unique_ptr;
unique_ptr<Block> BlockStoreWithRandomKeys::create(size_t size) {
auto result = tryCreate(size);
while (!result) {
result = tryCreate(size);
}
return result;
}
unique_ptr<Block> BlockStoreWithRandomKeys::tryCreate(size_t size) {
Key key = Key::CreateRandom();
return create(key, size);
}

View File

@ -12,14 +12,9 @@ namespace blockstore {
// work with the BlockStore interface instead.
class BlockStoreWithRandomKeys: public BlockStore {
public:
//TODO Use boost::optional (if key already exists)
// Return nullptr if key already exists
virtual std::unique_ptr<Block> create(const Key &key, size_t size) = 0;
std::unique_ptr<Block> create(size_t size) final;
private:
std::unique_ptr<Block> tryCreate(size_t size);
Key createKey() final {
return Key::CreateRandom();
}
};
}

View File

@ -35,7 +35,7 @@ public:
TEST_F(OnDiskBlockCreateTest, CreatingBlockCreatesFile) {
EXPECT_FALSE(bf::exists(file.path()));
auto block = OnDiskBlock::CreateOnDisk(dir.path(), key, 0);
auto block = OnDiskBlock::CreateOnDisk(dir.path(), key, Data(0));
block->flush();
EXPECT_TRUE(bf::exists(file.path()));
@ -43,9 +43,9 @@ TEST_F(OnDiskBlockCreateTest, CreatingBlockCreatesFile) {
}
TEST_F(OnDiskBlockCreateTest, CreatingExistingBlockReturnsNull) {
auto block1 = OnDiskBlock::CreateOnDisk(dir.path(), key, 0);
auto block1 = OnDiskBlock::CreateOnDisk(dir.path(), key, Data(0));
block1->flush();
auto block2 = OnDiskBlock::CreateOnDisk(dir.path(), key, 0);
auto block2 = OnDiskBlock::CreateOnDisk(dir.path(), key, Data(0));
EXPECT_TRUE((bool)block1);
EXPECT_FALSE((bool)block2);
}
@ -56,7 +56,7 @@ public:
Data ZEROES;
OnDiskBlockCreateSizeTest():
block(OnDiskBlock::CreateOnDisk(dir.path(), key, GetParam())),
block(OnDiskBlock::CreateOnDisk(dir.path(), key, std::move(Data(GetParam()).FillWithZeroes()))),
ZEROES(block->size())
{
block->flush();

View File

@ -37,13 +37,17 @@ public:
unique_ptr<OnDiskBlock> CreateBlockAndLoadItFromDisk() {
{
auto block = OnDiskBlock::CreateOnDisk(dir.path(), key, randomData.size());
Data data(randomData.size());
std::memcpy(data.data(), randomData.data(), randomData.size());
auto block = OnDiskBlock::CreateOnDisk(dir.path(), key, std::move(data));
}
return OnDiskBlock::LoadFromDisk(dir.path(), key);
}
unique_ptr<OnDiskBlock> CreateBlock() {
return OnDiskBlock::CreateOnDisk(dir.path(), key, randomData.size());
Data data(randomData.size());
std::memcpy(data.data(), randomData.data(), randomData.size());
return OnDiskBlock::CreateOnDisk(dir.path(), key, std::move(data));
}
void WriteDataToBlock(const unique_ptr<OnDiskBlock> &block) {

View File

@ -1,12 +1,14 @@
#include "../../../interface/helpers/BlockStoreWithRandomKeys.h"
#include "google/gtest/gtest.h"
#include "google/gmock/gmock.h"
#include "../../testutils/DataBlockFixture.h"
using ::testing::Test;
using ::testing::_;
using ::testing::Return;
using ::testing::Invoke;
using ::testing::Eq;
using ::testing::ByRef;
using std::string;
using std::unique_ptr;
@ -16,10 +18,10 @@ using namespace blockstore;
class BlockStoreWithRandomKeysMock: public BlockStoreWithRandomKeys {
public:
unique_ptr<Block> create(const Key &key, size_t size) {
return unique_ptr<Block>(do_create(key, size));
unique_ptr<Block> tryCreate(const Key &key, Data data) {
return unique_ptr<Block>(do_create(key, data));
}
MOCK_METHOD2(do_create, Block*(const Key &, size_t));
MOCK_METHOD2(do_create, Block*(const Key &, const Data &data));
unique_ptr<Block> load(const Key &key) {
return unique_ptr<Block>(do_load(key));
}
@ -43,78 +45,93 @@ public:
BlockStoreWithRandomKeysMock blockStoreMock;
BlockStore &blockStore = blockStoreMock;
const blockstore::Key key = Key::FromString("1491BB4932A389EE14BC7090AC772972");
Data createDataWithSize(size_t size) {
DataBlockFixture fixture(size);
Data data(size);
std::memcpy(data.data(), fixture.data(), size);
return data;
}
};
TEST_F(BlockStoreWithRandomKeysTest, SizeIsPassedThrough0) {
EXPECT_CALL(blockStoreMock, do_create(_, 0)).WillOnce(Return(new BlockMock));
blockStore.create(0);
TEST_F(BlockStoreWithRandomKeysTest, DataIsPassedThrough0) {
Data data = createDataWithSize(0);
EXPECT_CALL(blockStoreMock, do_create(_, Eq(ByRef(data)))).WillOnce(Return(new BlockMock));
blockStore.create(data);
}
TEST_F(BlockStoreWithRandomKeysTest, SizeIsPassedThrough1) {
EXPECT_CALL(blockStoreMock, do_create(_, 1)).WillOnce(Return(new BlockMock));
blockStore.create(1);
TEST_F(BlockStoreWithRandomKeysTest, DataIsPassedThrough1) {
Data data = createDataWithSize(1);
EXPECT_CALL(blockStoreMock, do_create(_, Eq(ByRef(data)))).WillOnce(Return(new BlockMock));
blockStore.create(data);
}
TEST_F(BlockStoreWithRandomKeysTest, SizeIsPassedThrough1024) {
EXPECT_CALL(blockStoreMock, do_create(_, 1024)).WillOnce(Return(new BlockMock));
blockStore.create(1024);
TEST_F(BlockStoreWithRandomKeysTest, DataIsPassedThrough1024) {
Data data = createDataWithSize(1024);
EXPECT_CALL(blockStoreMock, do_create(_, Eq(ByRef(data)))).WillOnce(Return(new BlockMock));
blockStore.create(data);
}
TEST_F(BlockStoreWithRandomKeysTest, KeyHasCorrectSize) {
EXPECT_CALL(blockStoreMock, do_create(_, _)).WillOnce(Invoke([](const Key &key, size_t) {
EXPECT_CALL(blockStoreMock, do_create(_, _)).WillOnce(Invoke([](const Key &key, const Data &) {
EXPECT_EQ(Key::STRING_LENGTH, key.ToString().size());
return new BlockMock;
}));
blockStore.create(1024);
blockStore.create(createDataWithSize(1024));
}
TEST_F(BlockStoreWithRandomKeysTest, TwoBlocksGetDifferentKeys) {
Key first_key = key;
EXPECT_CALL(blockStoreMock, do_create(_, _))
.WillOnce(Invoke([&first_key](const Key &key, size_t) {
.WillOnce(Invoke([&first_key](const Key &key, const Data &) {
first_key = key;
return new BlockMock;
}))
.WillOnce(Invoke([&first_key](const Key &key, size_t) {
.WillOnce(Invoke([&first_key](const Key &key, const Data &) {
EXPECT_NE(first_key, key);
return new BlockMock;
}));
blockStore.create(1024);
blockStore.create(1024);
Data data = createDataWithSize(1024);
blockStore.create(data);
blockStore.create(data);
}
TEST_F(BlockStoreWithRandomKeysTest, WillTryADifferentKeyIfKeyAlreadyExists) {
Key first_key = key;
EXPECT_CALL(blockStoreMock, do_create(_, _))
.WillOnce(Invoke([&first_key](const Key &key, size_t) {
Data data = createDataWithSize(1024);
EXPECT_CALL(blockStoreMock, do_create(_, Eq(ByRef(data))))
.WillOnce(Invoke([&first_key](const Key &key, const Data &) {
first_key = key;
return nullptr;
}))
.WillOnce(Invoke([&first_key](const Key &key, size_t) {
//TODO Check that this test case fails when the second do_create call gets different data
.WillOnce(Invoke([&first_key](const Key &key, const Data &) {
EXPECT_NE(first_key, key);
return new BlockMock;
}));
blockStore.create(1024);
blockStore.create(data);
}
TEST_F(BlockStoreWithRandomKeysTest, WillTryADifferentKeyIfKeyAlreadyExistsTwoTimes) {
Key first_key = key;
EXPECT_CALL(blockStoreMock, do_create(_, _))
.WillOnce(Invoke([&first_key](const Key &key, size_t) {
Data data = createDataWithSize(1024);
EXPECT_CALL(blockStoreMock, do_create(_, Eq(ByRef(data))))
.WillOnce(Invoke([&first_key](const Key &key, const Data &) {
first_key = key;
return nullptr;
}))
.WillOnce(Invoke([&first_key](const Key &key, size_t) {
//TODO Check that this test case fails when the second/third do_create calls get different data
.WillOnce(Invoke([&first_key](const Key &key, const Data &) {
first_key = key;
return nullptr;
}))
.WillOnce(Invoke([&first_key](const Key &key, size_t) {
.WillOnce(Invoke([&first_key](const Key &key, const Data &) {
EXPECT_NE(first_key, key);
return new BlockMock;
}));
blockStore.create(1024);
blockStore.create(data);
}

View File

@ -28,14 +28,14 @@ TYPED_TEST_CASE_P(BlockStoreTest);
TYPED_TEST_P(BlockStoreTest, TwoCreatedBlocksHaveDifferentKeys) {
auto blockStore = this->fixture.createBlockStore();
auto block1 = blockStore->create(1024);
auto block2 = blockStore->create(1024);
auto block1 = blockStore->create(blockstore::Data(1024));
auto block2 = blockStore->create(blockstore::Data(1024));
EXPECT_NE(block1->key(), block2->key());
}
TYPED_TEST_P(BlockStoreTest, BlockIsNotLoadableAfterDeleting) {
auto blockStore = this->fixture.createBlockStore();
auto blockkey = blockStore->create(1024)->key();
auto blockkey = blockStore->create(blockstore::Data(1024))->key();
auto block = blockStore->load(blockkey);
EXPECT_NE(nullptr, block.get());
blockStore->remove(std::move(block));
@ -49,55 +49,55 @@ TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectOnEmptyBlockstore) {
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingOneBlock) {
auto blockStore = this->fixture.createBlockStore();
auto block = blockStore->create(1);
auto block = blockStore->create(blockstore::Data(1));
EXPECT_EQ(1, blockStore->numBlocks());
}
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingOneBlock_AfterClosingBlock) {
auto blockStore = this->fixture.createBlockStore();
blockStore->create(1);
blockStore->create(blockstore::Data(1));
EXPECT_EQ(1, blockStore->numBlocks());
}
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterRemovingTheLastBlock) {
auto blockStore = this->fixture.createBlockStore();
auto block = blockStore->create(1);
auto block = blockStore->create(blockstore::Data(1));
blockStore->remove(std::move(block));
EXPECT_EQ(0, blockStore->numBlocks());
}
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks) {
auto blockStore = this->fixture.createBlockStore();
auto block1 = blockStore->create(1);
auto block2 = blockStore->create(0);
auto block1 = blockStore->create(blockstore::Data(1));
auto block2 = blockStore->create(blockstore::Data(0));
EXPECT_EQ(2, blockStore->numBlocks());
}
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks_AfterClosingFirstBlock) {
auto blockStore = this->fixture.createBlockStore();
blockStore->create(1);
auto block2 = blockStore->create(0);
blockStore->create(blockstore::Data(1));
auto block2 = blockStore->create(blockstore::Data(0));
EXPECT_EQ(2, blockStore->numBlocks());
}
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks_AfterClosingSecondBlock) {
auto blockStore = this->fixture.createBlockStore();
auto block1 = blockStore->create(1);
blockStore->create(0);
auto block1 = blockStore->create(blockstore::Data(1));
blockStore->create(blockstore::Data(0));
EXPECT_EQ(2, blockStore->numBlocks());
}
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks_AfterClosingBothBlocks) {
auto blockStore = this->fixture.createBlockStore();
blockStore->create(1);
blockStore->create(0);
blockStore->create(blockstore::Data(1));
blockStore->create(blockstore::Data(0));
EXPECT_EQ(2, blockStore->numBlocks());
}
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterRemovingABlock) {
auto blockStore = this->fixture.createBlockStore();
auto block = blockStore->create(1);
blockStore->create(1);
auto block = blockStore->create(blockstore::Data(1));
blockStore->create(blockstore::Data(1));
blockStore->remove(std::move(block));
EXPECT_EQ(1, blockStore->numBlocks());
}
@ -109,8 +109,8 @@ TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterRemovingABlock) {
REGISTER_TYPED_TEST_CASE_P(BlockStoreTest,
CreatedBlockHasCorrectSize,
LoadingUnchangedBlockHasCorrectSize,
CreatedBlockIsZeroedOut,
LoadingUnchangedBlockIsZeroedOut,
CreatedBlockData,
LoadingUnchangedBlockData,
LoadedBlockIsCorrect,
// LoadedBlockIsCorrectWhenLoadedDirectlyAfterFlushing,
AfterCreate_FlushingDoesntChangeBlock,

View File

@ -20,7 +20,7 @@ public:
}
void TestWriteAndReadImmediately() {
auto block = blockStore->create(testData.blocksize);
auto block = blockStore->create(blockstore::Data(testData.blocksize).FillWithZeroes());
block->write(foregroundData.data(), testData.offset, testData.count);
EXPECT_DATA_READS_AS(foregroundData, *block, testData.offset, testData.count);
@ -36,7 +36,7 @@ public:
}
void TestOverwriteAndRead() {
auto block = blockStore->create(testData.blocksize);
auto block = blockStore->create(blockstore::Data(testData.blocksize));
block->write(backgroundData.data(), 0, testData.blocksize);
block->write(foregroundData.data(), testData.offset, testData.count);
EXPECT_DATA_READS_AS(foregroundData, *block, testData.offset, testData.count);
@ -55,7 +55,7 @@ private:
}
blockstore::Key CreateBlockWriteToItAndReturnKey(const blockstore::Data &to_write) {
auto newblock = blockStore->create(testData.blocksize);
auto newblock = blockStore->create(blockstore::Data(testData.blocksize).FillWithZeroes());
newblock->write(to_write.data(), testData.offset, testData.count);
return newblock->key();

View File

@ -1,29 +1,38 @@
// This file is meant to be included by BlockStoreTest.h only
#include "../../utils/Data.h"
class BlockStoreSizeParameterizedTest {
public:
BlockStoreSizeParameterizedTest(std::unique_ptr<blockstore::BlockStore> blockStore_, size_t size_): blockStore(std::move(blockStore_)), size(size_) {}
void TestCreatedBlockHasCorrectSize() {
auto block = blockStore->create(size);
auto block = CreateBlock();
EXPECT_EQ(size, block->size());
}
void TestLoadingUnchangedBlockHasCorrectSize() {
blockstore::Key key = blockStore->create(size)->key();
blockstore::Key key = CreateBlock()->key();
auto loaded_block = blockStore->load(key);
EXPECT_EQ(size, loaded_block->size());
}
void TestCreatedBlockIsZeroedOut() {
auto block = blockStore->create(size);
EXPECT_EQ(0, std::memcmp(ZEROES(size).data(), block->data(), size));
void TestCreatedBlockData() {
DataBlockFixture dataFixture(size);
blockstore::Data data(size);
std::memcpy(data.data(), dataFixture.data(), size);
auto block = blockStore->create(data);
EXPECT_EQ(0, std::memcmp(dataFixture.data(), block->data(), size));
}
void TestLoadingUnchangedBlockIsZeroedOut() {
blockstore::Key key = blockStore->create(size)->key();
void TestLoadingUnchangedBlockData() {
DataBlockFixture dataFixture(size);
blockstore::Data data(size);
std::memcpy(data.data(), dataFixture.data(), size);
blockstore::Key key = blockStore->create(data)->key();
auto loaded_block = blockStore->load(key);
EXPECT_EQ(0, std::memcmp(ZEROES(size).data(), loaded_block->data(), size));
EXPECT_EQ(0, std::memcmp(dataFixture.data(), loaded_block->data(), size));
}
void TestLoadedBlockIsCorrect() {
@ -62,7 +71,7 @@ public:
DataBlockFixture randomData(size);
blockstore::Key key = key;
{
auto block = blockStore->create(size);
auto block = blockStore->create(blockstore::Data(size));
key = block->key();
WriteDataToBlock(block.get(), randomData);
}
@ -74,7 +83,7 @@ public:
DataBlockFixture randomData(size);
blockstore::Key key = key;
{
key = blockStore->create(size)->key();
key = CreateBlock()->key();
auto block = blockStore->load(key);
WriteDataToBlock(block.get(), randomData);
}
@ -104,26 +113,27 @@ private:
return blockStore->load(key);
}
blockstore::Key StoreDataToBlockAndGetKey(const DataBlockFixture &data) {
auto block = blockStore->create(data.size());
block->write(data.data(), 0, data.size());
return block->key();
blockstore::Key StoreDataToBlockAndGetKey(const DataBlockFixture &dataFixture) {
blockstore::Data data(dataFixture.size());
std::memcpy(data.data(), dataFixture.data(), dataFixture.size());
return blockStore->create(data)->key();
}
std::unique_ptr<blockstore::Block> StoreDataToBlockAndLoadItDirectlyAfterFlushing(const DataBlockFixture &data) {
auto block = blockStore->create(data.size());
block->write(data.data(), 0, data.size());
std::unique_ptr<blockstore::Block> StoreDataToBlockAndLoadItDirectlyAfterFlushing(const DataBlockFixture &dataFixture) {
blockstore::Data data(dataFixture.size());
std::memcpy(data.data(), dataFixture.data(), dataFixture.size());
auto block = blockStore->create(data);
block->flush();
return blockStore->load(block->key());
}
std::unique_ptr<blockstore::Block> CreateBlockAndLoadIt() {
blockstore::Key key = blockStore->create(size)->key();
blockstore::Key key = CreateBlock()->key();
return blockStore->load(key);
}
std::unique_ptr<blockstore::Block> CreateBlock() {
return blockStore->create(size);
return blockStore->create(blockstore::Data(size));
}
void WriteDataToBlock(blockstore::Block *block, const DataBlockFixture &randomData) {
@ -147,8 +157,8 @@ constexpr std::initializer_list<size_t> SIZES = {0, 1, 1024, 4096, 10*1024*1024}
TYPED_TEST_P_FOR_ALL_SIZES(CreatedBlockHasCorrectSize);
TYPED_TEST_P_FOR_ALL_SIZES(LoadingUnchangedBlockHasCorrectSize);
TYPED_TEST_P_FOR_ALL_SIZES(CreatedBlockIsZeroedOut);
TYPED_TEST_P_FOR_ALL_SIZES(LoadingUnchangedBlockIsZeroedOut);
TYPED_TEST_P_FOR_ALL_SIZES(CreatedBlockData);
TYPED_TEST_P_FOR_ALL_SIZES(LoadingUnchangedBlockData);
TYPED_TEST_P_FOR_ALL_SIZES(LoadedBlockIsCorrect);
//TYPED_TEST_P_FOR_ALL_SIZES(LoadedBlockIsCorrectWhenLoadedDirectlyAfterFlushing);
TYPED_TEST_P_FOR_ALL_SIZES(AfterCreate_FlushingDoesntChangeBlock);

View File

@ -31,45 +31,45 @@ TYPED_TEST_CASE_P(BlockStoreWithRandomKeysTest);
TYPED_TEST_P(BlockStoreWithRandomKeysTest, CreateTwoBlocksWithSameKeyAndSameSize) {
auto blockStore = this->fixture.createBlockStore();
auto block = blockStore->create(this->key, 1024);
auto block = blockStore->tryCreate(this->key, blockstore::Data(1024));
block->flush();
auto block2 = blockStore->create(this->key, 1024);
auto block2 = blockStore->tryCreate(this->key, blockstore::Data(1024));
EXPECT_TRUE((bool)block);
EXPECT_FALSE((bool)block2);
}
TYPED_TEST_P(BlockStoreWithRandomKeysTest, CreateTwoBlocksWithSameKeyAndDifferentSize) {
auto blockStore = this->fixture.createBlockStore();
auto block = blockStore->create(this->key, 1024);
auto block = blockStore->tryCreate(this->key, blockstore::Data(1024));
block->flush();
auto block2 = blockStore->create(this->key, 4096);
auto block2 = blockStore->tryCreate(this->key, blockstore::Data(4096));
EXPECT_TRUE((bool)block);
EXPECT_FALSE((bool)block2);
}
TYPED_TEST_P(BlockStoreWithRandomKeysTest, CreateTwoBlocksWithSameKeyAndFirstNullSize) {
auto blockStore = this->fixture.createBlockStore();
auto block = blockStore->create(this->key, 0);
auto block = blockStore->tryCreate(this->key, blockstore::Data(0));
block->flush();
auto block2 = blockStore->create(this->key, 1024);
auto block2 = blockStore->tryCreate(this->key, blockstore::Data(1024));
EXPECT_TRUE((bool)block);
EXPECT_FALSE((bool)block2);
}
TYPED_TEST_P(BlockStoreWithRandomKeysTest, CreateTwoBlocksWithSameKeyAndSecondNullSize) {
auto blockStore = this->fixture.createBlockStore();
auto block = blockStore->create(this->key, 1024);
auto block = blockStore->tryCreate(this->key, blockstore::Data(1024));
block->flush();
auto block2 = blockStore->create(this->key, 0);
auto block2 = blockStore->tryCreate(this->key, blockstore::Data(0));
EXPECT_TRUE((bool)block);
EXPECT_FALSE((bool)block2);
}
TYPED_TEST_P(BlockStoreWithRandomKeysTest, CreateTwoBlocksWithSameKeyAndBothNullSize) {
auto blockStore = this->fixture.createBlockStore();
auto block = blockStore->create(this->key, 0);
auto block = blockStore->tryCreate(this->key, blockstore::Data(0));
block->flush();
auto block2 = blockStore->create(this->key, 0);
auto block2 = blockStore->tryCreate(this->key, blockstore::Data(0));
EXPECT_TRUE((bool)block);
EXPECT_FALSE((bool)block2);
}

View File

@ -33,7 +33,7 @@ public:
};
TEST_F(BlockStoreUtilsTest, FillWithZeroes) {
auto block = blockStore->create(SIZE);
auto block = blockStore->create(Data(SIZE));
block->write(dataFixture.data(), 0, SIZE);
EXPECT_NE(0, std::memcmp(ZEROES.data(), block->data(), SIZE));
fillWithZeroes(block.get());
@ -43,14 +43,14 @@ TEST_F(BlockStoreUtilsTest, FillWithZeroes) {
class BlockStoreUtilsTest_CopyToNewBlock: public BlockStoreUtilsTest {};
TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyEmptyBlock) {
auto block = blockStore->create(0);
auto block = blockStore->create(Data(0));
auto block2 = copyToNewBlock(blockStore.get(), *block);
EXPECT_EQ(0u, block2->size());
}
TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyZeroBlock) {
auto block = blockStore->create(SIZE);
auto block = blockStore->create(ZEROES);
auto block2 = copyToNewBlock(blockStore.get(), *block);
EXPECT_EQ(SIZE, block2->size());
@ -58,7 +58,7 @@ TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyZeroBlock) {
}
TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyDataBlock) {
auto block = blockStore->create(SIZE);
auto block = blockStore->create(Data(SIZE));
block->write(dataFixture.data(), 0, SIZE);
auto block2 = copyToNewBlock(blockStore.get(), *block);
@ -67,7 +67,7 @@ TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyDataBlock) {
}
TEST_F(BlockStoreUtilsTest_CopyToNewBlock, OriginalBlockUnchanged) {
auto block = blockStore->create(SIZE);
auto block = blockStore->create(Data(SIZE));
block->write(dataFixture.data(), 0, SIZE);
auto block2 = copyToNewBlock(blockStore.get(), *block);
@ -78,14 +78,14 @@ TEST_F(BlockStoreUtilsTest_CopyToNewBlock, OriginalBlockUnchanged) {
class BlockStoreUtilsTest_CopyToExistingBlock: public BlockStoreUtilsTest {};
TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, CopyEmptyBlock) {
auto block = blockStore->create(0);
auto block2 = blockStore->create(0);
auto block = blockStore->create(Data(0));
auto block2 = blockStore->create(Data(0));
copyTo(block2.get(), *block);
}
TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, CopyZeroBlock) {
auto block = blockStore->create(SIZE);
auto block2 = blockStore->create(SIZE);
auto block = blockStore->create(ZEROES);
auto block2 = blockStore->create(Data(SIZE));
block2->write(dataFixture.data(), 0, SIZE);
copyTo(block2.get(), *block);
@ -93,18 +93,18 @@ TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, CopyZeroBlock) {
}
TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, CopyDataBlock) {
auto block = blockStore->create(SIZE);
auto block = blockStore->create(Data(SIZE));
block->write(dataFixture.data(), 0, SIZE);
auto block2 = blockStore->create(SIZE);
auto block2 = blockStore->create(Data(SIZE));
copyTo(block2.get(), *block);
EXPECT_EQ(0, std::memcmp(dataFixture.data(), block2->data(), SIZE));
}
TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, OriginalBlockUnchanged) {
auto block = blockStore->create(SIZE);
auto block = blockStore->create(Data(SIZE));
block->write(dataFixture.data(), 0, SIZE);
auto block2 = blockStore->create(SIZE);
auto block2 = blockStore->create(Data(SIZE));
copyTo(block2.get(), *block);
EXPECT_EQ(0, std::memcmp(dataFixture.data(), block->data(), SIZE));

View File

@ -10,9 +10,9 @@ namespace blockstore {
namespace utils {
unique_ptr<Block> copyToNewBlock(BlockStore *blockStore, const Block &block) {
auto newBlock = blockStore->create(block.size());
copyTo(newBlock.get(), block);
return newBlock;
Data data(block.size());
std::memcpy(data.data(), block.data(), block.size());
return blockStore->create(data);
}
void copyTo(Block *target, const Block &source) {

View File

@ -50,8 +50,9 @@ size_t Data::size() const {
return _size;
}
void Data::FillWithZeroes() {
Data &Data::FillWithZeroes() {
std::memset(_data, 0, _size);
return *this;
}
void Data::StoreToFile(const bf::path &filepath) const {
@ -92,4 +93,8 @@ void Data::_readFromStream(istream &stream) {
stream.read((char*)_data, _size);
}
bool operator==(const Data &lhs, const Data &rhs) {
return lhs.size() == rhs.size() && 0 == memcmp(lhs.data(), rhs.data(), lhs.size());
}
}

View File

@ -11,7 +11,7 @@ namespace blockstore {
class Data {
public:
Data(size_t size);
explicit Data(size_t size);
Data(Data &&rhs); // move constructor
virtual ~Data();
@ -22,7 +22,7 @@ public:
size_t size() const;
void FillWithZeroes();
Data &FillWithZeroes();
void StoreToFile(const boost::filesystem::path &filepath) const;
static Data LoadFromFile(const boost::filesystem::path &filepath);
@ -38,6 +38,9 @@ private:
DISALLOW_COPY_AND_ASSIGN(Data);
};
//TODO Test operator==
bool operator==(const Data &lhs, const Data &rhs);
}
#endif