Skip to content

Commit

Permalink
Single Pointer Cache (#1604)
Browse files Browse the repository at this point in the history
Signed-off-by: Akvinikym <anarant12@gmail.com>
  • Loading branch information
Akvinikym committed Jul 29, 2018
1 parent d1a47e6 commit 8ea9f48
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 0 deletions.
76 changes: 76 additions & 0 deletions libs/cache/single_pointer_cache.hpp
@@ -0,0 +1,76 @@
/**
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef IROHA_SINGLE_POINTER_CACHE_HPP
#define IROHA_SINGLE_POINTER_CACHE_HPP

#include <memory>
#include <mutex>

namespace iroha {
namespace cache {

/**
* Thread-safely stores and returns shared pointer to an element of template
* type
*/
template <typename DataType>
class SinglePointerCache {
public:
/**
* Pointer to data type
*/
using DataPointer = std::shared_ptr<DataType>;

/**
* Insert data to the cache
* @param pointer to the data to be inserted
*/
void insert(DataPointer data);

/**
* Get data from the cache
* @return pointer to the stored data
*/
DataPointer get() const;

/**
* Delete data inside the cache
*/
void release();

private:
DataPointer stored_data_;

mutable std::mutex mutex_;
};

template <typename DataType>
void SinglePointerCache<DataType>::insert(
SinglePointerCache::DataPointer data) {
std::lock_guard<std::mutex> lock(mutex_);

stored_data_ = std::move(data);
}

template <typename DataType>
typename SinglePointerCache<DataType>::DataPointer
SinglePointerCache<DataType>::get() const {
std::lock_guard<std::mutex> lock(mutex_);

return stored_data_;
}

template <typename DataType>
void SinglePointerCache<DataType>::release() {
std::lock_guard<std::mutex> lock(mutex_);

stored_data_.reset();
}

} // namespace cache
} // namespace iroha

#endif // IROHA_SINGLE_POINTER_CACHE_HPP
2 changes: 2 additions & 0 deletions test/module/libs/cache/CMakeLists.txt
Expand Up @@ -16,3 +16,5 @@ addtest(cache_test cache_test.cpp)
target_link_libraries(cache_test
torii_service
)

addtest(single_pointer_cache_test single_pointer_cache_test.cpp)
107 changes: 107 additions & 0 deletions test/module/libs/cache/single_pointer_cache_test.cpp
@@ -0,0 +1,107 @@
/**
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#include <condition_variable>
#include <thread>

#include <gtest/gtest.h>

#include "cache/single_pointer_cache.hpp"

using namespace iroha::cache;

class SinglePointerCacheTest : public ::testing::Test {
using SinglePointerIntCache = SinglePointerCache<int>;

protected:
void SetUp() override {
int_cache.release();
}

SinglePointerIntCache int_cache;
const int default_int_value = 5;
};

/**
* @given empty int cache
* @when trying to get the value inside
* @then cache will return nullptr
*/
TEST_F(SinglePointerCacheTest, GetWhenEmpty) {
ASSERT_FALSE(int_cache.get());
}

/**
* @given empty int cache
* @when inserting some value into it @and trying to get it
* @then cache will return the inserted value
*/
TEST_F(SinglePointerCacheTest, Insert) {
int_cache.insert(std::make_shared<int>(default_int_value));
ASSERT_EQ(*int_cache.get(), default_int_value);
}

/**
* @given empty int cache
* @when inserting some value into it @and releasing the cache @and trying to
* get value inside
* @then cache will return nullptr
*/
TEST_F(SinglePointerCacheTest, Release) {
int_cache.insert(std::make_shared<int>(default_int_value));
ASSERT_TRUE(int_cache.get());

int_cache.release();
ASSERT_FALSE(int_cache.get());
}

/**
* @given empty int cache
* @when several readers reading values from cache @and several writers writing
* values to the cache @and releaser emptyfying the cache are spawned
* @then the system must not crash
*/
TEST_F(SinglePointerCacheTest, MultithreadedCache) {
constexpr std::chrono::milliseconds sleep_interval{100};
constexpr int run_times{10};

auto read = [this, &sleep_interval] {
// if cache is not empty, read the value; otherwise do nothing
for (auto i = 0; i < run_times; ++i) {
auto value_ptr = int_cache.get();
if (value_ptr) {
ASSERT_NO_THROW(*value_ptr);
}
std::this_thread::sleep_for(sleep_interval);
}
};
auto write_one = [this, &sleep_interval] {
// just write to cache
for (auto i = 0; i < run_times; i++) {
std::this_thread::sleep_for(sleep_interval);
int_cache.insert(std::make_shared<int>(i));
}
};
auto write_two = [this, &sleep_interval] {
// just write to cache
for (auto i = run_times; i > 0; --i) {
std::this_thread::sleep_for(sleep_interval);
int_cache.insert(std::make_shared<int>(i));
}
};
auto release = [this, &sleep_interval] {
// release the cache
for (auto i = 0; i < run_times; ++i) {
int_cache.release();
std::this_thread::sleep_for(sleep_interval);
}
};

std::thread writer_one{write_one}, reader{read}, releaser{release}, writer_two{write_two};
writer_one.join();
reader.join();
releaser.join();
writer_two.join();
}

0 comments on commit 8ea9f48

Please sign in to comment.