- 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:
parent
18e7d68f15
commit
417a701636
@ -1,4 +1,5 @@
|
|||||||
#include "CachedBlock.h"
|
#include "CachedBlock.h"
|
||||||
|
#include "NewBlock.h"
|
||||||
#include "CachingBlockStore.h"
|
#include "CachingBlockStore.h"
|
||||||
#include "../../interface/Block.h"
|
#include "../../interface/Block.h"
|
||||||
|
|
||||||
@ -13,15 +14,16 @@ namespace blockstore {
|
|||||||
namespace caching {
|
namespace caching {
|
||||||
|
|
||||||
CachingBlockStore::CachingBlockStore(std::unique_ptr<BlockStore> baseBlockStore)
|
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) {
|
Key CachingBlockStore::createKey() {
|
||||||
//TODO Also cache this and only write back in the destructor?
|
return _baseBlockStore->createKey();
|
||||||
// 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.
|
unique_ptr<Block> CachingBlockStore::tryCreate(const Key &key, Data data) {
|
||||||
return make_unique<CachedBlock>(_baseBlockStore->create(size), this);
|
++_numNewBlocks;
|
||||||
|
return make_unique<CachedBlock>(make_unique<NewBlock>(key, std::move(data), this), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ptr<Block> CachingBlockStore::load(const Key &key) {
|
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) {
|
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 {
|
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) {
|
void CachingBlockStore::release(unique_ptr<Block> block) {
|
||||||
_cache.push(std::move(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));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,16 +14,21 @@ class CachingBlockStore: public BlockStore {
|
|||||||
public:
|
public:
|
||||||
CachingBlockStore(std::unique_ptr<BlockStore> baseBlockStore);
|
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;
|
std::unique_ptr<Block> load(const Key &key) override;
|
||||||
void remove(std::unique_ptr<Block> block) override;
|
void remove(std::unique_ptr<Block> block) override;
|
||||||
uint64_t numBlocks() const override;
|
uint64_t numBlocks() const override;
|
||||||
|
|
||||||
void release(std::unique_ptr<Block> block);
|
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:
|
private:
|
||||||
std::unique_ptr<BlockStore> _baseBlockStore;
|
std::unique_ptr<BlockStore> _baseBlockStore;
|
||||||
Cache _cache;
|
Cache _cache;
|
||||||
|
uint32_t _numNewBlocks;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(CachingBlockStore);
|
DISALLOW_COPY_AND_ASSIGN(CachingBlockStore);
|
||||||
};
|
};
|
||||||
|
66
implementations/caching/NewBlock.cpp
Normal file
66
implementations/caching/NewBlock.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
50
implementations/caching/NewBlock.h
Normal file
50
implementations/caching/NewBlock.h
Normal 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
|
@ -15,11 +15,15 @@ namespace encrypted {
|
|||||||
|
|
||||||
constexpr unsigned int EncryptedBlock::IV_SIZE;
|
constexpr unsigned int EncryptedBlock::IV_SIZE;
|
||||||
|
|
||||||
std::unique_ptr<EncryptedBlock> EncryptedBlock::CreateNew(std::unique_ptr<Block> baseBlock, const EncryptionKey &encKey) {
|
std::unique_ptr<EncryptedBlock> EncryptedBlock::TryCreateNew(BlockStore *baseBlockStore, const Key &key, Data data, const EncryptionKey &encKey) {
|
||||||
auto block = make_unique<EncryptedBlock>(std::move(baseBlock), encKey);
|
Data encrypted = _encrypt(data, encKey);
|
||||||
//We have to explicitly fill the block with zeroes, because otherwise the encrypted version is filled with zeroes and not the plaintext version
|
auto baseBlock = baseBlockStore->tryCreate(key, std::move(encrypted));
|
||||||
utils::fillWithZeroes(block.get());
|
if (baseBlock.get() == nullptr) {
|
||||||
return block;
|
//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)
|
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() {
|
EncryptedBlock::~EncryptedBlock() {
|
||||||
flush();
|
_encryptToBaseBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *EncryptedBlock::data() const {
|
const void *EncryptedBlock::data() const {
|
||||||
@ -63,16 +67,21 @@ void EncryptedBlock::_decryptFromBaseBlock() {
|
|||||||
|
|
||||||
void EncryptedBlock::_encryptToBaseBlock() {
|
void EncryptedBlock::_encryptToBaseBlock() {
|
||||||
if (_dataChanged) {
|
if (_dataChanged) {
|
||||||
FixedSizeData<IV_SIZE> iv = FixedSizeData<IV_SIZE>::CreateRandom();
|
Data encrypted = _encrypt(_plaintextData, _encKey);
|
||||||
auto encryption = CFB_Mode<AES>::Encryption(_encKey.data(), EncryptionKey::BINARY_LENGTH, iv.data());
|
_baseBlock->write(encrypted.data(), 0, encrypted.size());
|
||||||
//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());
|
|
||||||
_dataChanged = false;
|
_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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "../../interface/Block.h"
|
#include "../../interface/Block.h"
|
||||||
#include "EncryptionKey.h"
|
#include "EncryptionKey.h"
|
||||||
#include "../../utils/Data.h"
|
#include "../../utils/Data.h"
|
||||||
|
#include "../../interface/BlockStore.h"
|
||||||
|
|
||||||
#include "messmer/cpp-utils/macros.h"
|
#include "messmer/cpp-utils/macros.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -19,7 +20,7 @@ public:
|
|||||||
EncryptedBlock(std::unique_ptr<Block> baseBlock, const EncryptionKey &encKey);
|
EncryptedBlock(std::unique_ptr<Block> baseBlock, const EncryptionKey &encKey);
|
||||||
virtual ~EncryptedBlock();
|
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;
|
const void *data() const override;
|
||||||
void write(const void *source, uint64_t offset, uint64_t size) override;
|
void write(const void *source, uint64_t offset, uint64_t size) override;
|
||||||
@ -49,6 +50,8 @@ private:
|
|||||||
void _encryptToBaseBlock();
|
void _encryptToBaseBlock();
|
||||||
void _decryptFromBaseBlock();
|
void _decryptFromBaseBlock();
|
||||||
|
|
||||||
|
static Data _encrypt(const Data &plaintext, const EncryptionKey &encKey);
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(EncryptedBlock);
|
DISALLOW_COPY_AND_ASSIGN(EncryptedBlock);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,8 +13,12 @@ EncryptedBlockStore::EncryptedBlockStore(unique_ptr<BlockStore> baseBlockStore,
|
|||||||
: _baseBlockStore(std::move(baseBlockStore)), _encKey(encKey) {
|
: _baseBlockStore(std::move(baseBlockStore)), _encKey(encKey) {
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ptr<Block> EncryptedBlockStore::create(size_t size) {
|
Key EncryptedBlockStore::createKey() {
|
||||||
return EncryptedBlock::CreateNew(_baseBlockStore->create(EncryptedBlock::BASE_BLOCK_SIZE(size)), _encKey);
|
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) {
|
unique_ptr<Block> EncryptedBlockStore::load(const Key &key) {
|
||||||
@ -33,5 +37,10 @@ uint64_t EncryptedBlockStore::numBlocks() const {
|
|||||||
return _baseBlockStore->numBlocks();
|
return _baseBlockStore->numBlocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unique_ptr<Block> EncryptedBlockStore::tryCreateInBaseStore(const Key &key, Data encryptedData) {
|
||||||
|
return _baseBlockStore->tryCreate(key, std::move(encryptedData));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,11 +13,14 @@ class EncryptedBlockStore: public BlockStore {
|
|||||||
public:
|
public:
|
||||||
EncryptedBlockStore(std::unique_ptr<BlockStore> baseBlockStore, const EncryptionKey &encKey);
|
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;
|
std::unique_ptr<Block> load(const Key &key) override;
|
||||||
void remove(std::unique_ptr<Block> block) override;
|
void remove(std::unique_ptr<Block> block) override;
|
||||||
uint64_t numBlocks() const override;
|
uint64_t numBlocks() const override;
|
||||||
|
|
||||||
|
std::unique_ptr<Block> tryCreateInBaseStore(const Key &key, Data encryptedData);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<BlockStore> _baseBlockStore;
|
std::unique_ptr<BlockStore> _baseBlockStore;
|
||||||
EncryptionKey _encKey;
|
EncryptionKey _encKey;
|
||||||
|
@ -13,9 +13,8 @@ using std::ios;
|
|||||||
namespace blockstore {
|
namespace blockstore {
|
||||||
namespace inmemory {
|
namespace inmemory {
|
||||||
|
|
||||||
InMemoryBlock::InMemoryBlock(const Key &key, size_t size)
|
InMemoryBlock::InMemoryBlock(const Key &key, Data data)
|
||||||
: Block(key), _data(make_shared<Data>(size)) {
|
: Block(key), _data(make_shared<Data>(std::move(data))) {
|
||||||
_data->FillWithZeroes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InMemoryBlock::InMemoryBlock(const InMemoryBlock &rhs)
|
InMemoryBlock::InMemoryBlock(const InMemoryBlock &rhs)
|
||||||
|
@ -11,7 +11,7 @@ class InMemoryBlockStore;
|
|||||||
|
|
||||||
class InMemoryBlock: public Block {
|
class InMemoryBlock: public Block {
|
||||||
public:
|
public:
|
||||||
InMemoryBlock(const Key &key, size_t size);
|
InMemoryBlock(const Key &key, Data size);
|
||||||
InMemoryBlock(const InMemoryBlock &rhs);
|
InMemoryBlock(const InMemoryBlock &rhs);
|
||||||
virtual ~InMemoryBlock();
|
virtual ~InMemoryBlock();
|
||||||
|
|
||||||
|
@ -16,8 +16,8 @@ namespace inmemory {
|
|||||||
InMemoryBlockStore::InMemoryBlockStore()
|
InMemoryBlockStore::InMemoryBlockStore()
|
||||||
: _blocks() {}
|
: _blocks() {}
|
||||||
|
|
||||||
unique_ptr<Block> InMemoryBlockStore::create(const Key &key, size_t 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, size));
|
auto insert_result = _blocks.emplace(piecewise_construct, make_tuple(key.ToString()), make_tuple(key, std::move(data)));
|
||||||
|
|
||||||
if (!insert_result.second) {
|
if (!insert_result.second) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -16,7 +16,7 @@ class InMemoryBlockStore: public BlockStoreWithRandomKeys {
|
|||||||
public:
|
public:
|
||||||
InMemoryBlockStore();
|
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;
|
std::unique_ptr<Block> load(const Key &key) override;
|
||||||
void remove(std::unique_ptr<Block> block) override;
|
void remove(std::unique_ptr<Block> block) override;
|
||||||
uint64_t numBlocks() const override;
|
uint64_t numBlocks() const override;
|
||||||
|
@ -19,11 +19,7 @@ namespace bf = boost::filesystem;
|
|||||||
namespace blockstore {
|
namespace blockstore {
|
||||||
namespace ondisk {
|
namespace ondisk {
|
||||||
|
|
||||||
OnDiskBlock::OnDiskBlock(const Key &key, const bf::path &filepath, size_t size)
|
OnDiskBlock::OnDiskBlock(const Key &key, const bf::path &filepath, Data data)
|
||||||
: Block(key), _filepath(filepath), _data(size), _dataChanged(false) {
|
|
||||||
}
|
|
||||||
|
|
||||||
OnDiskBlock::OnDiskBlock(const Key &key, const bf::path &filepath, Data &&data)
|
|
||||||
: Block(key), _filepath(filepath), _data(std::move(data)), _dataChanged(false) {
|
: 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();
|
auto filepath = rootdir / key.ToString();
|
||||||
if (bf::exists(filepath)) {
|
if (bf::exists(filepath)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto block = unique_ptr<OnDiskBlock>(new OnDiskBlock(key, filepath, size));
|
auto block = unique_ptr<OnDiskBlock>(new OnDiskBlock(key, filepath, std::move(data)));
|
||||||
block->_fillDataWithZeroes();
|
block->_storeToDisk();
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ public:
|
|||||||
virtual ~OnDiskBlock();
|
virtual ~OnDiskBlock();
|
||||||
|
|
||||||
static std::unique_ptr<OnDiskBlock> LoadFromDisk(const boost::filesystem::path &rootdir, const Key &key);
|
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);
|
static void RemoveFromDisk(const boost::filesystem::path &rootdir, const Key &key);
|
||||||
|
|
||||||
const void *data() const override;
|
const void *data() const override;
|
||||||
@ -33,8 +33,7 @@ private:
|
|||||||
Data _data;
|
Data _data;
|
||||||
bool _dataChanged;
|
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 _fillDataWithZeroes();
|
||||||
void _storeToDisk() const;
|
void _storeToDisk() const;
|
||||||
|
@ -13,8 +13,8 @@ namespace ondisk {
|
|||||||
OnDiskBlockStore::OnDiskBlockStore(const boost::filesystem::path &rootdir)
|
OnDiskBlockStore::OnDiskBlockStore(const boost::filesystem::path &rootdir)
|
||||||
: _rootdir(rootdir) {}
|
: _rootdir(rootdir) {}
|
||||||
|
|
||||||
unique_ptr<Block> OnDiskBlockStore::create(const Key &key, size_t size) {
|
unique_ptr<Block> OnDiskBlockStore::tryCreate(const Key &key, Data data) {
|
||||||
auto block = OnDiskBlock::CreateOnDisk(_rootdir, key, size);
|
auto block = OnDiskBlock::CreateOnDisk(_rootdir, key, std::move(data));
|
||||||
|
|
||||||
if (!block) {
|
if (!block) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -14,7 +14,7 @@ class OnDiskBlockStore: public BlockStoreWithRandomKeys {
|
|||||||
public:
|
public:
|
||||||
OnDiskBlockStore(const boost::filesystem::path &rootdir);
|
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;
|
std::unique_ptr<Block> load(const Key &key) override;
|
||||||
void remove(std::unique_ptr<Block> block) override;
|
void remove(std::unique_ptr<Block> block) override;
|
||||||
uint64_t numBlocks() const override;
|
uint64_t numBlocks() const override;
|
||||||
|
@ -20,9 +20,16 @@ ParallelAccessBlockStore::ParallelAccessBlockStore(unique_ptr<BlockStore> baseBl
|
|||||||
: _baseBlockStore(std::move(baseBlockStore)), _parallelAccessStore(make_unique<ParallelAccessBlockStoreAdapter>(_baseBlockStore.get())) {
|
: _baseBlockStore(std::move(baseBlockStore)), _parallelAccessStore(make_unique<ParallelAccessBlockStoreAdapter>(_baseBlockStore.get())) {
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ptr<Block> ParallelAccessBlockStore::create(size_t size) {
|
Key ParallelAccessBlockStore::createKey() {
|
||||||
auto block = _baseBlockStore->create(size);
|
return _baseBlockStore->createKey();
|
||||||
Key key = block->key();
|
}
|
||||||
|
|
||||||
|
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));
|
return _parallelAccessStore.add(key, std::move(block));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,8 @@ class ParallelAccessBlockStore: public BlockStore {
|
|||||||
public:
|
public:
|
||||||
ParallelAccessBlockStore(std::unique_ptr<BlockStore> baseBlockStore);
|
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;
|
std::unique_ptr<Block> load(const Key &key) override;
|
||||||
void remove(std::unique_ptr<Block> block) override;
|
void remove(std::unique_ptr<Block> block) override;
|
||||||
uint64_t numBlocks() const override;
|
uint64_t numBlocks() const override;
|
||||||
|
@ -14,13 +14,15 @@ namespace testfake {
|
|||||||
FakeBlockStore::FakeBlockStore()
|
FakeBlockStore::FakeBlockStore()
|
||||||
: _blocks(), _used_dataregions_for_blocks() {}
|
: _blocks(), _used_dataregions_for_blocks() {}
|
||||||
|
|
||||||
unique_ptr<Block> FakeBlockStore::create(const Key &key, size_t size) {
|
unique_ptr<Block> FakeBlockStore::tryCreate(const Key &key, Data data) {
|
||||||
if (_blocks.find(key.ToString()) != _blocks.end()) {
|
auto insert_result = _blocks.emplace(key.ToString(), std::move(data));
|
||||||
|
|
||||||
|
if (!insert_result.second) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
Data data(size);
|
|
||||||
data.FillWithZeroes();
|
//Return a copy of the stored data
|
||||||
return makeFakeBlockFromData(key, data, true);
|
return load(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ptr<Block> FakeBlockStore::load(const Key &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) {
|
void FakeBlockStore::updateData(const Key &key, const Data &data) {
|
||||||
auto found = _blocks.find(key.ToString());
|
auto found = _blocks.find(key.ToString());
|
||||||
if (found == _blocks.end()) {
|
if (found == _blocks.end()) {
|
||||||
auto insertResult = _blocks.emplace(key.ToString(), data.size());
|
auto insertResult = _blocks.emplace(key.ToString(), data.copy());
|
||||||
assert(true == insertResult.second);
|
assert(true == insertResult.second);
|
||||||
found = insertResult.first;
|
found = insertResult.first;
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ class FakeBlockStore: public BlockStoreWithRandomKeys {
|
|||||||
public:
|
public:
|
||||||
FakeBlockStore();
|
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;
|
std::unique_ptr<Block> load(const Key &key) override;
|
||||||
void remove(std::unique_ptr<Block> block) override;
|
void remove(std::unique_ptr<Block> block) override;
|
||||||
uint64_t numBlocks() const override;
|
uint64_t numBlocks() const override;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include "Block.h"
|
#include "Block.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include "../utils/Data.h"
|
||||||
|
|
||||||
namespace blockstore {
|
namespace blockstore {
|
||||||
|
|
||||||
@ -13,12 +13,23 @@ class BlockStore {
|
|||||||
public:
|
public:
|
||||||
virtual ~BlockStore() {}
|
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)
|
//TODO Use boost::optional (if key doesn't exist)
|
||||||
// Return nullptr if block with this key doesn't exists
|
// Return nullptr if block with this key doesn't exists
|
||||||
virtual std::unique_ptr<Block> load(const Key &key) = 0;
|
virtual std::unique_ptr<Block> load(const Key &key) = 0;
|
||||||
virtual void remove(std::unique_ptr<Block> block) = 0;
|
virtual void remove(std::unique_ptr<Block> block) = 0;
|
||||||
virtual uint64_t numBlocks() const = 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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1 @@
|
|||||||
#include "BlockStoreWithRandomKeys.h"
|
#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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -12,14 +12,9 @@ namespace blockstore {
|
|||||||
// work with the BlockStore interface instead.
|
// work with the BlockStore interface instead.
|
||||||
class BlockStoreWithRandomKeys: public BlockStore {
|
class BlockStoreWithRandomKeys: public BlockStore {
|
||||||
public:
|
public:
|
||||||
//TODO Use boost::optional (if key already exists)
|
Key createKey() final {
|
||||||
// Return nullptr if key already exists
|
return Key::CreateRandom();
|
||||||
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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ public:
|
|||||||
TEST_F(OnDiskBlockCreateTest, CreatingBlockCreatesFile) {
|
TEST_F(OnDiskBlockCreateTest, CreatingBlockCreatesFile) {
|
||||||
EXPECT_FALSE(bf::exists(file.path()));
|
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();
|
block->flush();
|
||||||
|
|
||||||
EXPECT_TRUE(bf::exists(file.path()));
|
EXPECT_TRUE(bf::exists(file.path()));
|
||||||
@ -43,9 +43,9 @@ TEST_F(OnDiskBlockCreateTest, CreatingBlockCreatesFile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OnDiskBlockCreateTest, CreatingExistingBlockReturnsNull) {
|
TEST_F(OnDiskBlockCreateTest, CreatingExistingBlockReturnsNull) {
|
||||||
auto block1 = OnDiskBlock::CreateOnDisk(dir.path(), key, 0);
|
auto block1 = OnDiskBlock::CreateOnDisk(dir.path(), key, Data(0));
|
||||||
block1->flush();
|
block1->flush();
|
||||||
auto block2 = OnDiskBlock::CreateOnDisk(dir.path(), key, 0);
|
auto block2 = OnDiskBlock::CreateOnDisk(dir.path(), key, Data(0));
|
||||||
EXPECT_TRUE((bool)block1);
|
EXPECT_TRUE((bool)block1);
|
||||||
EXPECT_FALSE((bool)block2);
|
EXPECT_FALSE((bool)block2);
|
||||||
}
|
}
|
||||||
@ -56,7 +56,7 @@ public:
|
|||||||
Data ZEROES;
|
Data ZEROES;
|
||||||
|
|
||||||
OnDiskBlockCreateSizeTest():
|
OnDiskBlockCreateSizeTest():
|
||||||
block(OnDiskBlock::CreateOnDisk(dir.path(), key, GetParam())),
|
block(OnDiskBlock::CreateOnDisk(dir.path(), key, std::move(Data(GetParam()).FillWithZeroes()))),
|
||||||
ZEROES(block->size())
|
ZEROES(block->size())
|
||||||
{
|
{
|
||||||
block->flush();
|
block->flush();
|
||||||
|
@ -37,13 +37,17 @@ public:
|
|||||||
|
|
||||||
unique_ptr<OnDiskBlock> CreateBlockAndLoadItFromDisk() {
|
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);
|
return OnDiskBlock::LoadFromDisk(dir.path(), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ptr<OnDiskBlock> CreateBlock() {
|
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) {
|
void WriteDataToBlock(const unique_ptr<OnDiskBlock> &block) {
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
#include "../../../interface/helpers/BlockStoreWithRandomKeys.h"
|
#include "../../../interface/helpers/BlockStoreWithRandomKeys.h"
|
||||||
#include "google/gtest/gtest.h"
|
#include "google/gtest/gtest.h"
|
||||||
#include "google/gmock/gmock.h"
|
#include "google/gmock/gmock.h"
|
||||||
|
#include "../../testutils/DataBlockFixture.h"
|
||||||
|
|
||||||
using ::testing::Test;
|
using ::testing::Test;
|
||||||
using ::testing::_;
|
using ::testing::_;
|
||||||
using ::testing::Return;
|
using ::testing::Return;
|
||||||
using ::testing::Invoke;
|
using ::testing::Invoke;
|
||||||
|
using ::testing::Eq;
|
||||||
|
using ::testing::ByRef;
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::unique_ptr;
|
using std::unique_ptr;
|
||||||
@ -16,10 +18,10 @@ using namespace blockstore;
|
|||||||
|
|
||||||
class BlockStoreWithRandomKeysMock: public BlockStoreWithRandomKeys {
|
class BlockStoreWithRandomKeysMock: public BlockStoreWithRandomKeys {
|
||||||
public:
|
public:
|
||||||
unique_ptr<Block> create(const Key &key, size_t size) {
|
unique_ptr<Block> tryCreate(const Key &key, Data data) {
|
||||||
return unique_ptr<Block>(do_create(key, size));
|
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) {
|
unique_ptr<Block> load(const Key &key) {
|
||||||
return unique_ptr<Block>(do_load(key));
|
return unique_ptr<Block>(do_load(key));
|
||||||
}
|
}
|
||||||
@ -43,78 +45,93 @@ public:
|
|||||||
BlockStoreWithRandomKeysMock blockStoreMock;
|
BlockStoreWithRandomKeysMock blockStoreMock;
|
||||||
BlockStore &blockStore = blockStoreMock;
|
BlockStore &blockStore = blockStoreMock;
|
||||||
const blockstore::Key key = Key::FromString("1491BB4932A389EE14BC7090AC772972");
|
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) {
|
TEST_F(BlockStoreWithRandomKeysTest, DataIsPassedThrough0) {
|
||||||
EXPECT_CALL(blockStoreMock, do_create(_, 0)).WillOnce(Return(new BlockMock));
|
Data data = createDataWithSize(0);
|
||||||
blockStore.create(0);
|
EXPECT_CALL(blockStoreMock, do_create(_, Eq(ByRef(data)))).WillOnce(Return(new BlockMock));
|
||||||
|
blockStore.create(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlockStoreWithRandomKeysTest, SizeIsPassedThrough1) {
|
TEST_F(BlockStoreWithRandomKeysTest, DataIsPassedThrough1) {
|
||||||
EXPECT_CALL(blockStoreMock, do_create(_, 1)).WillOnce(Return(new BlockMock));
|
Data data = createDataWithSize(1);
|
||||||
blockStore.create(1);
|
EXPECT_CALL(blockStoreMock, do_create(_, Eq(ByRef(data)))).WillOnce(Return(new BlockMock));
|
||||||
|
blockStore.create(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlockStoreWithRandomKeysTest, SizeIsPassedThrough1024) {
|
TEST_F(BlockStoreWithRandomKeysTest, DataIsPassedThrough1024) {
|
||||||
EXPECT_CALL(blockStoreMock, do_create(_, 1024)).WillOnce(Return(new BlockMock));
|
Data data = createDataWithSize(1024);
|
||||||
blockStore.create(1024);
|
EXPECT_CALL(blockStoreMock, do_create(_, Eq(ByRef(data)))).WillOnce(Return(new BlockMock));
|
||||||
|
blockStore.create(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlockStoreWithRandomKeysTest, KeyHasCorrectSize) {
|
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());
|
EXPECT_EQ(Key::STRING_LENGTH, key.ToString().size());
|
||||||
return new BlockMock;
|
return new BlockMock;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
blockStore.create(1024);
|
blockStore.create(createDataWithSize(1024));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlockStoreWithRandomKeysTest, TwoBlocksGetDifferentKeys) {
|
TEST_F(BlockStoreWithRandomKeysTest, TwoBlocksGetDifferentKeys) {
|
||||||
Key first_key = key;
|
Key first_key = key;
|
||||||
EXPECT_CALL(blockStoreMock, do_create(_, _))
|
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;
|
first_key = key;
|
||||||
return new BlockMock;
|
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);
|
EXPECT_NE(first_key, key);
|
||||||
return new BlockMock;
|
return new BlockMock;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
blockStore.create(1024);
|
Data data = createDataWithSize(1024);
|
||||||
blockStore.create(1024);
|
blockStore.create(data);
|
||||||
|
blockStore.create(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlockStoreWithRandomKeysTest, WillTryADifferentKeyIfKeyAlreadyExists) {
|
TEST_F(BlockStoreWithRandomKeysTest, WillTryADifferentKeyIfKeyAlreadyExists) {
|
||||||
Key first_key = key;
|
Key first_key = key;
|
||||||
EXPECT_CALL(blockStoreMock, do_create(_, _))
|
Data data = createDataWithSize(1024);
|
||||||
.WillOnce(Invoke([&first_key](const Key &key, size_t) {
|
EXPECT_CALL(blockStoreMock, do_create(_, Eq(ByRef(data))))
|
||||||
|
.WillOnce(Invoke([&first_key](const Key &key, const Data &) {
|
||||||
first_key = key;
|
first_key = key;
|
||||||
return nullptr;
|
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);
|
EXPECT_NE(first_key, key);
|
||||||
return new BlockMock;
|
return new BlockMock;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
blockStore.create(1024);
|
blockStore.create(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlockStoreWithRandomKeysTest, WillTryADifferentKeyIfKeyAlreadyExistsTwoTimes) {
|
TEST_F(BlockStoreWithRandomKeysTest, WillTryADifferentKeyIfKeyAlreadyExistsTwoTimes) {
|
||||||
Key first_key = key;
|
Key first_key = key;
|
||||||
EXPECT_CALL(blockStoreMock, do_create(_, _))
|
Data data = createDataWithSize(1024);
|
||||||
.WillOnce(Invoke([&first_key](const Key &key, size_t) {
|
EXPECT_CALL(blockStoreMock, do_create(_, Eq(ByRef(data))))
|
||||||
|
.WillOnce(Invoke([&first_key](const Key &key, const Data &) {
|
||||||
first_key = key;
|
first_key = key;
|
||||||
return nullptr;
|
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;
|
first_key = key;
|
||||||
return nullptr;
|
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);
|
EXPECT_NE(first_key, key);
|
||||||
return new BlockMock;
|
return new BlockMock;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
blockStore.create(1024);
|
blockStore.create(data);
|
||||||
}
|
}
|
||||||
|
@ -28,14 +28,14 @@ TYPED_TEST_CASE_P(BlockStoreTest);
|
|||||||
|
|
||||||
TYPED_TEST_P(BlockStoreTest, TwoCreatedBlocksHaveDifferentKeys) {
|
TYPED_TEST_P(BlockStoreTest, TwoCreatedBlocksHaveDifferentKeys) {
|
||||||
auto blockStore = this->fixture.createBlockStore();
|
auto blockStore = this->fixture.createBlockStore();
|
||||||
auto block1 = blockStore->create(1024);
|
auto block1 = blockStore->create(blockstore::Data(1024));
|
||||||
auto block2 = blockStore->create(1024);
|
auto block2 = blockStore->create(blockstore::Data(1024));
|
||||||
EXPECT_NE(block1->key(), block2->key());
|
EXPECT_NE(block1->key(), block2->key());
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST_P(BlockStoreTest, BlockIsNotLoadableAfterDeleting) {
|
TYPED_TEST_P(BlockStoreTest, BlockIsNotLoadableAfterDeleting) {
|
||||||
auto blockStore = this->fixture.createBlockStore();
|
auto blockStore = this->fixture.createBlockStore();
|
||||||
auto blockkey = blockStore->create(1024)->key();
|
auto blockkey = blockStore->create(blockstore::Data(1024))->key();
|
||||||
auto block = blockStore->load(blockkey);
|
auto block = blockStore->load(blockkey);
|
||||||
EXPECT_NE(nullptr, block.get());
|
EXPECT_NE(nullptr, block.get());
|
||||||
blockStore->remove(std::move(block));
|
blockStore->remove(std::move(block));
|
||||||
@ -49,55 +49,55 @@ TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectOnEmptyBlockstore) {
|
|||||||
|
|
||||||
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingOneBlock) {
|
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingOneBlock) {
|
||||||
auto blockStore = this->fixture.createBlockStore();
|
auto blockStore = this->fixture.createBlockStore();
|
||||||
auto block = blockStore->create(1);
|
auto block = blockStore->create(blockstore::Data(1));
|
||||||
EXPECT_EQ(1, blockStore->numBlocks());
|
EXPECT_EQ(1, blockStore->numBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingOneBlock_AfterClosingBlock) {
|
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingOneBlock_AfterClosingBlock) {
|
||||||
auto blockStore = this->fixture.createBlockStore();
|
auto blockStore = this->fixture.createBlockStore();
|
||||||
blockStore->create(1);
|
blockStore->create(blockstore::Data(1));
|
||||||
EXPECT_EQ(1, blockStore->numBlocks());
|
EXPECT_EQ(1, blockStore->numBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterRemovingTheLastBlock) {
|
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterRemovingTheLastBlock) {
|
||||||
auto blockStore = this->fixture.createBlockStore();
|
auto blockStore = this->fixture.createBlockStore();
|
||||||
auto block = blockStore->create(1);
|
auto block = blockStore->create(blockstore::Data(1));
|
||||||
blockStore->remove(std::move(block));
|
blockStore->remove(std::move(block));
|
||||||
EXPECT_EQ(0, blockStore->numBlocks());
|
EXPECT_EQ(0, blockStore->numBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks) {
|
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks) {
|
||||||
auto blockStore = this->fixture.createBlockStore();
|
auto blockStore = this->fixture.createBlockStore();
|
||||||
auto block1 = blockStore->create(1);
|
auto block1 = blockStore->create(blockstore::Data(1));
|
||||||
auto block2 = blockStore->create(0);
|
auto block2 = blockStore->create(blockstore::Data(0));
|
||||||
EXPECT_EQ(2, blockStore->numBlocks());
|
EXPECT_EQ(2, blockStore->numBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks_AfterClosingFirstBlock) {
|
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks_AfterClosingFirstBlock) {
|
||||||
auto blockStore = this->fixture.createBlockStore();
|
auto blockStore = this->fixture.createBlockStore();
|
||||||
blockStore->create(1);
|
blockStore->create(blockstore::Data(1));
|
||||||
auto block2 = blockStore->create(0);
|
auto block2 = blockStore->create(blockstore::Data(0));
|
||||||
EXPECT_EQ(2, blockStore->numBlocks());
|
EXPECT_EQ(2, blockStore->numBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks_AfterClosingSecondBlock) {
|
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks_AfterClosingSecondBlock) {
|
||||||
auto blockStore = this->fixture.createBlockStore();
|
auto blockStore = this->fixture.createBlockStore();
|
||||||
auto block1 = blockStore->create(1);
|
auto block1 = blockStore->create(blockstore::Data(1));
|
||||||
blockStore->create(0);
|
blockStore->create(blockstore::Data(0));
|
||||||
EXPECT_EQ(2, blockStore->numBlocks());
|
EXPECT_EQ(2, blockStore->numBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks_AfterClosingBothBlocks) {
|
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks_AfterClosingBothBlocks) {
|
||||||
auto blockStore = this->fixture.createBlockStore();
|
auto blockStore = this->fixture.createBlockStore();
|
||||||
blockStore->create(1);
|
blockStore->create(blockstore::Data(1));
|
||||||
blockStore->create(0);
|
blockStore->create(blockstore::Data(0));
|
||||||
EXPECT_EQ(2, blockStore->numBlocks());
|
EXPECT_EQ(2, blockStore->numBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterRemovingABlock) {
|
TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterRemovingABlock) {
|
||||||
auto blockStore = this->fixture.createBlockStore();
|
auto blockStore = this->fixture.createBlockStore();
|
||||||
auto block = blockStore->create(1);
|
auto block = blockStore->create(blockstore::Data(1));
|
||||||
blockStore->create(1);
|
blockStore->create(blockstore::Data(1));
|
||||||
blockStore->remove(std::move(block));
|
blockStore->remove(std::move(block));
|
||||||
EXPECT_EQ(1, blockStore->numBlocks());
|
EXPECT_EQ(1, blockStore->numBlocks());
|
||||||
}
|
}
|
||||||
@ -109,8 +109,8 @@ TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterRemovingABlock) {
|
|||||||
REGISTER_TYPED_TEST_CASE_P(BlockStoreTest,
|
REGISTER_TYPED_TEST_CASE_P(BlockStoreTest,
|
||||||
CreatedBlockHasCorrectSize,
|
CreatedBlockHasCorrectSize,
|
||||||
LoadingUnchangedBlockHasCorrectSize,
|
LoadingUnchangedBlockHasCorrectSize,
|
||||||
CreatedBlockIsZeroedOut,
|
CreatedBlockData,
|
||||||
LoadingUnchangedBlockIsZeroedOut,
|
LoadingUnchangedBlockData,
|
||||||
LoadedBlockIsCorrect,
|
LoadedBlockIsCorrect,
|
||||||
// LoadedBlockIsCorrectWhenLoadedDirectlyAfterFlushing,
|
// LoadedBlockIsCorrectWhenLoadedDirectlyAfterFlushing,
|
||||||
AfterCreate_FlushingDoesntChangeBlock,
|
AfterCreate_FlushingDoesntChangeBlock,
|
||||||
|
@ -20,7 +20,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TestWriteAndReadImmediately() {
|
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);
|
block->write(foregroundData.data(), testData.offset, testData.count);
|
||||||
|
|
||||||
EXPECT_DATA_READS_AS(foregroundData, *block, testData.offset, testData.count);
|
EXPECT_DATA_READS_AS(foregroundData, *block, testData.offset, testData.count);
|
||||||
@ -36,7 +36,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TestOverwriteAndRead() {
|
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(backgroundData.data(), 0, testData.blocksize);
|
||||||
block->write(foregroundData.data(), testData.offset, testData.count);
|
block->write(foregroundData.data(), testData.offset, testData.count);
|
||||||
EXPECT_DATA_READS_AS(foregroundData, *block, 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) {
|
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);
|
newblock->write(to_write.data(), testData.offset, testData.count);
|
||||||
return newblock->key();
|
return newblock->key();
|
||||||
|
@ -1,29 +1,38 @@
|
|||||||
// This file is meant to be included by BlockStoreTest.h only
|
// This file is meant to be included by BlockStoreTest.h only
|
||||||
|
|
||||||
|
#include "../../utils/Data.h"
|
||||||
|
|
||||||
class BlockStoreSizeParameterizedTest {
|
class BlockStoreSizeParameterizedTest {
|
||||||
public:
|
public:
|
||||||
BlockStoreSizeParameterizedTest(std::unique_ptr<blockstore::BlockStore> blockStore_, size_t size_): blockStore(std::move(blockStore_)), size(size_) {}
|
BlockStoreSizeParameterizedTest(std::unique_ptr<blockstore::BlockStore> blockStore_, size_t size_): blockStore(std::move(blockStore_)), size(size_) {}
|
||||||
|
|
||||||
void TestCreatedBlockHasCorrectSize() {
|
void TestCreatedBlockHasCorrectSize() {
|
||||||
auto block = blockStore->create(size);
|
auto block = CreateBlock();
|
||||||
EXPECT_EQ(size, block->size());
|
EXPECT_EQ(size, block->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestLoadingUnchangedBlockHasCorrectSize() {
|
void TestLoadingUnchangedBlockHasCorrectSize() {
|
||||||
blockstore::Key key = blockStore->create(size)->key();
|
blockstore::Key key = CreateBlock()->key();
|
||||||
auto loaded_block = blockStore->load(key);
|
auto loaded_block = blockStore->load(key);
|
||||||
EXPECT_EQ(size, loaded_block->size());
|
EXPECT_EQ(size, loaded_block->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestCreatedBlockIsZeroedOut() {
|
void TestCreatedBlockData() {
|
||||||
auto block = blockStore->create(size);
|
DataBlockFixture dataFixture(size);
|
||||||
EXPECT_EQ(0, std::memcmp(ZEROES(size).data(), block->data(), 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() {
|
void TestLoadingUnchangedBlockData() {
|
||||||
blockstore::Key key = blockStore->create(size)->key();
|
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);
|
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() {
|
void TestLoadedBlockIsCorrect() {
|
||||||
@ -62,7 +71,7 @@ public:
|
|||||||
DataBlockFixture randomData(size);
|
DataBlockFixture randomData(size);
|
||||||
blockstore::Key key = key;
|
blockstore::Key key = key;
|
||||||
{
|
{
|
||||||
auto block = blockStore->create(size);
|
auto block = blockStore->create(blockstore::Data(size));
|
||||||
key = block->key();
|
key = block->key();
|
||||||
WriteDataToBlock(block.get(), randomData);
|
WriteDataToBlock(block.get(), randomData);
|
||||||
}
|
}
|
||||||
@ -74,7 +83,7 @@ public:
|
|||||||
DataBlockFixture randomData(size);
|
DataBlockFixture randomData(size);
|
||||||
blockstore::Key key = key;
|
blockstore::Key key = key;
|
||||||
{
|
{
|
||||||
key = blockStore->create(size)->key();
|
key = CreateBlock()->key();
|
||||||
auto block = blockStore->load(key);
|
auto block = blockStore->load(key);
|
||||||
WriteDataToBlock(block.get(), randomData);
|
WriteDataToBlock(block.get(), randomData);
|
||||||
}
|
}
|
||||||
@ -104,26 +113,27 @@ private:
|
|||||||
return blockStore->load(key);
|
return blockStore->load(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
blockstore::Key StoreDataToBlockAndGetKey(const DataBlockFixture &data) {
|
blockstore::Key StoreDataToBlockAndGetKey(const DataBlockFixture &dataFixture) {
|
||||||
auto block = blockStore->create(data.size());
|
blockstore::Data data(dataFixture.size());
|
||||||
block->write(data.data(), 0, data.size());
|
std::memcpy(data.data(), dataFixture.data(), dataFixture.size());
|
||||||
return block->key();
|
return blockStore->create(data)->key();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<blockstore::Block> StoreDataToBlockAndLoadItDirectlyAfterFlushing(const DataBlockFixture &data) {
|
std::unique_ptr<blockstore::Block> StoreDataToBlockAndLoadItDirectlyAfterFlushing(const DataBlockFixture &dataFixture) {
|
||||||
auto block = blockStore->create(data.size());
|
blockstore::Data data(dataFixture.size());
|
||||||
block->write(data.data(), 0, data.size());
|
std::memcpy(data.data(), dataFixture.data(), dataFixture.size());
|
||||||
|
auto block = blockStore->create(data);
|
||||||
block->flush();
|
block->flush();
|
||||||
return blockStore->load(block->key());
|
return blockStore->load(block->key());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<blockstore::Block> CreateBlockAndLoadIt() {
|
std::unique_ptr<blockstore::Block> CreateBlockAndLoadIt() {
|
||||||
blockstore::Key key = blockStore->create(size)->key();
|
blockstore::Key key = CreateBlock()->key();
|
||||||
return blockStore->load(key);
|
return blockStore->load(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<blockstore::Block> CreateBlock() {
|
std::unique_ptr<blockstore::Block> CreateBlock() {
|
||||||
return blockStore->create(size);
|
return blockStore->create(blockstore::Data(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteDataToBlock(blockstore::Block *block, const DataBlockFixture &randomData) {
|
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(CreatedBlockHasCorrectSize);
|
||||||
TYPED_TEST_P_FOR_ALL_SIZES(LoadingUnchangedBlockHasCorrectSize);
|
TYPED_TEST_P_FOR_ALL_SIZES(LoadingUnchangedBlockHasCorrectSize);
|
||||||
TYPED_TEST_P_FOR_ALL_SIZES(CreatedBlockIsZeroedOut);
|
TYPED_TEST_P_FOR_ALL_SIZES(CreatedBlockData);
|
||||||
TYPED_TEST_P_FOR_ALL_SIZES(LoadingUnchangedBlockIsZeroedOut);
|
TYPED_TEST_P_FOR_ALL_SIZES(LoadingUnchangedBlockData);
|
||||||
TYPED_TEST_P_FOR_ALL_SIZES(LoadedBlockIsCorrect);
|
TYPED_TEST_P_FOR_ALL_SIZES(LoadedBlockIsCorrect);
|
||||||
//TYPED_TEST_P_FOR_ALL_SIZES(LoadedBlockIsCorrectWhenLoadedDirectlyAfterFlushing);
|
//TYPED_TEST_P_FOR_ALL_SIZES(LoadedBlockIsCorrectWhenLoadedDirectlyAfterFlushing);
|
||||||
TYPED_TEST_P_FOR_ALL_SIZES(AfterCreate_FlushingDoesntChangeBlock);
|
TYPED_TEST_P_FOR_ALL_SIZES(AfterCreate_FlushingDoesntChangeBlock);
|
||||||
|
@ -31,45 +31,45 @@ TYPED_TEST_CASE_P(BlockStoreWithRandomKeysTest);
|
|||||||
|
|
||||||
TYPED_TEST_P(BlockStoreWithRandomKeysTest, CreateTwoBlocksWithSameKeyAndSameSize) {
|
TYPED_TEST_P(BlockStoreWithRandomKeysTest, CreateTwoBlocksWithSameKeyAndSameSize) {
|
||||||
auto blockStore = this->fixture.createBlockStore();
|
auto blockStore = this->fixture.createBlockStore();
|
||||||
auto block = blockStore->create(this->key, 1024);
|
auto block = blockStore->tryCreate(this->key, blockstore::Data(1024));
|
||||||
block->flush();
|
block->flush();
|
||||||
auto block2 = blockStore->create(this->key, 1024);
|
auto block2 = blockStore->tryCreate(this->key, blockstore::Data(1024));
|
||||||
EXPECT_TRUE((bool)block);
|
EXPECT_TRUE((bool)block);
|
||||||
EXPECT_FALSE((bool)block2);
|
EXPECT_FALSE((bool)block2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST_P(BlockStoreWithRandomKeysTest, CreateTwoBlocksWithSameKeyAndDifferentSize) {
|
TYPED_TEST_P(BlockStoreWithRandomKeysTest, CreateTwoBlocksWithSameKeyAndDifferentSize) {
|
||||||
auto blockStore = this->fixture.createBlockStore();
|
auto blockStore = this->fixture.createBlockStore();
|
||||||
auto block = blockStore->create(this->key, 1024);
|
auto block = blockStore->tryCreate(this->key, blockstore::Data(1024));
|
||||||
block->flush();
|
block->flush();
|
||||||
auto block2 = blockStore->create(this->key, 4096);
|
auto block2 = blockStore->tryCreate(this->key, blockstore::Data(4096));
|
||||||
EXPECT_TRUE((bool)block);
|
EXPECT_TRUE((bool)block);
|
||||||
EXPECT_FALSE((bool)block2);
|
EXPECT_FALSE((bool)block2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST_P(BlockStoreWithRandomKeysTest, CreateTwoBlocksWithSameKeyAndFirstNullSize) {
|
TYPED_TEST_P(BlockStoreWithRandomKeysTest, CreateTwoBlocksWithSameKeyAndFirstNullSize) {
|
||||||
auto blockStore = this->fixture.createBlockStore();
|
auto blockStore = this->fixture.createBlockStore();
|
||||||
auto block = blockStore->create(this->key, 0);
|
auto block = blockStore->tryCreate(this->key, blockstore::Data(0));
|
||||||
block->flush();
|
block->flush();
|
||||||
auto block2 = blockStore->create(this->key, 1024);
|
auto block2 = blockStore->tryCreate(this->key, blockstore::Data(1024));
|
||||||
EXPECT_TRUE((bool)block);
|
EXPECT_TRUE((bool)block);
|
||||||
EXPECT_FALSE((bool)block2);
|
EXPECT_FALSE((bool)block2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST_P(BlockStoreWithRandomKeysTest, CreateTwoBlocksWithSameKeyAndSecondNullSize) {
|
TYPED_TEST_P(BlockStoreWithRandomKeysTest, CreateTwoBlocksWithSameKeyAndSecondNullSize) {
|
||||||
auto blockStore = this->fixture.createBlockStore();
|
auto blockStore = this->fixture.createBlockStore();
|
||||||
auto block = blockStore->create(this->key, 1024);
|
auto block = blockStore->tryCreate(this->key, blockstore::Data(1024));
|
||||||
block->flush();
|
block->flush();
|
||||||
auto block2 = blockStore->create(this->key, 0);
|
auto block2 = blockStore->tryCreate(this->key, blockstore::Data(0));
|
||||||
EXPECT_TRUE((bool)block);
|
EXPECT_TRUE((bool)block);
|
||||||
EXPECT_FALSE((bool)block2);
|
EXPECT_FALSE((bool)block2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST_P(BlockStoreWithRandomKeysTest, CreateTwoBlocksWithSameKeyAndBothNullSize) {
|
TYPED_TEST_P(BlockStoreWithRandomKeysTest, CreateTwoBlocksWithSameKeyAndBothNullSize) {
|
||||||
auto blockStore = this->fixture.createBlockStore();
|
auto blockStore = this->fixture.createBlockStore();
|
||||||
auto block = blockStore->create(this->key, 0);
|
auto block = blockStore->tryCreate(this->key, blockstore::Data(0));
|
||||||
block->flush();
|
block->flush();
|
||||||
auto block2 = blockStore->create(this->key, 0);
|
auto block2 = blockStore->tryCreate(this->key, blockstore::Data(0));
|
||||||
EXPECT_TRUE((bool)block);
|
EXPECT_TRUE((bool)block);
|
||||||
EXPECT_FALSE((bool)block2);
|
EXPECT_FALSE((bool)block2);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(BlockStoreUtilsTest, FillWithZeroes) {
|
TEST_F(BlockStoreUtilsTest, FillWithZeroes) {
|
||||||
auto block = blockStore->create(SIZE);
|
auto block = blockStore->create(Data(SIZE));
|
||||||
block->write(dataFixture.data(), 0, SIZE);
|
block->write(dataFixture.data(), 0, SIZE);
|
||||||
EXPECT_NE(0, std::memcmp(ZEROES.data(), block->data(), SIZE));
|
EXPECT_NE(0, std::memcmp(ZEROES.data(), block->data(), SIZE));
|
||||||
fillWithZeroes(block.get());
|
fillWithZeroes(block.get());
|
||||||
@ -43,14 +43,14 @@ TEST_F(BlockStoreUtilsTest, FillWithZeroes) {
|
|||||||
class BlockStoreUtilsTest_CopyToNewBlock: public BlockStoreUtilsTest {};
|
class BlockStoreUtilsTest_CopyToNewBlock: public BlockStoreUtilsTest {};
|
||||||
|
|
||||||
TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyEmptyBlock) {
|
TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyEmptyBlock) {
|
||||||
auto block = blockStore->create(0);
|
auto block = blockStore->create(Data(0));
|
||||||
auto block2 = copyToNewBlock(blockStore.get(), *block);
|
auto block2 = copyToNewBlock(blockStore.get(), *block);
|
||||||
|
|
||||||
EXPECT_EQ(0u, block2->size());
|
EXPECT_EQ(0u, block2->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyZeroBlock) {
|
TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyZeroBlock) {
|
||||||
auto block = blockStore->create(SIZE);
|
auto block = blockStore->create(ZEROES);
|
||||||
auto block2 = copyToNewBlock(blockStore.get(), *block);
|
auto block2 = copyToNewBlock(blockStore.get(), *block);
|
||||||
|
|
||||||
EXPECT_EQ(SIZE, block2->size());
|
EXPECT_EQ(SIZE, block2->size());
|
||||||
@ -58,7 +58,7 @@ TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyZeroBlock) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyDataBlock) {
|
TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyDataBlock) {
|
||||||
auto block = blockStore->create(SIZE);
|
auto block = blockStore->create(Data(SIZE));
|
||||||
block->write(dataFixture.data(), 0, SIZE);
|
block->write(dataFixture.data(), 0, SIZE);
|
||||||
auto block2 = copyToNewBlock(blockStore.get(), *block);
|
auto block2 = copyToNewBlock(blockStore.get(), *block);
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyDataBlock) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlockStoreUtilsTest_CopyToNewBlock, OriginalBlockUnchanged) {
|
TEST_F(BlockStoreUtilsTest_CopyToNewBlock, OriginalBlockUnchanged) {
|
||||||
auto block = blockStore->create(SIZE);
|
auto block = blockStore->create(Data(SIZE));
|
||||||
block->write(dataFixture.data(), 0, SIZE);
|
block->write(dataFixture.data(), 0, SIZE);
|
||||||
auto block2 = copyToNewBlock(blockStore.get(), *block);
|
auto block2 = copyToNewBlock(blockStore.get(), *block);
|
||||||
|
|
||||||
@ -78,14 +78,14 @@ TEST_F(BlockStoreUtilsTest_CopyToNewBlock, OriginalBlockUnchanged) {
|
|||||||
class BlockStoreUtilsTest_CopyToExistingBlock: public BlockStoreUtilsTest {};
|
class BlockStoreUtilsTest_CopyToExistingBlock: public BlockStoreUtilsTest {};
|
||||||
|
|
||||||
TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, CopyEmptyBlock) {
|
TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, CopyEmptyBlock) {
|
||||||
auto block = blockStore->create(0);
|
auto block = blockStore->create(Data(0));
|
||||||
auto block2 = blockStore->create(0);
|
auto block2 = blockStore->create(Data(0));
|
||||||
copyTo(block2.get(), *block);
|
copyTo(block2.get(), *block);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, CopyZeroBlock) {
|
TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, CopyZeroBlock) {
|
||||||
auto block = blockStore->create(SIZE);
|
auto block = blockStore->create(ZEROES);
|
||||||
auto block2 = blockStore->create(SIZE);
|
auto block2 = blockStore->create(Data(SIZE));
|
||||||
block2->write(dataFixture.data(), 0, SIZE);
|
block2->write(dataFixture.data(), 0, SIZE);
|
||||||
copyTo(block2.get(), *block);
|
copyTo(block2.get(), *block);
|
||||||
|
|
||||||
@ -93,18 +93,18 @@ TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, CopyZeroBlock) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, CopyDataBlock) {
|
TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, CopyDataBlock) {
|
||||||
auto block = blockStore->create(SIZE);
|
auto block = blockStore->create(Data(SIZE));
|
||||||
block->write(dataFixture.data(), 0, SIZE);
|
block->write(dataFixture.data(), 0, SIZE);
|
||||||
auto block2 = blockStore->create(SIZE);
|
auto block2 = blockStore->create(Data(SIZE));
|
||||||
copyTo(block2.get(), *block);
|
copyTo(block2.get(), *block);
|
||||||
|
|
||||||
EXPECT_EQ(0, std::memcmp(dataFixture.data(), block2->data(), SIZE));
|
EXPECT_EQ(0, std::memcmp(dataFixture.data(), block2->data(), SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, OriginalBlockUnchanged) {
|
TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, OriginalBlockUnchanged) {
|
||||||
auto block = blockStore->create(SIZE);
|
auto block = blockStore->create(Data(SIZE));
|
||||||
block->write(dataFixture.data(), 0, SIZE);
|
block->write(dataFixture.data(), 0, SIZE);
|
||||||
auto block2 = blockStore->create(SIZE);
|
auto block2 = blockStore->create(Data(SIZE));
|
||||||
copyTo(block2.get(), *block);
|
copyTo(block2.get(), *block);
|
||||||
|
|
||||||
EXPECT_EQ(0, std::memcmp(dataFixture.data(), block->data(), SIZE));
|
EXPECT_EQ(0, std::memcmp(dataFixture.data(), block->data(), SIZE));
|
||||||
|
@ -10,9 +10,9 @@ namespace blockstore {
|
|||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
unique_ptr<Block> copyToNewBlock(BlockStore *blockStore, const Block &block) {
|
unique_ptr<Block> copyToNewBlock(BlockStore *blockStore, const Block &block) {
|
||||||
auto newBlock = blockStore->create(block.size());
|
Data data(block.size());
|
||||||
copyTo(newBlock.get(), block);
|
std::memcpy(data.data(), block.data(), block.size());
|
||||||
return newBlock;
|
return blockStore->create(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyTo(Block *target, const Block &source) {
|
void copyTo(Block *target, const Block &source) {
|
||||||
|
@ -50,8 +50,9 @@ size_t Data::size() const {
|
|||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Data::FillWithZeroes() {
|
Data &Data::FillWithZeroes() {
|
||||||
std::memset(_data, 0, _size);
|
std::memset(_data, 0, _size);
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Data::StoreToFile(const bf::path &filepath) const {
|
void Data::StoreToFile(const bf::path &filepath) const {
|
||||||
@ -92,4 +93,8 @@ void Data::_readFromStream(istream &stream) {
|
|||||||
stream.read((char*)_data, _size);
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ namespace blockstore {
|
|||||||
|
|
||||||
class Data {
|
class Data {
|
||||||
public:
|
public:
|
||||||
Data(size_t size);
|
explicit Data(size_t size);
|
||||||
Data(Data &&rhs); // move constructor
|
Data(Data &&rhs); // move constructor
|
||||||
virtual ~Data();
|
virtual ~Data();
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ public:
|
|||||||
|
|
||||||
size_t size() const;
|
size_t size() const;
|
||||||
|
|
||||||
void FillWithZeroes();
|
Data &FillWithZeroes();
|
||||||
|
|
||||||
void StoreToFile(const boost::filesystem::path &filepath) const;
|
void StoreToFile(const boost::filesystem::path &filepath) const;
|
||||||
static Data LoadFromFile(const boost::filesystem::path &filepath);
|
static Data LoadFromFile(const boost::filesystem::path &filepath);
|
||||||
@ -38,6 +38,9 @@ private:
|
|||||||
DISALLOW_COPY_AND_ASSIGN(Data);
|
DISALLOW_COPY_AND_ASSIGN(Data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//TODO Test operator==
|
||||||
|
bool operator==(const Data &lhs, const Data &rhs);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user