diff --git a/implementations/caching/CachingBlockStore.cpp b/implementations/caching/CachingBlockStore.cpp index e17eafe0..0e152f37 100644 --- a/implementations/caching/CachingBlockStore.cpp +++ b/implementations/caching/CachingBlockStore.cpp @@ -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 baseBlockStore) - :_baseBlockStore(std::move(baseBlockStore)) { + :_baseBlockStore(std::move(baseBlockStore)), _cache(), _numNewBlocks(0) { } -unique_ptr 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(_baseBlockStore->create(size), this); +Key CachingBlockStore::createKey() { + return _baseBlockStore->createKey(); +} + +unique_ptr CachingBlockStore::tryCreate(const Key &key, Data data) { + ++_numNewBlocks; + return make_unique(make_unique(key, std::move(data), this), this); } unique_ptr CachingBlockStore::load(const Key &key) { @@ -37,16 +39,38 @@ unique_ptr CachingBlockStore::load(const Key &key) { } void CachingBlockStore::remove(std::unique_ptr block) { - return _baseBlockStore->remove(std::move(dynamic_pointer_move(block)->releaseBlock())); + auto baseBlock = dynamic_pointer_move(block)->releaseBlock(); + auto baseNewBlock = dynamic_pointer_move(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) { _cache.push(std::move(block)); } +std::unique_ptr 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) { + _baseBlockStore->remove(std::move(block)); +} + } } diff --git a/implementations/caching/CachingBlockStore.h b/implementations/caching/CachingBlockStore.h index c8e40d88..bf9adbc5 100644 --- a/implementations/caching/CachingBlockStore.h +++ b/implementations/caching/CachingBlockStore.h @@ -14,16 +14,21 @@ class CachingBlockStore: public BlockStore { public: CachingBlockStore(std::unique_ptr baseBlockStore); - std::unique_ptr create(size_t size) override; + Key createKey() override; + std::unique_ptr tryCreate(const Key &key, Data data) override; std::unique_ptr load(const Key &key) override; void remove(std::unique_ptr block) override; uint64_t numBlocks() const override; void release(std::unique_ptr block); + std::unique_ptr tryCreateInBaseStore(const Key &key, Data data); + void removeFromBaseStore(std::unique_ptr block); + private: std::unique_ptr _baseBlockStore; Cache _cache; + uint32_t _numNewBlocks; DISALLOW_COPY_AND_ASSIGN(CachingBlockStore); }; diff --git a/implementations/caching/NewBlock.cpp b/implementations/caching/NewBlock.cpp new file mode 100644 index 00000000..edbfeb61 --- /dev/null +++ b/implementations/caching/NewBlock.cpp @@ -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; +} + +} +} diff --git a/implementations/caching/NewBlock.h b/implementations/caching/NewBlock.h new file mode 100644 index 00000000..d71dbf69 --- /dev/null +++ b/implementations/caching/NewBlock.h @@ -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 + +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 _baseBlock; + bool _dataChanged; + + void writeToBaseBlockIfChanged(); + + DISALLOW_COPY_AND_ASSIGN(NewBlock); +}; + +} +} + +#endif diff --git a/implementations/encrypted/EncryptedBlock.cpp b/implementations/encrypted/EncryptedBlock.cpp index ba6bbc49..54adc531 100644 --- a/implementations/encrypted/EncryptedBlock.cpp +++ b/implementations/encrypted/EncryptedBlock.cpp @@ -15,11 +15,15 @@ namespace encrypted { constexpr unsigned int EncryptedBlock::IV_SIZE; -std::unique_ptr EncryptedBlock::CreateNew(std::unique_ptr baseBlock, const EncryptionKey &encKey) { - auto block = make_unique(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::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(std::move(baseBlock), encKey); } EncryptedBlock::EncryptedBlock(std::unique_ptr baseBlock, const EncryptionKey &encKey) @@ -32,7 +36,7 @@ EncryptedBlock::EncryptedBlock(std::unique_ptr 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 = FixedSizeData::CreateRandom(); - auto encryption = CFB_Mode::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 = FixedSizeData::CreateRandom(); + auto encryption = CFB_Mode::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; +} + } } diff --git a/implementations/encrypted/EncryptedBlock.h b/implementations/encrypted/EncryptedBlock.h index 6f9347b6..9fbc8042 100644 --- a/implementations/encrypted/EncryptedBlock.h +++ b/implementations/encrypted/EncryptedBlock.h @@ -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 @@ -19,7 +20,7 @@ public: EncryptedBlock(std::unique_ptr baseBlock, const EncryptionKey &encKey); virtual ~EncryptedBlock(); - static std::unique_ptr CreateNew(std::unique_ptr, const EncryptionKey &encKey); + static std::unique_ptr 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); }; diff --git a/implementations/encrypted/EncryptedBlockStore.cpp b/implementations/encrypted/EncryptedBlockStore.cpp index 1502d31e..f229a9ed 100644 --- a/implementations/encrypted/EncryptedBlockStore.cpp +++ b/implementations/encrypted/EncryptedBlockStore.cpp @@ -13,8 +13,12 @@ EncryptedBlockStore::EncryptedBlockStore(unique_ptr baseBlockStore, : _baseBlockStore(std::move(baseBlockStore)), _encKey(encKey) { } -unique_ptr EncryptedBlockStore::create(size_t size) { - return EncryptedBlock::CreateNew(_baseBlockStore->create(EncryptedBlock::BASE_BLOCK_SIZE(size)), _encKey); +Key EncryptedBlockStore::createKey() { + return _baseBlockStore->createKey(); +} + +unique_ptr EncryptedBlockStore::tryCreate(const Key &key, Data data) { + return EncryptedBlock::TryCreateNew(_baseBlockStore.get(), key, std::move(data), _encKey); } unique_ptr EncryptedBlockStore::load(const Key &key) { @@ -33,5 +37,10 @@ uint64_t EncryptedBlockStore::numBlocks() const { return _baseBlockStore->numBlocks(); } +unique_ptr EncryptedBlockStore::tryCreateInBaseStore(const Key &key, Data encryptedData) { + return _baseBlockStore->tryCreate(key, std::move(encryptedData)); +} + } } + diff --git a/implementations/encrypted/EncryptedBlockStore.h b/implementations/encrypted/EncryptedBlockStore.h index 1590ab6d..bb2a3669 100644 --- a/implementations/encrypted/EncryptedBlockStore.h +++ b/implementations/encrypted/EncryptedBlockStore.h @@ -13,11 +13,14 @@ class EncryptedBlockStore: public BlockStore { public: EncryptedBlockStore(std::unique_ptr baseBlockStore, const EncryptionKey &encKey); - std::unique_ptr create(size_t size) override; + Key createKey() override; + std::unique_ptr tryCreate(const Key &key, Data data) override; std::unique_ptr load(const Key &key) override; void remove(std::unique_ptr block) override; uint64_t numBlocks() const override; + std::unique_ptr tryCreateInBaseStore(const Key &key, Data encryptedData); + private: std::unique_ptr _baseBlockStore; EncryptionKey _encKey; diff --git a/implementations/inmemory/InMemoryBlock.cpp b/implementations/inmemory/InMemoryBlock.cpp index f86ecac8..69d8a142 100644 --- a/implementations/inmemory/InMemoryBlock.cpp +++ b/implementations/inmemory/InMemoryBlock.cpp @@ -13,9 +13,8 @@ using std::ios; namespace blockstore { namespace inmemory { -InMemoryBlock::InMemoryBlock(const Key &key, size_t size) - : Block(key), _data(make_shared(size)) { - _data->FillWithZeroes(); +InMemoryBlock::InMemoryBlock(const Key &key, Data data) + : Block(key), _data(make_shared(std::move(data))) { } InMemoryBlock::InMemoryBlock(const InMemoryBlock &rhs) diff --git a/implementations/inmemory/InMemoryBlock.h b/implementations/inmemory/InMemoryBlock.h index 4790c08d..4efb1553 100644 --- a/implementations/inmemory/InMemoryBlock.h +++ b/implementations/inmemory/InMemoryBlock.h @@ -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(); diff --git a/implementations/inmemory/InMemoryBlockStore.cpp b/implementations/inmemory/InMemoryBlockStore.cpp index 650283ca..3692b965 100644 --- a/implementations/inmemory/InMemoryBlockStore.cpp +++ b/implementations/inmemory/InMemoryBlockStore.cpp @@ -16,8 +16,8 @@ namespace inmemory { InMemoryBlockStore::InMemoryBlockStore() : _blocks() {} -unique_ptr 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 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; diff --git a/implementations/inmemory/InMemoryBlockStore.h b/implementations/inmemory/InMemoryBlockStore.h index f73c7686..3faea85f 100644 --- a/implementations/inmemory/InMemoryBlockStore.h +++ b/implementations/inmemory/InMemoryBlockStore.h @@ -16,7 +16,7 @@ class InMemoryBlockStore: public BlockStoreWithRandomKeys { public: InMemoryBlockStore(); - std::unique_ptr create(const Key &key, size_t size) override; + std::unique_ptr tryCreate(const Key &key, Data data) override; std::unique_ptr load(const Key &key) override; void remove(std::unique_ptr block) override; uint64_t numBlocks() const override; diff --git a/implementations/ondisk/OnDiskBlock.cpp b/implementations/ondisk/OnDiskBlock.cpp index 6bcf580e..4c0f25ef 100644 --- a/implementations/ondisk/OnDiskBlock.cpp +++ b/implementations/ondisk/OnDiskBlock.cpp @@ -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::LoadFromDisk(const bf::path &rootdir, const } } -unique_ptr OnDiskBlock::CreateOnDisk(const bf::path &rootdir, const Key &key, size_t size) { +unique_ptr 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(new OnDiskBlock(key, filepath, size)); - block->_fillDataWithZeroes(); + auto block = unique_ptr(new OnDiskBlock(key, filepath, std::move(data))); + block->_storeToDisk(); return block; } diff --git a/implementations/ondisk/OnDiskBlock.h b/implementations/ondisk/OnDiskBlock.h index 00573873..a139249a 100644 --- a/implementations/ondisk/OnDiskBlock.h +++ b/implementations/ondisk/OnDiskBlock.h @@ -18,7 +18,7 @@ public: virtual ~OnDiskBlock(); static std::unique_ptr LoadFromDisk(const boost::filesystem::path &rootdir, const Key &key); - static std::unique_ptr CreateOnDisk(const boost::filesystem::path &rootdir, const Key &key, size_t size); + static std::unique_ptr 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; diff --git a/implementations/ondisk/OnDiskBlockStore.cpp b/implementations/ondisk/OnDiskBlockStore.cpp index 11459bee..4757807b 100644 --- a/implementations/ondisk/OnDiskBlockStore.cpp +++ b/implementations/ondisk/OnDiskBlockStore.cpp @@ -13,8 +13,8 @@ namespace ondisk { OnDiskBlockStore::OnDiskBlockStore(const boost::filesystem::path &rootdir) : _rootdir(rootdir) {} -unique_ptr OnDiskBlockStore::create(const Key &key, size_t size) { - auto block = OnDiskBlock::CreateOnDisk(_rootdir, key, size); +unique_ptr OnDiskBlockStore::tryCreate(const Key &key, Data data) { + auto block = OnDiskBlock::CreateOnDisk(_rootdir, key, std::move(data)); if (!block) { return nullptr; diff --git a/implementations/ondisk/OnDiskBlockStore.h b/implementations/ondisk/OnDiskBlockStore.h index 4836e64f..3a668d4d 100644 --- a/implementations/ondisk/OnDiskBlockStore.h +++ b/implementations/ondisk/OnDiskBlockStore.h @@ -14,7 +14,7 @@ class OnDiskBlockStore: public BlockStoreWithRandomKeys { public: OnDiskBlockStore(const boost::filesystem::path &rootdir); - std::unique_ptr create(const Key &key, size_t size) override; + std::unique_ptr tryCreate(const Key &key, Data data) override; std::unique_ptr load(const Key &key) override; void remove(std::unique_ptr block) override; uint64_t numBlocks() const override; diff --git a/implementations/parallelaccess/ParallelAccessBlockStore.cpp b/implementations/parallelaccess/ParallelAccessBlockStore.cpp index 9a4b3f47..2f59bb79 100644 --- a/implementations/parallelaccess/ParallelAccessBlockStore.cpp +++ b/implementations/parallelaccess/ParallelAccessBlockStore.cpp @@ -20,9 +20,16 @@ ParallelAccessBlockStore::ParallelAccessBlockStore(unique_ptr baseBl : _baseBlockStore(std::move(baseBlockStore)), _parallelAccessStore(make_unique(_baseBlockStore.get())) { } -unique_ptr ParallelAccessBlockStore::create(size_t size) { - auto block = _baseBlockStore->create(size); - Key key = block->key(); +Key ParallelAccessBlockStore::createKey() { + return _baseBlockStore->createKey(); +} + +unique_ptr 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)); } diff --git a/implementations/parallelaccess/ParallelAccessBlockStore.h b/implementations/parallelaccess/ParallelAccessBlockStore.h index 4aee46d4..7c7c7adf 100644 --- a/implementations/parallelaccess/ParallelAccessBlockStore.h +++ b/implementations/parallelaccess/ParallelAccessBlockStore.h @@ -14,7 +14,8 @@ class ParallelAccessBlockStore: public BlockStore { public: ParallelAccessBlockStore(std::unique_ptr baseBlockStore); - std::unique_ptr create(size_t size) override; + Key createKey() override; + std::unique_ptr tryCreate(const Key &key, Data data) override; std::unique_ptr load(const Key &key) override; void remove(std::unique_ptr block) override; uint64_t numBlocks() const override; diff --git a/implementations/testfake/FakeBlockStore.cpp b/implementations/testfake/FakeBlockStore.cpp index 6d71ee69..50dce405 100644 --- a/implementations/testfake/FakeBlockStore.cpp +++ b/implementations/testfake/FakeBlockStore.cpp @@ -14,13 +14,15 @@ namespace testfake { FakeBlockStore::FakeBlockStore() : _blocks(), _used_dataregions_for_blocks() {} -unique_ptr FakeBlockStore::create(const Key &key, size_t size) { - if (_blocks.find(key.ToString()) != _blocks.end()) { +unique_ptr 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 FakeBlockStore::load(const Key &key) { @@ -49,7 +51,7 @@ unique_ptr 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; } diff --git a/implementations/testfake/FakeBlockStore.h b/implementations/testfake/FakeBlockStore.h index 670d047b..cec32b56 100644 --- a/implementations/testfake/FakeBlockStore.h +++ b/implementations/testfake/FakeBlockStore.h @@ -31,7 +31,7 @@ class FakeBlockStore: public BlockStoreWithRandomKeys { public: FakeBlockStore(); - std::unique_ptr create(const Key &key, size_t size) override; + std::unique_ptr tryCreate(const Key &key, Data data) override; std::unique_ptr load(const Key &key) override; void remove(std::unique_ptr block) override; uint64_t numBlocks() const override; diff --git a/interface/BlockStore.h b/interface/BlockStore.h index b81a99cd..8ea14ed3 100644 --- a/interface/BlockStore.h +++ b/interface/BlockStore.h @@ -5,7 +5,7 @@ #include "Block.h" #include #include - +#include "../utils/Data.h" namespace blockstore { @@ -13,12 +13,23 @@ class BlockStore { public: virtual ~BlockStore() {} - virtual std::unique_ptr create(size_t size) = 0; + virtual Key createKey() = 0; + //Returns nullptr if key already exists + virtual std::unique_ptr 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 load(const Key &key) = 0; virtual void remove(std::unique_ptr block) = 0; virtual uint64_t numBlocks() const = 0; + + std::unique_ptr create(const Data &data) { + std::unique_ptr block(nullptr); + while(block.get() == nullptr) { + //TODO Copy necessary? + block = tryCreate(createKey(), data.copy()); + } + return block; + } }; } diff --git a/interface/helpers/BlockStoreWithRandomKeys.cpp b/interface/helpers/BlockStoreWithRandomKeys.cpp index d5d81885..f9d7c120 100644 --- a/interface/helpers/BlockStoreWithRandomKeys.cpp +++ b/interface/helpers/BlockStoreWithRandomKeys.cpp @@ -1,20 +1 @@ #include "BlockStoreWithRandomKeys.h" - -using namespace blockstore; - -using std::string; -using std::unique_ptr; - -unique_ptr BlockStoreWithRandomKeys::create(size_t size) { - auto result = tryCreate(size); - while (!result) { - result = tryCreate(size); - } - return result; -} - -unique_ptr BlockStoreWithRandomKeys::tryCreate(size_t size) { - Key key = Key::CreateRandom(); - return create(key, size); -} - diff --git a/interface/helpers/BlockStoreWithRandomKeys.h b/interface/helpers/BlockStoreWithRandomKeys.h index e781ed0c..a10ae588 100644 --- a/interface/helpers/BlockStoreWithRandomKeys.h +++ b/interface/helpers/BlockStoreWithRandomKeys.h @@ -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 create(const Key &key, size_t size) = 0; - - std::unique_ptr create(size_t size) final; - -private: - std::unique_ptr tryCreate(size_t size); + Key createKey() final { + return Key::CreateRandom(); + } }; } diff --git a/test/implementations/ondisk/OnDiskBlockTest/OnDiskBlockCreateTest.cpp b/test/implementations/ondisk/OnDiskBlockTest/OnDiskBlockCreateTest.cpp index e47c7279..b098792f 100644 --- a/test/implementations/ondisk/OnDiskBlockTest/OnDiskBlockCreateTest.cpp +++ b/test/implementations/ondisk/OnDiskBlockTest/OnDiskBlockCreateTest.cpp @@ -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(); diff --git a/test/implementations/ondisk/OnDiskBlockTest/OnDiskBlockFlushTest.cpp b/test/implementations/ondisk/OnDiskBlockTest/OnDiskBlockFlushTest.cpp index d11b0936..23e49fd2 100644 --- a/test/implementations/ondisk/OnDiskBlockTest/OnDiskBlockFlushTest.cpp +++ b/test/implementations/ondisk/OnDiskBlockTest/OnDiskBlockFlushTest.cpp @@ -37,13 +37,17 @@ public: unique_ptr 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 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 &block) { diff --git a/test/interface/helpers/BlockStoreWithRandomKeysTest.cpp b/test/interface/helpers/BlockStoreWithRandomKeysTest.cpp index 2b4d926f..fa0109a6 100644 --- a/test/interface/helpers/BlockStoreWithRandomKeysTest.cpp +++ b/test/interface/helpers/BlockStoreWithRandomKeysTest.cpp @@ -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 create(const Key &key, size_t size) { - return unique_ptr(do_create(key, size)); + unique_ptr tryCreate(const Key &key, Data data) { + return unique_ptr(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 load(const Key &key) { return unique_ptr(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); } diff --git a/test/testutils/BlockStoreTest.h b/test/testutils/BlockStoreTest.h index fb143056..ad7d940c 100644 --- a/test/testutils/BlockStoreTest.h +++ b/test/testutils/BlockStoreTest.h @@ -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, diff --git a/test/testutils/BlockStoreTest_Data.h b/test/testutils/BlockStoreTest_Data.h index bcdfd8a8..11dfa2ac 100644 --- a/test/testutils/BlockStoreTest_Data.h +++ b/test/testutils/BlockStoreTest_Data.h @@ -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(); diff --git a/test/testutils/BlockStoreTest_Size.h b/test/testutils/BlockStoreTest_Size.h index 1e9ad262..5948d836 100644 --- a/test/testutils/BlockStoreTest_Size.h +++ b/test/testutils/BlockStoreTest_Size.h @@ -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_, 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 StoreDataToBlockAndLoadItDirectlyAfterFlushing(const DataBlockFixture &data) { - auto block = blockStore->create(data.size()); - block->write(data.data(), 0, data.size()); + std::unique_ptr 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 CreateBlockAndLoadIt() { - blockstore::Key key = blockStore->create(size)->key(); + blockstore::Key key = CreateBlock()->key(); return blockStore->load(key); } std::unique_ptr 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 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); diff --git a/test/testutils/BlockStoreWithRandomKeysTest.h b/test/testutils/BlockStoreWithRandomKeysTest.h index 1ed93e06..03d64cab 100644 --- a/test/testutils/BlockStoreWithRandomKeysTest.h +++ b/test/testutils/BlockStoreWithRandomKeysTest.h @@ -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); } diff --git a/test/utils/BlockStoreUtilsTest.cpp b/test/utils/BlockStoreUtilsTest.cpp index d4681854..93515636 100644 --- a/test/utils/BlockStoreUtilsTest.cpp +++ b/test/utils/BlockStoreUtilsTest.cpp @@ -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)); diff --git a/utils/BlockStoreUtils.cpp b/utils/BlockStoreUtils.cpp index d104265d..e6c33e2c 100644 --- a/utils/BlockStoreUtils.cpp +++ b/utils/BlockStoreUtils.cpp @@ -10,9 +10,9 @@ namespace blockstore { namespace utils { unique_ptr 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) { diff --git a/utils/Data.cpp b/utils/Data.cpp index 2750c20f..4895f727 100644 --- a/utils/Data.cpp +++ b/utils/Data.cpp @@ -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()); +} + } diff --git a/utils/Data.h b/utils/Data.h index 6b3d341c..54d5ccc7 100644 --- a/utils/Data.h +++ b/utils/Data.h @@ -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