Finish MockBlockStore to also collect other performance metrics, and implement the standard block store tests for it.
This commit is contained in:
parent
fdcd3b1314
commit
d626349802
@ -32,6 +32,8 @@ set(SOURCES
|
|||||||
implementations/versioncounting/KnownBlockVersions.cpp
|
implementations/versioncounting/KnownBlockVersions.cpp
|
||||||
implementations/versioncounting/ClientIdAndBlockKey.cpp
|
implementations/versioncounting/ClientIdAndBlockKey.cpp
|
||||||
implementations/versioncounting/IntegrityViolationError.cpp
|
implementations/versioncounting/IntegrityViolationError.cpp
|
||||||
|
implementations/mock/MockBlockStore.cpp
|
||||||
|
implementations/mock/MockBlock.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
||||||
|
18
src/blockstore/implementations/mock/MockBlock.cpp
Normal file
18
src/blockstore/implementations/mock/MockBlock.cpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include "MockBlock.h"
|
||||||
|
#include "MockBlockStore.h"
|
||||||
|
|
||||||
|
namespace blockstore {
|
||||||
|
namespace mock {
|
||||||
|
|
||||||
|
void MockBlock::write(const void *source, uint64_t offset, uint64_t size) {
|
||||||
|
_blockStore->_increaseNumWrittenBlocks(key());
|
||||||
|
return _baseBlock->write(source, offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MockBlock::resize(size_t newSize) {
|
||||||
|
_blockStore->_increaseNumResizedBlocks(key());
|
||||||
|
return _baseBlock->resize(newSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
50
src/blockstore/implementations/mock/MockBlock.h
Normal file
50
src/blockstore/implementations/mock/MockBlock.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_MOCK_MOCKBLOCK_H_
|
||||||
|
#define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_MOCK_MOCKBLOCK_H_
|
||||||
|
|
||||||
|
#include <blockstore/interface/Block.h>
|
||||||
|
#include <cpp-utils/pointer/unique_ref.h>
|
||||||
|
|
||||||
|
namespace blockstore {
|
||||||
|
namespace mock {
|
||||||
|
|
||||||
|
class MockBlockStore;
|
||||||
|
|
||||||
|
class MockBlock final : public blockstore::Block {
|
||||||
|
public:
|
||||||
|
MockBlock(cpputils::unique_ref<blockstore::Block> baseBlock, MockBlockStore *blockStore)
|
||||||
|
:Block(baseBlock->key()), _baseBlock(std::move(baseBlock)), _blockStore(blockStore) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *data() const override {
|
||||||
|
return _baseBlock->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(const void *source, uint64_t offset, uint64_t size) override;
|
||||||
|
|
||||||
|
void flush() override {
|
||||||
|
return _baseBlock->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const override {
|
||||||
|
return _baseBlock->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize(size_t newSize) override;
|
||||||
|
|
||||||
|
cpputils::unique_ref<blockstore::Block> releaseBaseBlock() {
|
||||||
|
return std::move(_baseBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
cpputils::unique_ref<blockstore::Block> _baseBlock;
|
||||||
|
MockBlockStore *_blockStore;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(MockBlock);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
1
src/blockstore/implementations/mock/MockBlockStore.cpp
Normal file
1
src/blockstore/implementations/mock/MockBlockStore.cpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "MockBlockStore.h"
|
143
src/blockstore/implementations/mock/MockBlockStore.h
Normal file
143
src/blockstore/implementations/mock/MockBlockStore.h
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_MOCK_MOCKBLOCKSTORE_H_
|
||||||
|
#define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_MOCK_MOCKBLOCKSTORE_H_
|
||||||
|
|
||||||
|
#include <blockstore/implementations/testfake/FakeBlockStore.h>
|
||||||
|
#include <mutex>
|
||||||
|
#include "MockBlock.h"
|
||||||
|
|
||||||
|
namespace blockstore {
|
||||||
|
namespace mock {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a blockstore that counts the number of loaded, resized, written, ... blocks.
|
||||||
|
* It is used for testing that operations only access few blocks (performance tests).
|
||||||
|
*/
|
||||||
|
class MockBlockStore final : public BlockStore {
|
||||||
|
public:
|
||||||
|
MockBlockStore(cpputils::unique_ref<BlockStore> baseBlockStore = cpputils::make_unique_ref<testfake::FakeBlockStore>())
|
||||||
|
: _mutex(), _baseBlockStore(std::move(baseBlockStore)), _loadedBlocks(), _createdBlocks(0), _writtenBlocks(), _resizedBlocks(), _removedBlocks() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Key createKey() override {
|
||||||
|
return _baseBlockStore->createKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<cpputils::unique_ref<Block>> tryCreate(const Key &key, cpputils::Data data) override {
|
||||||
|
_increaseNumCreatedBlocks();
|
||||||
|
auto base = _baseBlockStore->tryCreate(key, std::move(data));
|
||||||
|
if (base == boost::none) {
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
return boost::optional<cpputils::unique_ref<Block>>(cpputils::make_unique_ref<MockBlock>(std::move(*base), this));
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<cpputils::unique_ref<Block>> load(const Key &key) override {
|
||||||
|
_increaseNumLoadedBlocks(key);
|
||||||
|
auto base = _baseBlockStore->load(key);
|
||||||
|
if (base == boost::none) {
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
return boost::optional<cpputils::unique_ref<Block>>(cpputils::make_unique_ref<MockBlock>(std::move(*base), this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(const Key &key) override {
|
||||||
|
_increaseNumRemovedBlocks(key);
|
||||||
|
return _baseBlockStore->remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t numBlocks() const override {
|
||||||
|
return _baseBlockStore->numBlocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t estimateNumFreeBytes() const override {
|
||||||
|
return _baseBlockStore->estimateNumFreeBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t blockSizeFromPhysicalBlockSize(uint64_t blockSize) const override {
|
||||||
|
return _baseBlockStore->blockSizeFromPhysicalBlockSize(blockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void forEachBlock(std::function<void(const Key &)> callback) const override {
|
||||||
|
return _baseBlockStore->forEachBlock(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(cpputils::unique_ref<Block> block) override {
|
||||||
|
_increaseNumRemovedBlocks(block->key());
|
||||||
|
auto mockBlock = cpputils::dynamic_pointer_move<MockBlock>(block);
|
||||||
|
ASSERT(mockBlock != boost::none, "Wrong block type");
|
||||||
|
return _baseBlockStore->remove((*mockBlock)->releaseBaseBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetCounters() {
|
||||||
|
_loadedBlocks = {};
|
||||||
|
_createdBlocks = 0;
|
||||||
|
_removedBlocks = {};
|
||||||
|
_resizedBlocks = {};
|
||||||
|
_writtenBlocks = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t createdBlocks() const {
|
||||||
|
return _createdBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Key> loadedBlocks() const {
|
||||||
|
return _loadedBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Key> removedBlocks() const {
|
||||||
|
return _removedBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Key> resizedBlocks() const {
|
||||||
|
return _resizedBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Key> writtenBlocks() const {
|
||||||
|
return _writtenBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _increaseNumCreatedBlocks() {
|
||||||
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
|
_createdBlocks += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _increaseNumLoadedBlocks(const Key &key) {
|
||||||
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
|
_loadedBlocks.push_back(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _increaseNumRemovedBlocks(const Key &key) {
|
||||||
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
|
_removedBlocks.push_back(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _increaseNumResizedBlocks(const Key &key) {
|
||||||
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
|
_resizedBlocks.push_back(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _increaseNumWrittenBlocks(const Key &key) {
|
||||||
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
|
_writtenBlocks.push_back(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend class MockBlock;
|
||||||
|
|
||||||
|
std::mutex _mutex;
|
||||||
|
cpputils::unique_ref<BlockStore> _baseBlockStore;
|
||||||
|
|
||||||
|
std::vector<Key> _loadedBlocks;
|
||||||
|
uint64_t _createdBlocks;
|
||||||
|
std::vector<Key> _writtenBlocks;
|
||||||
|
std::vector<Key> _resizedBlocks;
|
||||||
|
std::vector<Key> _removedBlocks;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(MockBlockStore);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -28,8 +28,8 @@ TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Twolevel_DeleteByTree)
|
|||||||
|
|
||||||
treeStore.remove(std::move(tree));
|
treeStore.remove(std::move(tree));
|
||||||
|
|
||||||
EXPECT_EQ(1u, blockStore->loadedBlocks.size()); // First loading is from loading the tree, second one from removing it (i.e. loading the root)
|
EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // First loading is from loading the tree, second one from removing it (i.e. loading the root)
|
||||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Twolevel_DeleteByKey) {
|
TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Twolevel_DeleteByKey) {
|
||||||
@ -38,8 +38,8 @@ TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Twolevel_DeleteByKey)
|
|||||||
|
|
||||||
treeStore.remove(key);
|
treeStore.remove(key);
|
||||||
|
|
||||||
EXPECT_EQ(1u, blockStore->loadedBlocks.size());
|
EXPECT_EQ(1u, blockStore->loadedBlocks().size());
|
||||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByTree) {
|
TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByTree) {
|
||||||
@ -49,8 +49,8 @@ TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByTre
|
|||||||
|
|
||||||
treeStore.remove(std::move(tree));
|
treeStore.remove(std::move(tree));
|
||||||
|
|
||||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks.size());
|
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size());
|
||||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByKey) {
|
TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByKey) {
|
||||||
@ -59,8 +59,8 @@ TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByKey
|
|||||||
|
|
||||||
treeStore.remove(key);
|
treeStore.remove(key);
|
||||||
|
|
||||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks.size());
|
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size());
|
||||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_All) {
|
TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_All) {
|
||||||
@ -70,8 +70,8 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_All) {
|
|||||||
|
|
||||||
Traverse(tree.get(), 0, maxChildrenPerInnerNode);
|
Traverse(tree.get(), 0, maxChildrenPerInnerNode);
|
||||||
|
|
||||||
EXPECT_EQ(maxChildrenPerInnerNode, blockStore->loadedBlocks.size()); // Loads all leaves (not the root, because it is already loaded in the tree)
|
EXPECT_EQ(maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); // Loads all leaves (not the root, because it is already loaded in the tree)
|
||||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_Some) {
|
TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_Some) {
|
||||||
@ -81,8 +81,8 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_Some) {
|
|||||||
|
|
||||||
Traverse(tree.get(), 3, 5);
|
Traverse(tree.get(), 3, 5);
|
||||||
|
|
||||||
EXPECT_EQ(2u, blockStore->loadedBlocks.size()); // Loads both leaves (not the root, because it is already loaded in the tree)
|
EXPECT_EQ(2u, blockStore->loadedBlocks().size()); // Loads both leaves (not the root, because it is already loaded in the tree)
|
||||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_All) {
|
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_All) {
|
||||||
@ -92,8 +92,8 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_All) {
|
|||||||
|
|
||||||
Traverse(tree.get(), 0, maxChildrenPerInnerNode * maxChildrenPerInnerNode);
|
Traverse(tree.get(), 0, maxChildrenPerInnerNode * maxChildrenPerInnerNode);
|
||||||
|
|
||||||
EXPECT_EQ(maxChildrenPerInnerNode + maxChildrenPerInnerNode * maxChildrenPerInnerNode, blockStore->loadedBlocks.size()); // Loads inner nodes and all leaves once (not the root, because it is already loaded in the tree)
|
EXPECT_EQ(maxChildrenPerInnerNode + maxChildrenPerInnerNode * maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); // Loads inner nodes and all leaves once (not the root, because it is already loaded in the tree)
|
||||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InOneInner) {
|
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InOneInner) {
|
||||||
@ -103,8 +103,8 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InOneInner) {
|
|||||||
|
|
||||||
Traverse(tree.get(), 3, 5);
|
Traverse(tree.get(), 3, 5);
|
||||||
|
|
||||||
EXPECT_EQ(3u, blockStore->loadedBlocks.size()); // Loads inner node and both leaves (not the root, because it is already loaded in the tree)
|
EXPECT_EQ(3u, blockStore->loadedBlocks().size()); // Loads inner node and both leaves (not the root, because it is already loaded in the tree)
|
||||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InTwoInner) {
|
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InTwoInner) {
|
||||||
@ -114,8 +114,8 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InTwoInner) {
|
|||||||
|
|
||||||
Traverse(tree.get(), 3, 3 + maxChildrenPerInnerNode);
|
Traverse(tree.get(), 3, 3 + maxChildrenPerInnerNode);
|
||||||
|
|
||||||
EXPECT_EQ(2u + maxChildrenPerInnerNode, blockStore->loadedBlocks.size()); // Loads inner node and both leaves (not the root, because it is already loaded in the tree)
|
EXPECT_EQ(2u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); // Loads inner node and both leaves (not the root, because it is already loaded in the tree)
|
||||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_WholeInner) {
|
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_WholeInner) {
|
||||||
@ -125,8 +125,8 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_WholeInner) {
|
|||||||
|
|
||||||
Traverse(tree.get(), maxChildrenPerInnerNode, 2*maxChildrenPerInnerNode);
|
Traverse(tree.get(), maxChildrenPerInnerNode, 2*maxChildrenPerInnerNode);
|
||||||
|
|
||||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks.size()); // Loads inner node and leaves (not the root, because it is already loaded in the tree)f
|
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); // Loads inner node and leaves (not the root, because it is already loaded in the tree)f
|
||||||
EXPECT_EQ(0u, blockStore->createdBlocks);
|
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingInside) {
|
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingInside) {
|
||||||
@ -136,8 +136,8 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingInside) {
|
|||||||
|
|
||||||
Traverse(tree.get(), 1, 4);
|
Traverse(tree.get(), 1, 4);
|
||||||
|
|
||||||
EXPECT_EQ(1u, blockStore->loadedBlocks.size()); // Loads last old child (for growing it)
|
EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old child (for growing it)
|
||||||
EXPECT_EQ(2u, blockStore->createdBlocks);
|
EXPECT_EQ(2u, blockStore->createdBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_TwoLevel) {
|
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_TwoLevel) {
|
||||||
@ -147,8 +147,8 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_TwoL
|
|||||||
|
|
||||||
Traverse(tree.get(), 4, 5);
|
Traverse(tree.get(), 4, 5);
|
||||||
|
|
||||||
EXPECT_EQ(1u, blockStore->loadedBlocks.size()); // Loads last old leaf for growing it
|
EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it
|
||||||
EXPECT_EQ(3u, blockStore->createdBlocks);
|
EXPECT_EQ(3u, blockStore->createdBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_ThreeLevel) {
|
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_ThreeLevel) {
|
||||||
@ -158,8 +158,8 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_Thre
|
|||||||
|
|
||||||
Traverse(tree.get(), 2*maxChildrenPerInnerNode+1, 2*maxChildrenPerInnerNode+2);
|
Traverse(tree.get(), 2*maxChildrenPerInnerNode+1, 2*maxChildrenPerInnerNode+2);
|
||||||
|
|
||||||
EXPECT_EQ(2u, blockStore->loadedBlocks.size()); // Loads last old leaf (and its inner node) for growing it
|
EXPECT_EQ(2u, blockStore->loadedBlocks().size()); // Loads last old leaf (and its inner node) for growing it
|
||||||
EXPECT_EQ(3u, blockStore->createdBlocks); // inner node and two leaves
|
EXPECT_EQ(3u, blockStore->createdBlocks()); // inner node and two leaves
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingAtBeginOfChild) {
|
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingAtBeginOfChild) {
|
||||||
@ -169,8 +169,8 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingAtBeginOfChi
|
|||||||
|
|
||||||
Traverse(tree.get(), maxChildrenPerInnerNode, 3*maxChildrenPerInnerNode);
|
Traverse(tree.get(), maxChildrenPerInnerNode, 3*maxChildrenPerInnerNode);
|
||||||
|
|
||||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks.size()); // Inner node and its leaves
|
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); // Inner node and its leaves
|
||||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->createdBlocks); // Creates an inner node and its leaves
|
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->createdBlocks()); // Creates an inner node and its leaves
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInOldDepth) {
|
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInOldDepth) {
|
||||||
@ -180,8 +180,8 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInOldDe
|
|||||||
|
|
||||||
Traverse(tree.get(), 4, maxChildrenPerInnerNode+2);
|
Traverse(tree.get(), 4, maxChildrenPerInnerNode+2);
|
||||||
|
|
||||||
EXPECT_EQ(1u, blockStore->loadedBlocks.size()); // Loads last old leaf for growing it
|
EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it
|
||||||
EXPECT_EQ(2 + maxChildrenPerInnerNode, blockStore->createdBlocks); // 2x new inner node + leaves
|
EXPECT_EQ(2 + maxChildrenPerInnerNode, blockStore->createdBlocks()); // 2x new inner node + leaves
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInNewDepth) {
|
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInNewDepth) {
|
||||||
@ -191,6 +191,6 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInNewDe
|
|||||||
|
|
||||||
Traverse(tree.get(), maxChildrenPerInnerNode, maxChildrenPerInnerNode+2);
|
Traverse(tree.get(), maxChildrenPerInnerNode, maxChildrenPerInnerNode+2);
|
||||||
|
|
||||||
EXPECT_EQ(1u, blockStore->loadedBlocks.size()); // Loads last old leaf for growing it
|
EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it
|
||||||
EXPECT_EQ(2 + maxChildrenPerInnerNode, blockStore->createdBlocks); // 2x new inner node + leaves
|
EXPECT_EQ(2 + maxChildrenPerInnerNode, blockStore->createdBlocks()); // 2x new inner node + leaves
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ using blobstore::onblocks::datanodestore::DataNode;
|
|||||||
using blobstore::onblocks::datanodestore::DataInnerNode;
|
using blobstore::onblocks::datanodestore::DataInnerNode;
|
||||||
using blobstore::onblocks::datanodestore::DataLeafNode;
|
using blobstore::onblocks::datanodestore::DataLeafNode;
|
||||||
using blobstore::onblocks::datatreestore::DataTree;
|
using blobstore::onblocks::datatreestore::DataTree;
|
||||||
using blockstore::testfake::FakeBlockStore;
|
using blockstore::mock::MockBlockStore;
|
||||||
using blockstore::Key;
|
using blockstore::Key;
|
||||||
using cpputils::unique_ref;
|
using cpputils::unique_ref;
|
||||||
using cpputils::make_unique_ref;
|
using cpputils::make_unique_ref;
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#include "blobstore/implementations/onblocks/datanodestore/DataLeafNode.h"
|
#include "blobstore/implementations/onblocks/datanodestore/DataLeafNode.h"
|
||||||
#include "blobstore/implementations/onblocks/datatreestore/DataTree.h"
|
#include "blobstore/implementations/onblocks/datatreestore/DataTree.h"
|
||||||
#include "blobstore/implementations/onblocks/datatreestore/DataTreeStore.h"
|
#include "blobstore/implementations/onblocks/datatreestore/DataTreeStore.h"
|
||||||
#include "MockBlockStore.h"
|
#include "blockstore/implementations/mock/MockBlockStore.h"
|
||||||
|
|
||||||
class DataTreeTest: public ::testing::Test {
|
class DataTreeTest: public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
@ -46,8 +46,8 @@ public:
|
|||||||
cpputils::unique_ref<blobstore::onblocks::datanodestore::DataInnerNode> CreateFullThreeLevelWithLastLeafSize(uint32_t size);
|
cpputils::unique_ref<blobstore::onblocks::datanodestore::DataInnerNode> CreateFullThreeLevelWithLastLeafSize(uint32_t size);
|
||||||
cpputils::unique_ref<blobstore::onblocks::datanodestore::DataInnerNode> CreateFourLevelMinDataWithLastLeafSize(uint32_t size);
|
cpputils::unique_ref<blobstore::onblocks::datanodestore::DataInnerNode> CreateFourLevelMinDataWithLastLeafSize(uint32_t size);
|
||||||
|
|
||||||
cpputils::unique_ref<MockBlockStore> _blockStore;
|
cpputils::unique_ref<blockstore::mock::MockBlockStore> _blockStore;
|
||||||
MockBlockStore *blockStore;
|
blockstore::mock::MockBlockStore *blockStore;
|
||||||
cpputils::unique_ref<blobstore::onblocks::datanodestore::DataNodeStore> _nodeStore;
|
cpputils::unique_ref<blobstore::onblocks::datanodestore::DataNodeStore> _nodeStore;
|
||||||
blobstore::onblocks::datanodestore::DataNodeStore *nodeStore;
|
blobstore::onblocks::datanodestore::DataNodeStore *nodeStore;
|
||||||
blobstore::onblocks::datatreestore::DataTreeStore treeStore;
|
blobstore::onblocks::datatreestore::DataTreeStore treeStore;
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_GROWING_TESTUTILS_MOCKBLOCKSTORE_H_
|
|
||||||
#define MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_GROWING_TESTUTILS_MOCKBLOCKSTORE_H_
|
|
||||||
|
|
||||||
#include <gmock/gmock.h>
|
|
||||||
#include <blockstore/implementations/testfake/FakeBlockStore.h>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
class MockBlockStore final : public blockstore::BlockStore {
|
|
||||||
public:
|
|
||||||
MockBlockStore(cpputils::unique_ref<BlockStore> baseBlockStore = cpputils::make_unique_ref<blockstore::testfake::FakeBlockStore>())
|
|
||||||
: loadedBlocks(), createdBlocks(0), _mutex(), _baseBlockStore(std::move(baseBlockStore)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
blockstore::Key createKey() override {
|
|
||||||
return _baseBlockStore->createKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::optional<cpputils::unique_ref<blockstore::Block>> tryCreate(const blockstore::Key &key, cpputils::Data data) override {
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(_mutex);
|
|
||||||
createdBlocks += 1;
|
|
||||||
}
|
|
||||||
return _baseBlockStore->tryCreate(key, std::move(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::optional<cpputils::unique_ref<blockstore::Block>> load(const blockstore::Key &key) override {
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(_mutex);
|
|
||||||
loadedBlocks.push_back(key);
|
|
||||||
}
|
|
||||||
return _baseBlockStore->load(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove(const blockstore::Key &key) override {
|
|
||||||
return _baseBlockStore->remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t numBlocks() const override {
|
|
||||||
return _baseBlockStore->numBlocks();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t estimateNumFreeBytes() const override {
|
|
||||||
return _baseBlockStore->estimateNumFreeBytes();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t blockSizeFromPhysicalBlockSize(uint64_t blockSize) const override {
|
|
||||||
return _baseBlockStore->blockSizeFromPhysicalBlockSize(blockSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void forEachBlock(std::function<void(const blockstore::Key &)> callback) const override {
|
|
||||||
return _baseBlockStore->forEachBlock(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove(cpputils::unique_ref<blockstore::Block> block) override {
|
|
||||||
return _baseBlockStore->remove(std::move(block));
|
|
||||||
}
|
|
||||||
|
|
||||||
void resetCounters() {
|
|
||||||
loadedBlocks = {};
|
|
||||||
createdBlocks = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<blockstore::Key> loadedBlocks;
|
|
||||||
uint64_t createdBlocks;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::mutex _mutex;
|
|
||||||
cpputils::unique_ref<blockstore::BlockStore> _baseBlockStore;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -6,6 +6,7 @@ set(SOURCES
|
|||||||
interface/BlockStoreTest.cpp
|
interface/BlockStoreTest.cpp
|
||||||
interface/BlockTest.cpp
|
interface/BlockTest.cpp
|
||||||
implementations/testfake/TestFakeBlockStoreTest.cpp
|
implementations/testfake/TestFakeBlockStoreTest.cpp
|
||||||
|
implementations/mock/MockBlockStoreTest.cpp
|
||||||
implementations/inmemory/InMemoryBlockStoreTest.cpp
|
implementations/inmemory/InMemoryBlockStoreTest.cpp
|
||||||
implementations/parallelaccess/ParallelAccessBlockStoreTest_Generic.cpp
|
implementations/parallelaccess/ParallelAccessBlockStoreTest_Generic.cpp
|
||||||
implementations/parallelaccess/ParallelAccessBlockStoreTest_Specific.cpp
|
implementations/parallelaccess/ParallelAccessBlockStoreTest_Specific.cpp
|
||||||
|
22
test/blockstore/implementations/mock/MockBlockStoreTest.cpp
Normal file
22
test/blockstore/implementations/mock/MockBlockStoreTest.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "blockstore/implementations/mock/MockBlock.h"
|
||||||
|
#include "blockstore/implementations/mock/MockBlockStore.h"
|
||||||
|
#include "../../testutils/BlockStoreTest.h"
|
||||||
|
#include "../../testutils/BlockStoreWithRandomKeysTest.h"
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <cpp-utils/pointer/unique_ref_boost_optional_gtest_workaround.h>
|
||||||
|
|
||||||
|
using blockstore::BlockStore;
|
||||||
|
using blockstore::BlockStoreWithRandomKeys;
|
||||||
|
using blockstore::mock::MockBlockStore;
|
||||||
|
using blockstore::testfake::FakeBlockStore;
|
||||||
|
using cpputils::unique_ref;
|
||||||
|
using cpputils::make_unique_ref;
|
||||||
|
|
||||||
|
class MockBlockStoreTestFixture: public BlockStoreTestFixture {
|
||||||
|
public:
|
||||||
|
unique_ref<BlockStore> createBlockStore() override {
|
||||||
|
return make_unique_ref<MockBlockStore>(make_unique_ref<FakeBlockStore>());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
INSTANTIATE_TYPED_TEST_CASE_P(Mock, BlockStoreTest, MockBlockStoreTestFixture);
|
Loading…
Reference in New Issue
Block a user