From e6918187568dbd01842d8d1d2c808ce16a894239 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 21 Apr 2024 13:54:28 +0200 Subject: Adding upstream version 18.2.2. Signed-off-by: Daniel Baumann --- src/test/immutable_object_cache/CMakeLists.txt | 37 ++++ src/test/immutable_object_cache/MockCacheDaemon.h | 45 ++++ .../immutable_object_cache/test_DomainSocket.cc | 177 ++++++++++++++++ .../immutable_object_cache/test_SimplePolicy.cc | 235 +++++++++++++++++++++ src/test/immutable_object_cache/test_common.h | 41 ++++ src/test/immutable_object_cache/test_main.cc | 29 +++ src/test/immutable_object_cache/test_message.cc | 50 +++++ .../immutable_object_cache/test_multi_session.cc | 162 ++++++++++++++ .../immutable_object_cache/test_object_store.cc | 99 +++++++++ 9 files changed, 875 insertions(+) create mode 100644 src/test/immutable_object_cache/CMakeLists.txt create mode 100644 src/test/immutable_object_cache/MockCacheDaemon.h create mode 100644 src/test/immutable_object_cache/test_DomainSocket.cc create mode 100644 src/test/immutable_object_cache/test_SimplePolicy.cc create mode 100644 src/test/immutable_object_cache/test_common.h create mode 100644 src/test/immutable_object_cache/test_main.cc create mode 100644 src/test/immutable_object_cache/test_message.cc create mode 100644 src/test/immutable_object_cache/test_multi_session.cc create mode 100644 src/test/immutable_object_cache/test_object_store.cc (limited to 'src/test/immutable_object_cache') diff --git a/src/test/immutable_object_cache/CMakeLists.txt b/src/test/immutable_object_cache/CMakeLists.txt new file mode 100644 index 000000000..e4ed3d459 --- /dev/null +++ b/src/test/immutable_object_cache/CMakeLists.txt @@ -0,0 +1,37 @@ + +add_executable(unittest_ceph_immutable_obj_cache + test_main.cc + test_SimplePolicy.cc + test_DomainSocket.cc + test_multi_session.cc + test_object_store.cc + test_message.cc + ) +add_ceph_unittest(unittest_ceph_immutable_obj_cache) + + +target_link_libraries(unittest_ceph_immutable_obj_cache + ceph_immutable_object_cache_lib + rados_test_stub + librados + global + radostest-cxx + StdFilesystem::filesystem + GTest::GTest + ) + + +add_executable(ceph_test_immutable_obj_cache + test_main.cc + ) + +target_link_libraries(ceph_test_immutable_obj_cache + librados + radostest-cxx + ${UNITTEST_LIBS} + ) + + +install(TARGETS + ceph_test_immutable_obj_cache + DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/test/immutable_object_cache/MockCacheDaemon.h b/src/test/immutable_object_cache/MockCacheDaemon.h new file mode 100644 index 000000000..02e86acb2 --- /dev/null +++ b/src/test/immutable_object_cache/MockCacheDaemon.h @@ -0,0 +1,45 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef IMMUTABLE_OBJECT_CACHE_MOCK_DAEMON +#define IMMUTABLE_OBJECT_CACHE_MOCK_DAEMON + +#include +#include + +#include "gmock/gmock.h" + +#include "include/Context.h" +#include "tools/immutable_object_cache/CacheClient.h" + +namespace ceph { +namespace immutable_obj_cache { + +class MockCacheClient { + public: + MockCacheClient(const std::string& file, CephContext* ceph_ctx) {} + MOCK_METHOD0(run, void()); + MOCK_METHOD0(is_session_work, bool()); + MOCK_METHOD0(close, void()); + MOCK_METHOD0(stop, void()); + MOCK_METHOD0(connect, int()); + MOCK_METHOD1(connect, void(Context*)); + MOCK_METHOD6(lookup_object, void(std::string, uint64_t, uint64_t, uint64_t, + std::string, CacheGenContextURef)); + MOCK_METHOD1(register_client, int(Context*)); +}; + +class MockCacheServer { + public: + MockCacheServer(CephContext* cct, const std::string& file, + ProcessMsg processmsg) { + } + MOCK_METHOD0(run, int()); + MOCK_METHOD0(start_accept, int()); + MOCK_METHOD0(stop, int()); +}; + +} // namespace immutable_obj_cach3 +} // namespace ceph + +#endif // IMMUTABLE_OBJECT_CACHE_MOCK_DAEMON diff --git a/src/test/immutable_object_cache/test_DomainSocket.cc b/src/test/immutable_object_cache/test_DomainSocket.cc new file mode 100644 index 000000000..31d1b9adc --- /dev/null +++ b/src/test/immutable_object_cache/test_DomainSocket.cc @@ -0,0 +1,177 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include +#include + +#include "gtest/gtest.h" +#include "include/Context.h" +#include "global/global_init.h" +#include "global/global_context.h" + +#include "test/immutable_object_cache/test_common.h" +#include "tools/immutable_object_cache/CacheClient.h" +#include "tools/immutable_object_cache/CacheServer.h" + +using namespace ceph::immutable_obj_cache; + +class TestCommunication :public ::testing::Test { +public: + CacheServer* m_cache_server; + std::thread* srv_thd; + CacheClient* m_cache_client; + std::string m_local_path; + pthread_mutex_t m_mutex; + pthread_cond_t m_cond; + std::atomic m_send_request_index; + std::atomic m_recv_ack_index; + WaitEvent m_wait_event; + unordered_set m_hit_entry_set; + + TestCommunication() + : m_cache_server(nullptr), m_cache_client(nullptr), + m_local_path("/tmp/ceph_test_domain_socket"), + m_send_request_index(0), m_recv_ack_index(0) + {} + + ~TestCommunication() {} + + static void SetUpTestCase() {} + static void TearDownTestCase() {} + + void SetUp() override { + std::remove(m_local_path.c_str()); + m_cache_server = new CacheServer(g_ceph_context, m_local_path, + [this](CacheSession* sid, ObjectCacheRequest* req){ + handle_request(sid, req); + }); + ASSERT_TRUE(m_cache_server != nullptr); + srv_thd = new std::thread([this]() {m_cache_server->run();}); + + m_cache_client = new CacheClient(m_local_path, g_ceph_context); + ASSERT_TRUE(m_cache_client != nullptr); + m_cache_client->run(); + + while (true) { + if (0 == m_cache_client->connect()) { + break; + } + } + + auto ctx = new LambdaContext([](int reg) { + ASSERT_TRUE(reg == 0); + }); + m_cache_client->register_client(ctx); + ASSERT_TRUE(m_cache_client->is_session_work()); + } + + void TearDown() override { + + delete m_cache_client; + m_cache_server->stop(); + if (srv_thd->joinable()) { + srv_thd->join(); + } + delete m_cache_server; + std::remove(m_local_path.c_str()); + delete srv_thd; + } + + void handle_request(CacheSession* session_id, ObjectCacheRequest* req) { + + switch (req->get_request_type()) { + case RBDSC_REGISTER: { + ObjectCacheRequest* reply = new ObjectCacheRegReplyData(RBDSC_REGISTER_REPLY, req->seq); + session_id->send(reply); + break; + } + case RBDSC_READ: { + ObjectCacheReadData* read_req = (ObjectCacheReadData*)req; + ObjectCacheRequest* reply = nullptr; + if (m_hit_entry_set.find(read_req->oid) == m_hit_entry_set.end()) { + reply = new ObjectCacheReadRadosData(RBDSC_READ_RADOS, req->seq); + } else { + reply = new ObjectCacheReadReplyData(RBDSC_READ_REPLY, req->seq, "/fakepath"); + } + session_id->send(reply); + break; + } + } + } + + // times: message number + // queue_depth : imitate message queue depth + // thinking : imitate handing message time + void startup_pingpong_testing(uint64_t times, uint64_t queue_depth, int thinking) { + m_send_request_index.store(0); + m_recv_ack_index.store(0); + for (uint64_t index = 0; index < times; index++) { + auto ctx = make_gen_lambda_context> + ([this, thinking, times](ObjectCacheRequest* ack){ + if (thinking != 0) { + usleep(thinking); // handling message + } + m_recv_ack_index++; + if (m_recv_ack_index == times) { + m_wait_event.signal(); + } + }); + + // simple queue depth + while (m_send_request_index - m_recv_ack_index > queue_depth) { + usleep(1); + } + + m_cache_client->lookup_object("pool_nspace", 1, 2, 3, "object_name", std::move(ctx)); + m_send_request_index++; + } + m_wait_event.wait(); + } + + bool startup_lookupobject_testing(std::string pool_nspace, std::string object_id) { + bool hit; + auto ctx = make_gen_lambda_context> + ([this, &hit](ObjectCacheRequest* ack){ + hit = ack->type == RBDSC_READ_REPLY; + m_wait_event.signal(); + }); + m_cache_client->lookup_object(pool_nspace, 1, 2, 3, object_id, std::move(ctx)); + m_wait_event.wait(); + return hit; + } + + void set_hit_entry_in_fake_lru(std::string cache_file_name) { + if (m_hit_entry_set.find(cache_file_name) == m_hit_entry_set.end()) { + m_hit_entry_set.insert(cache_file_name); + } + } +}; + +TEST_F(TestCommunication, test_pingpong) { + + startup_pingpong_testing(64, 16, 0); + ASSERT_TRUE(m_send_request_index == m_recv_ack_index); + startup_pingpong_testing(200, 128, 0); + ASSERT_TRUE(m_send_request_index == m_recv_ack_index); +} + +TEST_F(TestCommunication, test_lookup_object) { + + m_hit_entry_set.clear(); + + srand(time(0)); + uint64_t random_hit = random(); + + for (uint64_t i = 50; i < 100; i++) { + if ((random_hit % i) == 0) { + set_hit_entry_in_fake_lru(std::to_string(i)); + } + } + for (uint64_t i = 50; i < 100; i++) { + if ((random_hit % i) != 0) { + ASSERT_FALSE(startup_lookupobject_testing("test_nspace", std::to_string(i))); + } else { + ASSERT_TRUE(startup_lookupobject_testing("test_nspace", std::to_string(i))); + } + } +} diff --git a/src/test/immutable_object_cache/test_SimplePolicy.cc b/src/test/immutable_object_cache/test_SimplePolicy.cc new file mode 100644 index 000000000..26f503be4 --- /dev/null +++ b/src/test/immutable_object_cache/test_SimplePolicy.cc @@ -0,0 +1,235 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include +#include +#include + +#include "include/Context.h" +#include "tools/immutable_object_cache/SimplePolicy.h" + +using namespace ceph::immutable_obj_cache; + +std::string generate_file_name(uint64_t index) { + std::string pre_name("object_cache_file_"); + std::ostringstream oss; + oss << index; + return pre_name + oss.str(); +} + +class TestSimplePolicy :public ::testing::Test { +public: + SimplePolicy* m_simple_policy; + const uint64_t m_cache_size; + uint64_t m_entry_index; + std::vector m_promoted_lru; + std::vector m_promoting_lru; + + TestSimplePolicy() : m_cache_size(100), m_entry_index(0) {} + ~TestSimplePolicy() {} + static void SetUpTestCase() {} + static void TearDownTestCase() {} + void SetUp() override { + m_simple_policy = new SimplePolicy(g_ceph_context, m_cache_size, 128, 0.9); + // populate 50 entries + for (uint64_t i = 0; i < m_cache_size / 2; i++, m_entry_index++) { + insert_entry_into_promoted_lru(generate_file_name(m_entry_index)); + } + } + void TearDown() override { + while(m_promoted_lru.size()) { + ASSERT_TRUE(m_simple_policy->get_evict_entry() == m_promoted_lru.front()); + m_simple_policy->evict_entry(m_simple_policy->get_evict_entry()); + m_promoted_lru.erase(m_promoted_lru.begin()); + } + delete m_simple_policy; + } + + void insert_entry_into_promoted_lru(std::string cache_file_name) { + ASSERT_EQ(m_cache_size - m_promoted_lru.size(), m_simple_policy->get_free_size()); + ASSERT_EQ(m_promoting_lru.size(), m_simple_policy->get_promoting_entry_num()); + ASSERT_EQ(m_promoted_lru.size(), m_simple_policy->get_promoted_entry_num()); + ASSERT_EQ(OBJ_CACHE_NONE, m_simple_policy->get_status(cache_file_name)); + + m_simple_policy->lookup_object(cache_file_name); + ASSERT_EQ(OBJ_CACHE_SKIP, m_simple_policy->get_status(cache_file_name)); + ASSERT_EQ(m_cache_size - m_promoted_lru.size(), m_simple_policy->get_free_size()); + ASSERT_EQ(m_promoting_lru.size() + 1, m_simple_policy->get_promoting_entry_num()); + ASSERT_EQ(m_promoted_lru.size(), m_simple_policy->get_promoted_entry_num()); + + m_simple_policy->update_status(cache_file_name, OBJ_CACHE_PROMOTED, 1); + m_promoted_lru.push_back(cache_file_name); + ASSERT_EQ(OBJ_CACHE_PROMOTED, m_simple_policy->get_status(cache_file_name)); + + ASSERT_EQ(m_cache_size - m_promoted_lru.size(), m_simple_policy->get_free_size()); + ASSERT_EQ(m_promoting_lru.size(), m_simple_policy->get_promoting_entry_num()); + ASSERT_EQ(m_promoted_lru.size(), m_simple_policy->get_promoted_entry_num()); + } + + void insert_entry_into_promoting_lru(std::string cache_file_name) { + ASSERT_EQ(m_cache_size - m_promoted_lru.size(), m_simple_policy->get_free_size()); + ASSERT_EQ(m_promoting_lru.size(), m_simple_policy->get_promoting_entry_num()); + ASSERT_EQ(m_promoted_lru.size(), m_simple_policy->get_promoted_entry_num()); + ASSERT_EQ(OBJ_CACHE_NONE, m_simple_policy->get_status(cache_file_name)); + + m_simple_policy->lookup_object(cache_file_name); + m_promoting_lru.push_back(cache_file_name); + ASSERT_EQ(OBJ_CACHE_SKIP, m_simple_policy->get_status(cache_file_name)); + ASSERT_EQ(m_cache_size - m_promoted_lru.size(), m_simple_policy->get_free_size()); + ASSERT_EQ(m_promoting_lru.size(), m_simple_policy->get_promoting_entry_num()); + ASSERT_EQ(m_promoted_lru.size(), m_simple_policy->get_promoted_entry_num()); + } +}; + +TEST_F(TestSimplePolicy, test_lookup_miss_and_no_free) { + // exhaust cache space + uint64_t left_entry_num = m_cache_size - m_promoted_lru.size(); + for (uint64_t i = 0; i < left_entry_num; i++, ++m_entry_index) { + insert_entry_into_promoted_lru(generate_file_name(m_entry_index)); + } + ASSERT_TRUE(0 == m_simple_policy->get_free_size()); + ASSERT_TRUE(m_simple_policy->lookup_object("no_this_cache_file_name") == OBJ_CACHE_SKIP); +} + +TEST_F(TestSimplePolicy, test_lookup_miss_and_have_free) { + ASSERT_TRUE(m_cache_size - m_promoted_lru.size() == m_simple_policy->get_free_size()); + ASSERT_TRUE(m_simple_policy->lookup_object("miss_but_have_free_space_file_name") == OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_status("miss_but_have_free_space_file_name") == OBJ_CACHE_SKIP); +} + +TEST_F(TestSimplePolicy, test_lookup_hit_and_promoting) { + ASSERT_TRUE(m_cache_size - m_promoted_lru.size() == m_simple_policy->get_free_size()); + insert_entry_into_promoting_lru("promoting_file_1"); + insert_entry_into_promoting_lru("promoting_file_2"); + insert_entry_into_promoted_lru(generate_file_name(++m_entry_index)); + insert_entry_into_promoted_lru(generate_file_name(++m_entry_index)); + insert_entry_into_promoting_lru("promoting_file_3"); + insert_entry_into_promoting_lru("promoting_file_4"); + + ASSERT_TRUE(m_simple_policy->get_promoting_entry_num() == 4); + ASSERT_TRUE(m_simple_policy->get_status("promoting_file_1") == OBJ_CACHE_SKIP); + ASSERT_TRUE(m_simple_policy->get_status("promoting_file_2") == OBJ_CACHE_SKIP); + ASSERT_TRUE(m_simple_policy->get_status("promoting_file_3") == OBJ_CACHE_SKIP); + ASSERT_TRUE(m_simple_policy->get_status("promoting_file_4") == OBJ_CACHE_SKIP); + ASSERT_TRUE(m_simple_policy->lookup_object("promoting_file_1") == OBJ_CACHE_SKIP); + ASSERT_TRUE(m_simple_policy->lookup_object("promoting_file_2") == OBJ_CACHE_SKIP); + ASSERT_TRUE(m_simple_policy->lookup_object("promoting_file_3") == OBJ_CACHE_SKIP); + ASSERT_TRUE(m_simple_policy->lookup_object("promoting_file_4") == OBJ_CACHE_SKIP); +} + +TEST_F(TestSimplePolicy, test_lookup_hit_and_promoted) { + ASSERT_TRUE(m_promoted_lru.size() == m_simple_policy->get_promoted_entry_num()); + for (uint64_t index = 0; index < m_entry_index; index++) { + ASSERT_TRUE(m_simple_policy->get_status(generate_file_name(index)) == OBJ_CACHE_PROMOTED); + } +} + +TEST_F(TestSimplePolicy, test_update_state_from_promoting_to_none) { + ASSERT_TRUE(m_cache_size - m_promoted_lru.size() == m_simple_policy->get_free_size()); + insert_entry_into_promoting_lru("promoting_to_none_file_1"); + insert_entry_into_promoting_lru("promoting_to_none_file_2"); + insert_entry_into_promoted_lru(generate_file_name(++m_entry_index)); + insert_entry_into_promoting_lru("promoting_to_none_file_3"); + insert_entry_into_promoting_lru("promoting_to_none_file_4"); + + ASSERT_TRUE(m_simple_policy->get_promoting_entry_num() == 4); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_1") == OBJ_CACHE_SKIP); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_2") == OBJ_CACHE_SKIP); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_3") == OBJ_CACHE_SKIP); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_4") == OBJ_CACHE_SKIP); + + m_simple_policy->update_status("promoting_to_none_file_1", OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_promoting_entry_num() == 3); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_1") == OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_2") == OBJ_CACHE_SKIP); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_3") == OBJ_CACHE_SKIP); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_4") == OBJ_CACHE_SKIP); + + m_simple_policy->update_status("promoting_to_none_file_2", OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_promoting_entry_num() == 2); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_1") == OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_2") == OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_3") == OBJ_CACHE_SKIP); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_4") == OBJ_CACHE_SKIP); + + m_simple_policy->update_status("promoting_to_none_file_3", OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_promoting_entry_num() == 1); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_1") == OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_2") == OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_3") == OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_4") == OBJ_CACHE_SKIP); + + m_simple_policy->update_status("promoting_to_none_file_4", OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_promoting_entry_num() == 0); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_1") == OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_2") == OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_3") == OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_none_file_4") == OBJ_CACHE_NONE); +} + +TEST_F(TestSimplePolicy, test_update_state_from_promoted_to_none) { + ASSERT_TRUE(m_promoted_lru.size() == m_simple_policy->get_promoted_entry_num()); + for (uint64_t index = 0; index < m_entry_index; index++) { + ASSERT_TRUE(m_simple_policy->get_status(generate_file_name(index)) == OBJ_CACHE_PROMOTED); + m_simple_policy->update_status(generate_file_name(index), OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_status(generate_file_name(index)) == OBJ_CACHE_NONE); + ASSERT_TRUE(m_simple_policy->get_promoted_entry_num() == m_promoted_lru.size() - index - 1); + } + m_promoted_lru.clear(); +} + +TEST_F(TestSimplePolicy, test_update_state_from_promoting_to_promoted) { + ASSERT_TRUE(m_cache_size - m_promoted_lru.size() == m_simple_policy->get_free_size()); + insert_entry_into_promoting_lru("promoting_to_promoted_file_1"); + insert_entry_into_promoting_lru("promoting_to_promoted_file_2"); + insert_entry_into_promoting_lru("promoting_to_promoted_file_3"); + insert_entry_into_promoting_lru("promoting_to_promoted_file_4"); + ASSERT_TRUE(4 == m_simple_policy->get_promoting_entry_num()); + + m_simple_policy->update_status("promoting_to_promoted_file_1", OBJ_CACHE_PROMOTED); + ASSERT_TRUE(3 == m_simple_policy->get_promoting_entry_num()); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_promoted_file_1") == OBJ_CACHE_PROMOTED); + + m_simple_policy->update_status("promoting_to_promoted_file_2", OBJ_CACHE_PROMOTED); + ASSERT_TRUE(2 == m_simple_policy->get_promoting_entry_num()); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_promoted_file_2") == OBJ_CACHE_PROMOTED); + + m_simple_policy->update_status("promoting_to_promoted_file_3", OBJ_CACHE_PROMOTED); + ASSERT_TRUE(1 == m_simple_policy->get_promoting_entry_num()); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_promoted_file_3") == OBJ_CACHE_PROMOTED); + + m_simple_policy->update_status("promoting_to_promoted_file_4", OBJ_CACHE_PROMOTED); + ASSERT_TRUE(0 == m_simple_policy->get_promoting_entry_num()); + ASSERT_TRUE(m_simple_policy->get_status("promoting_to_promoted_file_4") == OBJ_CACHE_PROMOTED); + + m_promoted_lru.push_back("promoting_to_promoted_file_1"); + m_promoted_lru.push_back("promoting_to_promoted_file_2"); + m_promoted_lru.push_back("promoting_to_promoted_file_3"); + m_promoted_lru.push_back("promoting_to_promoted_file_4"); +} + +TEST_F(TestSimplePolicy, test_evict_list_0) { + std::list evict_entry_list; + // the default water mark is 0.9 + ASSERT_TRUE((float)m_simple_policy->get_free_size() > m_cache_size*0.1); + m_simple_policy->get_evict_list(&evict_entry_list); + ASSERT_TRUE(evict_entry_list.size() == 0); +} + +TEST_F(TestSimplePolicy, test_evict_list_10) { + uint64_t left_entry_num = m_cache_size - m_promoted_lru.size(); + for (uint64_t i = 0; i < left_entry_num; i++, ++m_entry_index) { + insert_entry_into_promoted_lru(generate_file_name(m_entry_index)); + } + ASSERT_TRUE(0 == m_simple_policy->get_free_size()); + std::list evict_entry_list; + m_simple_policy->get_evict_list(&evict_entry_list); + // evict 10% of old entries + ASSERT_TRUE(m_cache_size*0.1 == evict_entry_list.size()); + ASSERT_TRUE(m_cache_size - m_cache_size*0.1 == m_simple_policy->get_promoted_entry_num()); + + for (auto it = evict_entry_list.begin(); it != evict_entry_list.end(); it++) { + ASSERT_TRUE(*it == m_promoted_lru.front()); + m_promoted_lru.erase(m_promoted_lru.begin()); + } +} diff --git a/src/test/immutable_object_cache/test_common.h b/src/test/immutable_object_cache/test_common.h new file mode 100644 index 000000000..9d6fd14c7 --- /dev/null +++ b/src/test/immutable_object_cache/test_common.h @@ -0,0 +1,41 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +#ifndef CACHE_TEST_COMMON_H +#define CACHE_TEST_COMMON_H + +#include + +class WaitEvent { +public: + WaitEvent() : m_signaled(false) { + pthread_mutex_init(&m_lock, NULL); + pthread_cond_init(&m_cond, NULL); + } + + ~WaitEvent() { + pthread_mutex_destroy(&m_lock); + pthread_cond_destroy(&m_cond); + } + + void wait() { + pthread_mutex_lock(&m_lock); + while (!m_signaled) { + pthread_cond_wait(&m_cond, &m_lock); + } + m_signaled = false; + pthread_mutex_unlock(&m_lock); + } + + void signal() { + pthread_mutex_lock(&m_lock); + m_signaled = true; + pthread_cond_signal(&m_cond); + pthread_mutex_unlock(&m_lock); + } +private: + pthread_mutex_t m_lock; + pthread_cond_t m_cond; + bool m_signaled; +}; + +#endif diff --git a/src/test/immutable_object_cache/test_main.cc b/src/test/immutable_object_cache/test_main.cc new file mode 100644 index 000000000..571627e0b --- /dev/null +++ b/src/test/immutable_object_cache/test_main.cc @@ -0,0 +1,29 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "include/rados/librados.hpp" +#include "global/global_context.h" +#include "test/librados/test_cxx.h" +#include "gtest/gtest.h" +#include +#include + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + + librados::Rados rados; + std::string result = connect_cluster_pp(rados); + if (result != "" ) { + std::cerr << result << std::endl; + return 1; + } + + g_ceph_context = reinterpret_cast(rados.cct()); + + int r = rados.conf_set("lockdep", "true"); + if (r < 0) { + std::cerr << "warning: failed to enable lockdep" << std::endl; + } + return RUN_ALL_TESTS(); +} diff --git a/src/test/immutable_object_cache/test_message.cc b/src/test/immutable_object_cache/test_message.cc new file mode 100644 index 000000000..bbd6ad165 --- /dev/null +++ b/src/test/immutable_object_cache/test_message.cc @@ -0,0 +1,50 @@ +#include "gtest/gtest.h" +#include "tools/immutable_object_cache/Types.h" +#include "tools/immutable_object_cache/SocketCommon.h" + +using namespace ceph::immutable_obj_cache; + +TEST(test_for_message, test_1) +{ + std::string pool_nspace("this is a pool namespace"); + std::string oid_name("this is a oid name"); + std::string cache_file_path("/temp/ceph_immutable_object_cache"); + + uint16_t type = RBDSC_READ; + uint64_t seq = 123456UL; + uint64_t read_offset = 222222UL; + uint64_t read_len = 333333UL; + uint64_t pool_id = 444444UL; + uint64_t snap_id = 555555UL; + uint64_t object_size = 666666UL; + + // ObjectRequest --> bufferlist + ObjectCacheRequest* req = new ObjectCacheReadData(type, seq, read_offset, read_len, + pool_id, snap_id, object_size, oid_name, pool_nspace); + req->encode(); + auto payload_bl = req->get_payload_bufferlist(); + + uint32_t data_len = get_data_len(payload_bl.c_str()); + ASSERT_EQ(payload_bl.length(), data_len + get_header_size()); + ASSERT_TRUE(payload_bl.c_str() != nullptr); + + // bufferlist --> ObjectCacheRequest + ObjectCacheRequest* req_decode = decode_object_cache_request(payload_bl); + + ASSERT_EQ(req_decode->get_request_type(), RBDSC_READ); + + ASSERT_EQ(req_decode->type, RBDSC_READ); + ASSERT_EQ(req_decode->seq, 123456UL); + ASSERT_EQ(((ObjectCacheReadData*)req_decode)->type, RBDSC_READ); + ASSERT_EQ(((ObjectCacheReadData*)req_decode)->seq, 123456UL); + ASSERT_EQ(((ObjectCacheReadData*)req_decode)->read_offset, 222222UL); + ASSERT_EQ(((ObjectCacheReadData*)req_decode)->read_len, 333333UL); + ASSERT_EQ(((ObjectCacheReadData*)req_decode)->pool_id, 444444UL); + ASSERT_EQ(((ObjectCacheReadData*)req_decode)->snap_id, 555555UL); + ASSERT_EQ(((ObjectCacheReadData*)req_decode)->oid, oid_name); + ASSERT_EQ(((ObjectCacheReadData*)req_decode)->pool_namespace, pool_nspace); + ASSERT_EQ(((ObjectCacheReadData*)req_decode)->object_size, 666666UL); + + delete req; + delete req_decode; +} diff --git a/src/test/immutable_object_cache/test_multi_session.cc b/src/test/immutable_object_cache/test_multi_session.cc new file mode 100644 index 000000000..a8ccbffe2 --- /dev/null +++ b/src/test/immutable_object_cache/test_multi_session.cc @@ -0,0 +1,162 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +#include +#include + +#include "gtest/gtest.h" +#include "include/Context.h" +#include "global/global_init.h" +#include "global/global_context.h" + +#include "test/immutable_object_cache/test_common.h" +#include "tools/immutable_object_cache/CacheClient.h" +#include "tools/immutable_object_cache/CacheServer.h" + +using namespace std; +using namespace ceph::immutable_obj_cache; + +class TestMultiSession : public ::testing::Test { +public: + std::string m_local_path; + CacheServer* m_cache_server; + std::thread* m_cache_server_thread; + std::vector m_cache_client_vec; + WaitEvent m_wait_event; + std::atomic m_send_request_index; + std::atomic m_recv_ack_index; + uint64_t m_session_num = 110; + + TestMultiSession() : m_local_path("/tmp/ceph_test_multisession_socket"), + m_cache_server_thread(nullptr), m_send_request_index(0), + m_recv_ack_index(0) { + m_cache_client_vec.resize(m_session_num + 1, nullptr); + } + + ~TestMultiSession() {} + + static void SetUpTestCase() {} + static void TearDownTestCase() {} + + void SetUp() override { + std::remove(m_local_path.c_str()); + m_cache_server = new CacheServer(g_ceph_context, m_local_path, + [this](CacheSession* session_id, ObjectCacheRequest* req){ + server_handle_request(session_id, req); + }); + ASSERT_TRUE(m_cache_server != nullptr); + + m_cache_server_thread = new std::thread(([this]() { + m_wait_event.signal(); + m_cache_server->run(); + })); + + // waiting for thread running. + m_wait_event.wait(); + + // waiting for io_service run. + usleep(2); + } + + void TearDown() override { + for (uint64_t i = 0; i < m_session_num; i++) { + if (m_cache_client_vec[i] != nullptr) { + m_cache_client_vec[i]->close(); + delete m_cache_client_vec[i]; + } + } + m_cache_server->stop(); + if (m_cache_server_thread->joinable()) { + m_cache_server_thread->join(); + } + delete m_cache_server; + delete m_cache_server_thread; + + std::remove(m_local_path.c_str()); + } + + CacheClient* create_session(uint64_t random_index) { + CacheClient* cache_client = new CacheClient(m_local_path, g_ceph_context); + cache_client->run(); + while (true) { + if (0 == cache_client->connect()) { + break; + } + } + m_cache_client_vec[random_index] = cache_client; + return cache_client; + } + + void server_handle_request(CacheSession* session_id, ObjectCacheRequest* req) { + + switch (req->get_request_type()) { + case RBDSC_REGISTER: { + ObjectCacheRequest* reply = new ObjectCacheRegReplyData(RBDSC_REGISTER_REPLY, + req->seq); + session_id->send(reply); + break; + } + case RBDSC_READ: { + ObjectCacheRequest* reply = new ObjectCacheReadReplyData(RBDSC_READ_REPLY, + req->seq); + session_id->send(reply); + break; + } + } + } + + void test_register_client(uint64_t random_index) { + ASSERT_TRUE(m_cache_client_vec[random_index] == nullptr); + + auto ctx = new LambdaContext([](int ret){ + ASSERT_TRUE(ret == 0); + }); + auto session = create_session(random_index); + session->register_client(ctx); + + ASSERT_TRUE(m_cache_client_vec[random_index] != nullptr); + ASSERT_TRUE(session->is_session_work()); + } + + void test_lookup_object(std::string pool_nspace, uint64_t index, + uint64_t request_num, bool is_last) { + + for (uint64_t i = 0; i < request_num; i++) { + auto ctx = make_gen_lambda_context>([this](ObjectCacheRequest* ack) { + m_recv_ack_index++; + }); + m_send_request_index++; + // here just for concurrently testing register + lookup, so fix object id. + m_cache_client_vec[index]->lookup_object(pool_nspace, 1, 2, 3, "1234", std::move(ctx)); + } + + if (is_last) { + while(m_send_request_index != m_recv_ack_index) { + usleep(1); + } + m_wait_event.signal(); + } + } +}; + +// test concurrent : multi-session + register_client + lookup_request +TEST_F(TestMultiSession, test_multi_session) { + + uint64_t test_times = 1000; + uint64_t test_session_num = 100; + + for (uint64_t i = 0; i <= test_times; i++) { + uint64_t random_index = random() % test_session_num; + if (m_cache_client_vec[random_index] == nullptr) { + test_register_client(random_index); + } else { + test_lookup_object(string("test_nspace") + std::to_string(random_index), + random_index, 4, i == test_times ? true : false); + } + } + + // make sure all ack will be received. + m_wait_event.wait(); + + ASSERT_TRUE(m_send_request_index == m_recv_ack_index); +} diff --git a/src/test/immutable_object_cache/test_object_store.cc b/src/test/immutable_object_cache/test_object_store.cc new file mode 100644 index 000000000..f4d75274e --- /dev/null +++ b/src/test/immutable_object_cache/test_object_store.cc @@ -0,0 +1,99 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include +#include +#include + + +#include "gtest/gtest.h" +#include "include/Context.h" +#include "include/rados/librados.hpp" +#include "include/rbd/librbd.hpp" +#include "librbd/ImageCtx.h" +#include "test/librados/test.h" +#include "global/global_init.h" +#include "global/global_context.h" +#include "test/librados/test_cxx.h" + +#include "tools/immutable_object_cache/ObjectCacheStore.h" + +namespace fs = std::filesystem; + +using namespace ceph::immutable_obj_cache; + +std::string test_cache_path("/tmp/test_ceph_immutable_shared_cache"); + +class TestObjectStore : public ::testing::Test { +public: + ObjectCacheStore* m_object_cache_store; + librados::Rados* m_test_rados; + CephContext* m_ceph_context; + librados::IoCtx m_local_io_ctx; + std::string m_temp_pool_name; + std::string m_temp_volume_name; + + TestObjectStore(): m_object_cache_store(nullptr), m_test_rados(nullptr), m_ceph_context(nullptr){} + + ~TestObjectStore(){} + + static void SetUpTestCase() {} + static void TearDownTestCase() {} + + void SetUp() override { + m_test_rados = new librados::Rados(); + ASSERT_EQ("", connect_cluster_pp(*m_test_rados)); + ASSERT_EQ(0, m_test_rados->conf_set("rbd_cache", "false")); + ASSERT_EQ(0, m_test_rados->conf_set("immutable_object_cache_max_size", "1024")); + ASSERT_EQ(0, m_test_rados->conf_set("immutable_object_cache_path", test_cache_path.c_str())); + + } + + void create_object_cache_store(uint64_t entry_num) { + m_temp_pool_name = get_temp_pool_name("test_pool_"); + ASSERT_EQ(0, m_test_rados->pool_create(m_temp_pool_name.c_str())); + ASSERT_EQ(0, m_test_rados->ioctx_create(m_temp_pool_name.c_str(), m_local_io_ctx)); + m_temp_volume_name = "test_volume"; + m_ceph_context = reinterpret_cast(m_test_rados->cct()); + m_object_cache_store = new ObjectCacheStore(m_ceph_context); + } + + void init_object_cache_store(std::string pool_name, std::string vol_name, + uint64_t vol_size, bool reset) { + ASSERT_EQ(0, m_object_cache_store->init(reset)); + ASSERT_EQ(0, m_object_cache_store->init_cache()); + } + + void shutdown_object_cache_store() { + ASSERT_EQ(0, m_object_cache_store->shutdown()); + } + + void lookup_object_cache_store(std::string pool_name, std::string vol_name, + std::string obj_name, int& ret) { + std::string cache_path; + ret = m_object_cache_store->lookup_object(pool_name, 1, 2, 3, + obj_name, true, cache_path); + } + + void TearDown() override { + if(m_test_rados) + delete m_test_rados; + if(m_object_cache_store) + delete m_object_cache_store; + } +}; + +TEST_F(TestObjectStore, test_1) { + create_object_cache_store(1000); + + std::string cache_path(test_cache_path); + + fs::remove_all(test_cache_path); + + init_object_cache_store(m_temp_pool_name, m_temp_volume_name, 1000, true); + + + // TODO add lookup interface testing + + shutdown_object_cache_store(); +} -- cgit v1.2.3