summaryrefslogtreecommitdiffstats
path: root/src/test/immutable_object_cache
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/test/immutable_object_cache
parentInitial commit. (diff)
downloadceph-upstream/18.2.2.tar.xz
ceph-upstream/18.2.2.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/immutable_object_cache')
-rw-r--r--src/test/immutable_object_cache/CMakeLists.txt37
-rw-r--r--src/test/immutable_object_cache/MockCacheDaemon.h45
-rw-r--r--src/test/immutable_object_cache/test_DomainSocket.cc177
-rw-r--r--src/test/immutable_object_cache/test_SimplePolicy.cc235
-rw-r--r--src/test/immutable_object_cache/test_common.h41
-rw-r--r--src/test/immutable_object_cache/test_main.cc29
-rw-r--r--src/test/immutable_object_cache/test_message.cc50
-rw-r--r--src/test/immutable_object_cache/test_multi_session.cc162
-rw-r--r--src/test/immutable_object_cache/test_object_store.cc99
9 files changed, 875 insertions, 0 deletions
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 <iostream>
+#include <unistd.h>
+
+#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 <iostream>
+#include <unistd.h>
+
+#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<uint64_t> m_send_request_index;
+ std::atomic<uint64_t> m_recv_ack_index;
+ WaitEvent m_wait_event;
+ unordered_set<std::string> 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<ObjectCacheRequest*, std::function<void(ObjectCacheRequest*)>>
+ ([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<ObjectCacheRequest*, std::function<void(ObjectCacheRequest*)>>
+ ([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 <sstream>
+#include <list>
+#include <gtest/gtest.h>
+
+#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<std::string> m_promoted_lru;
+ std::vector<std::string> 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<std::string> 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<std::string> 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 <pthread.h>
+
+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 <iostream>
+#include <string>
+
+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<CephContext*>(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 <iostream>
+#include <unistd.h>
+
+#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<CacheClient*> m_cache_client_vec;
+ WaitEvent m_wait_event;
+ std::atomic<uint64_t> m_send_request_index;
+ std::atomic<uint64_t> 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<ObjectCacheRequest*,
+ std::function<void(ObjectCacheRequest*)>>([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 <filesystem>
+#include <iostream>
+#include <unistd.h>
+
+
+#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<CephContext*>(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();
+}