template <typename I>
ParentCacheObjectDispatch<I>::ParentCacheObjectDispatch(
- I* image_ctx) : m_image_ctx(image_ctx), m_cache_client(nullptr),
- m_initialized(false), m_connecting(false) {
+ I* image_ctx)
+ : m_image_ctx(image_ctx),
+ m_lock(ceph::make_mutex(
+ "librbd::cache::ParentCacheObjectDispatch::lock", true, false)) {
ceph_assert(m_image_ctx->data_ctx.is_valid());
- std::string controller_path =
- ((CephContext*)(m_image_ctx->cct))->_conf.get_val<std::string>("immutable_object_cache_sock");
+ auto controller_path = image_ctx->cct->_conf.template get_val<std::string>(
+ "immutable_object_cache_sock");
m_cache_client = new CacheClient(controller_path.c_str(), m_image_ctx->cct);
}
template <typename I>
ParentCacheObjectDispatch<I>::~ParentCacheObjectDispatch() {
- delete m_cache_client;
+ delete m_cache_client;
+ m_cache_client = nullptr;
}
template <typename I>
return;
}
- Context* create_session_ctx = new LambdaContext([this, on_finish](int ret) {
- m_connecting.store(false);
- if (on_finish != nullptr) {
- on_finish->complete(ret);
- }
- });
-
- m_connecting.store(true);
- create_cache_session(create_session_ctx, false);
-
m_image_ctx->io_object_dispatcher->register_dispatch(this);
- m_initialized = true;
+
+ std::unique_lock locker{m_lock};
+ create_cache_session(on_finish, false);
}
template <typename I>
auto cct = m_image_ctx->cct;
ldout(cct, 20) << "object_no=" << object_no << " " << object_off << "~"
<< object_len << dendl;
- ceph_assert(m_initialized);
string oid = data_object_name(m_image_ctx, object_no);
/* if RO daemon still don't startup, or RO daemon crash,
* or session occur any error, try to re-connect daemon.*/
+ std::unique_lock locker{m_lock};
if (!m_cache_client->is_session_work()) {
- if (!m_connecting.exchange(true)) {
- /* Since we don't have a giant lock protecting the full re-connect process,
- * if thread A first passes the if (!m_cache_client->is_session_work()),
- * thread B could have also passed it and reconnected
- * before thread A resumes and executes if (!m_connecting.exchange(true)).
- * This will result in thread A re-connecting a working session.
- * So, we need to check if session is normal again. If session work,
- * we need set m_connecting to false. */
- if (!m_cache_client->is_session_work()) {
- Context* on_finish = new LambdaContext([this](int ret) {
- m_connecting.store(false);
- });
- create_cache_session(on_finish, true);
- } else {
- m_connecting.store(false);
- }
- }
+ create_cache_session(nullptr, true);
ldout(cct, 5) << "Parent cache try to re-connect to RO daemon. "
<< "dispatch current request to lower object layer" << dendl;
return false;
}
- ceph_assert(m_cache_client->is_session_work());
-
CacheGenContextURef ctx = make_gen_lambda_context<ObjectCacheRequest*,
std::function<void(ObjectCacheRequest*)>>
([this, read_data, dispatch_result, on_dispatched,
}
template <typename I>
-int ParentCacheObjectDispatch<I>::create_cache_session(Context* on_finish, bool is_reconnect) {
+void ParentCacheObjectDispatch<I>::create_cache_session(Context* on_finish,
+ bool is_reconnect) {
+ ceph_assert(ceph_mutex_is_locked_by_me(m_lock));
+ if (m_connecting) {
+ return;
+ }
+ m_connecting = true;
+
auto cct = m_image_ctx->cct;
ldout(cct, 20) << dendl;
Context* register_ctx = new LambdaContext([this, cct, on_finish](int ret) {
if (ret < 0) {
lderr(cct) << "Parent cache fail to register client." << dendl;
- } else {
- ceph_assert(m_cache_client->is_session_work());
}
handle_register_client(ret < 0 ? false : true);
- on_finish->complete(ret);
+
+ ceph_assert(m_connecting);
+ m_connecting = false;
+
+ if (on_finish != nullptr) {
+ on_finish->complete(0);
+ }
});
Context* connect_ctx = new LambdaContext(
delete m_cache_client;
// create new CacheClient to connect RO daemon.
- std::string controller_path =
- ((CephContext*)(m_image_ctx->cct))->_conf.get_val<std::string>("immutable_object_cache_sock");
+ auto controller_path = cct->_conf.template get_val<std::string>(
+ "immutable_object_cache_sock");
m_cache_client = new CacheClient(controller_path.c_str(), m_image_ctx->cct);
}
m_cache_client->run();
-
m_cache_client->connect(connect_ctx);
- return 0;
}
template <typename I>
int ParentCacheObjectDispatch<I>::read_object(
- std::string file_path, ceph::bufferlist* read_data, uint64_t offset,
- uint64_t length, Context *on_finish) {
+ std::string file_path, ceph::bufferlist* read_data, uint64_t offset,
+ uint64_t length, Context *on_finish) {
auto *cct = m_image_ctx->cct;
ldout(cct, 20) << "file path: " << file_path << dendl;
#define CEPH_LIBRBD_CACHE_PARENT_CACHER_OBJECT_DISPATCH_H
#include "librbd/io/ObjectDispatchInterface.h"
-#include "tools/immutable_object_cache/CacheClient.h"
+#include "common/ceph_mutex.h"
#include "librbd/cache/TypeTraits.h"
+#include "tools/immutable_object_cache/CacheClient.h"
#include "tools/immutable_object_cache/Types.h"
namespace librbd {
uint64_t journal_tid, uint64_t new_journal_tid) {
}
- bool get_state() {
- return m_initialized;
- }
-
ImageCtxT* get_image_ctx() {
return m_image_ctx;
}
io::DispatchResult* dispatch_result,
Context* on_dispatched);
int handle_register_client(bool reg);
- int create_cache_session(Context* on_finish, bool is_reconnect);
+ void create_cache_session(Context* on_finish, bool is_reconnect);
ImageCtxT* m_image_ctx;
- CacheClient *m_cache_client;
- bool m_initialized;
- std::atomic<bool> m_connecting;
+
+ ceph::mutex m_lock;
+ CacheClient *m_cache_client = nullptr;
+ bool m_connecting = false;
};
} // namespace cache
test_mock_TrashWatcher.cc
test_mock_Watcher.cc
cache/test_mock_WriteAroundObjectDispatch.cc
- cache/test_mock_ParentImageCache.cc
+ cache/test_mock_ParentCacheObjectDispatch.cc
deep_copy/test_mock_ImageCopyRequest.cc
deep_copy/test_mock_MetadataCopyRequest.cc
deep_copy/test_mock_ObjectCopyRequest.cc
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "test/librbd/test_mock_fixture.h"
+#include "test/librbd/test_support.h"
+#include "test/librbd/mock/MockImageCtx.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "include/Context.h"
+#include "tools/immutable_object_cache/CacheClient.h"
+#include "test/immutable_object_cache/MockCacheDaemon.h"
+#include "librbd/cache/ParentCacheObjectDispatch.h"
+#include "test/librbd/test_mock_fixture.h"
+#include "test/librbd/mock/MockImageCtx.h"
+
+using namespace ceph::immutable_obj_cache;
+
+namespace librbd {
+
+namespace {
+
+struct MockParentImageCacheImageCtx : public MockImageCtx {
+ MockParentImageCacheImageCtx(ImageCtx& image_ctx)
+ : MockImageCtx(image_ctx), shared_cache_path("/tmp/socket/path"){
+ }
+ ~MockParentImageCacheImageCtx() {}
+
+ std::string shared_cache_path;
+};
+
+}; // anonymous namespace
+
+namespace cache {
+
+template<>
+struct TypeTraits<MockParentImageCacheImageCtx> {
+ typedef ceph::immutable_obj_cache::MockCacheClient CacheClient;
+};
+
+}; // namespace cache
+
+}; // namespace librbd
+
+#include "librbd/cache/ParentCacheObjectDispatch.cc"
+template class librbd::cache::ParentCacheObjectDispatch<librbd::MockParentImageCacheImageCtx>;
+
+namespace librbd {
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Invoke;
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::WithArg;
+using ::testing::WithArgs;
+
+class TestMockParentCacheObjectDispatch : public TestMockFixture {
+public :
+ typedef cache::ParentCacheObjectDispatch<librbd::MockParentImageCacheImageCtx> MockParentImageCache;
+
+ // ====== mock cache client ====
+ void expect_cache_run(MockParentImageCache& mparent_image_cache, bool ret_val) {
+ auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), run());
+
+ expect.WillOnce((Invoke([]() {
+ })));
+ }
+
+ void expect_cache_session_state(MockParentImageCache& mparent_image_cache, bool ret_val) {
+ auto & expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), is_session_work());
+
+ expect.WillOnce((Invoke([ret_val]() {
+ return ret_val;
+ })));
+ }
+
+ void expect_cache_connect(MockParentImageCache& mparent_image_cache, int ret_val) {
+ auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), connect());
+
+ expect.WillOnce((Invoke([ret_val]() {
+ return ret_val;
+ })));
+ }
+
+ void expect_cache_async_connect(MockParentImageCache& mparent_image_cache, int ret_val,
+ Context* on_finish) {
+ auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), connect(_));
+
+ expect.WillOnce(WithArg<0>(Invoke([on_finish, ret_val](Context* ctx) {
+ ctx->complete(ret_val);
+ on_finish->complete(ret_val);
+ })));
+ }
+
+ void expect_cache_lookup_object(MockParentImageCache& mparent_image_cache,
+ Context* on_finish) {
+ auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()),
+ internal_lookup(_, _, _, _));
+
+ expect.WillOnce(WithArg<3>(Invoke([on_finish](std::string oid) {
+ on_finish->complete(0);
+ })));
+ }
+
+ void expect_cache_close(MockParentImageCache& mparent_image_cache, int ret_val) {
+ auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), close());
+
+ expect.WillOnce((Invoke([]() {
+ })));
+ }
+
+ void expect_cache_stop(MockParentImageCache& mparent_image_cache, int ret_val) {
+ auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), stop());
+
+ expect.WillOnce((Invoke([]() {
+ })));
+ }
+
+ void expect_cache_register(MockParentImageCache& mparent_image_cache, Context* mock_handle_register, int ret_val) {
+ auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), register_client(_));
+
+ expect.WillOnce(WithArg<0>(Invoke([mock_handle_register, ret_val](Context* ctx) {
+ if(ret_val == 0) {
+ mock_handle_register->complete(true);
+ } else {
+ mock_handle_register->complete(false);
+ }
+ ctx->complete(true);
+ return ret_val;
+ })));
+ }
+
+ void expect_io_object_dispatcher_register_state(MockParentImageCache& mparent_image_cache,
+ int ret_val) {
+ auto& expect = EXPECT_CALL((*(mparent_image_cache.get_image_ctx()->io_object_dispatcher)),
+ register_dispatch(_));
+
+ expect.WillOnce(WithArg<0>(Invoke([&mparent_image_cache]
+ (io::ObjectDispatchInterface* object_dispatch) {
+ ASSERT_EQ(object_dispatch, &mparent_image_cache);
+ })));
+ }
+};
+
+TEST_F(TestMockParentCacheObjectDispatch, test_initialization_success) {
+ librbd::ImageCtx* ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ MockParentImageCacheImageCtx mock_image_ctx(*ictx);
+ mock_image_ctx.child = &mock_image_ctx;
+
+ auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx);
+
+ expect_cache_run(*mock_parent_image_cache, 0);
+ C_SaferCond cond;
+ Context* handle_connect = new LambdaContext([&cond](int ret) {
+ ASSERT_EQ(ret, 0);
+ cond.complete(0);
+ });
+ expect_cache_async_connect(*mock_parent_image_cache, 0, handle_connect);
+ Context* ctx = new LambdaContext([](bool reg) {
+ ASSERT_EQ(reg, true);
+ });
+ expect_cache_register(*mock_parent_image_cache, ctx, 0);
+ expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0);
+ expect_cache_close(*mock_parent_image_cache, 0);
+ expect_cache_stop(*mock_parent_image_cache, 0);
+
+ mock_parent_image_cache->init();
+ cond.wait();
+
+ ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(),
+ io::OBJECT_DISPATCH_LAYER_PARENT_CACHE);
+ expect_cache_session_state(*mock_parent_image_cache, true);
+ ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), true);
+
+ mock_parent_image_cache->get_cache_client()->close();
+ mock_parent_image_cache->get_cache_client()->stop();
+
+ delete mock_parent_image_cache;
+}
+
+TEST_F(TestMockParentCacheObjectDispatch, test_initialization_fail_at_connect) {
+ librbd::ImageCtx* ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ MockParentImageCacheImageCtx mock_image_ctx(*ictx);
+ mock_image_ctx.child = &mock_image_ctx;
+
+ auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx);
+
+ expect_cache_run(*mock_parent_image_cache, 0);
+ C_SaferCond cond;
+ Context* handle_connect = new LambdaContext([&cond](int ret) {
+ ASSERT_EQ(ret, -1);
+ cond.complete(0);
+ });
+ expect_cache_async_connect(*mock_parent_image_cache, -1, handle_connect);
+ expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0);
+ expect_cache_session_state(*mock_parent_image_cache, false);
+ expect_cache_close(*mock_parent_image_cache, 0);
+ expect_cache_stop(*mock_parent_image_cache, 0);
+
+ mock_parent_image_cache->init();
+
+ // initialization fails.
+ ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(),
+ io::OBJECT_DISPATCH_LAYER_PARENT_CACHE);
+ ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), false);
+
+ mock_parent_image_cache->get_cache_client()->close();
+ mock_parent_image_cache->get_cache_client()->stop();
+
+ delete mock_parent_image_cache;
+
+}
+
+TEST_F(TestMockParentCacheObjectDispatch, test_initialization_fail_at_register) {
+ librbd::ImageCtx* ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ MockParentImageCacheImageCtx mock_image_ctx(*ictx);
+ mock_image_ctx.child = &mock_image_ctx;
+
+ auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx);
+
+ expect_cache_run(*mock_parent_image_cache, 0);
+ C_SaferCond cond;
+ Context* handle_connect = new LambdaContext([&cond](int ret) {
+ ASSERT_EQ(ret, 0);
+ cond.complete(0);
+ });
+ expect_cache_async_connect(*mock_parent_image_cache, 0, handle_connect);
+ Context* ctx = new LambdaContext([](bool reg) {
+ ASSERT_EQ(reg, false);
+ });
+ expect_cache_register(*mock_parent_image_cache, ctx, -1);
+ expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0);
+ expect_cache_close(*mock_parent_image_cache, 0);
+ expect_cache_stop(*mock_parent_image_cache, 0);
+
+ mock_parent_image_cache->init();
+ cond.wait();
+
+ ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(),
+ io::OBJECT_DISPATCH_LAYER_PARENT_CACHE);
+ expect_cache_session_state(*mock_parent_image_cache, true);
+ ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), true);
+
+ mock_parent_image_cache->get_cache_client()->close();
+ mock_parent_image_cache->get_cache_client()->stop();
+
+ delete mock_parent_image_cache;
+}
+
+TEST_F(TestMockParentCacheObjectDispatch, test_disble_interface) {
+ librbd::ImageCtx* ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ MockParentImageCacheImageCtx mock_image_ctx(*ictx);
+ mock_image_ctx.child = &mock_image_ctx;
+
+ auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx);
+
+ std::string temp_oid("12345");
+ ceph::bufferlist temp_bl;
+ ::SnapContext *temp_snapc = nullptr;
+ io::DispatchResult* temp_dispatch_result = nullptr;
+ io::Extents temp_buffer_extents;
+ int* temp_op_flags = nullptr;
+ uint64_t* temp_journal_tid = nullptr;
+ Context** temp_on_finish = nullptr;
+ Context* temp_on_dispatched = nullptr;
+ ZTracer::Trace* temp_trace = nullptr;
+ io::LightweightBufferExtents buffer_extents;
+
+ ASSERT_EQ(mock_parent_image_cache->discard(0, 0, 0, *temp_snapc, 0, *temp_trace, temp_op_flags,
+ temp_journal_tid, temp_dispatch_result, temp_on_finish, temp_on_dispatched), false);
+ ASSERT_EQ(mock_parent_image_cache->write(0, 0, std::move(temp_bl), *temp_snapc, 0,
+ *temp_trace, temp_op_flags, temp_journal_tid, temp_dispatch_result,
+ temp_on_finish, temp_on_dispatched), false);
+ ASSERT_EQ(mock_parent_image_cache->write_same(0, 0, 0, std::move(buffer_extents),
+ std::move(temp_bl), *temp_snapc, 0, *temp_trace, temp_op_flags,
+ temp_journal_tid, temp_dispatch_result, temp_on_finish, temp_on_dispatched), false );
+ ASSERT_EQ(mock_parent_image_cache->compare_and_write(0, 0, std::move(temp_bl), std::move(temp_bl),
+ *temp_snapc, 0, *temp_trace, temp_journal_tid, temp_op_flags, temp_journal_tid,
+ temp_dispatch_result, temp_on_finish, temp_on_dispatched), false);
+ ASSERT_EQ(mock_parent_image_cache->flush(io::FLUSH_SOURCE_USER, *temp_trace, temp_journal_tid,
+ temp_dispatch_result, temp_on_finish, temp_on_dispatched), false);
+ ASSERT_EQ(mock_parent_image_cache->invalidate_cache(nullptr), false);
+ ASSERT_EQ(mock_parent_image_cache->reset_existence_cache(nullptr), false);
+
+ delete mock_parent_image_cache;
+
+}
+
+TEST_F(TestMockParentCacheObjectDispatch, test_read) {
+ librbd::ImageCtx* ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ MockParentImageCacheImageCtx mock_image_ctx(*ictx);
+ mock_image_ctx.child = &mock_image_ctx;
+
+ auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx);
+
+ expect_cache_run(*mock_parent_image_cache, 0);
+ C_SaferCond conn_cond;
+ Context* handle_connect = new LambdaContext([&conn_cond](int ret) {
+ ASSERT_EQ(ret, 0);
+ conn_cond.complete(0);
+ });
+ expect_cache_async_connect(*mock_parent_image_cache, 0, handle_connect);
+ Context* ctx = new LambdaContext([](bool reg) {
+ ASSERT_EQ(reg, true);
+ });
+ expect_cache_register(*mock_parent_image_cache, ctx, 0);
+ expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0);
+ expect_cache_close(*mock_parent_image_cache, 0);
+ expect_cache_stop(*mock_parent_image_cache, 0);
+
+ mock_parent_image_cache->init();
+ conn_cond.wait();
+
+ ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(),
+ io::OBJECT_DISPATCH_LAYER_PARENT_CACHE);
+ expect_cache_session_state(*mock_parent_image_cache, true);
+ ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), true);
+
+ C_SaferCond cond;
+ Context* on_finish = &cond;
+
+ auto& expect = EXPECT_CALL(*(mock_parent_image_cache->get_cache_client()), is_session_work());
+ expect.WillOnce(Return(true));
+
+ expect_cache_lookup_object(*mock_parent_image_cache, on_finish);
+
+ mock_parent_image_cache->read(0, 0, 4096, CEPH_NOSNAP, 0, {},
+ nullptr, nullptr, nullptr, nullptr, &on_finish, nullptr);
+ ASSERT_EQ(0, cond.wait());
+
+ mock_parent_image_cache->get_cache_client()->close();
+ mock_parent_image_cache->get_cache_client()->stop();
+ delete mock_parent_image_cache;
+}
+
+} // namespace librbd
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "test/librbd/test_mock_fixture.h"
-#include "test/librbd/test_support.h"
-#include "test/librbd/mock/MockImageCtx.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include "include/Context.h"
-#include "tools/immutable_object_cache/CacheClient.h"
-#include "test/immutable_object_cache/MockCacheDaemon.h"
-#include "librbd/cache/ParentCacheObjectDispatch.h"
-#include "test/librbd/test_mock_fixture.h"
-#include "test/librbd/mock/MockImageCtx.h"
-
-using namespace ceph::immutable_obj_cache;
-
-namespace librbd {
-
-namespace {
-
-struct MockParentImageCacheImageCtx : public MockImageCtx {
- MockParentImageCacheImageCtx(ImageCtx& image_ctx)
- : MockImageCtx(image_ctx), shared_cache_path("/tmp/socket/path"){
- }
- ~MockParentImageCacheImageCtx() {}
-
- std::string shared_cache_path;
-};
-
-}; // anonymous namespace
-
-namespace cache {
-
-template<>
-struct TypeTraits<MockParentImageCacheImageCtx> {
- typedef ceph::immutable_obj_cache::MockCacheClient CacheClient;
-};
-
-}; // namespace cache
-
-}; // namespace librbd
-
-#include "librbd/cache/ParentCacheObjectDispatch.cc"
-template class librbd::cache::ParentCacheObjectDispatch<librbd::MockParentImageCacheImageCtx>;
-
-namespace librbd {
-
-using ::testing::_;
-using ::testing::DoAll;
-using ::testing::Invoke;
-using ::testing::InSequence;
-using ::testing::Return;
-using ::testing::WithArg;
-using ::testing::WithArgs;
-
-class TestMockParentImageCache : public TestMockFixture {
-public :
- typedef cache::ParentCacheObjectDispatch<librbd::MockParentImageCacheImageCtx> MockParentImageCache;
-
- // ====== mock cache client ====
- void expect_cache_run(MockParentImageCache& mparent_image_cache, bool ret_val) {
- auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), run());
-
- expect.WillOnce((Invoke([]() {
- })));
- }
-
- void expect_cache_session_state(MockParentImageCache& mparent_image_cache, bool ret_val) {
- auto & expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), is_session_work());
-
- expect.WillOnce((Invoke([ret_val]() {
- return ret_val;
- })));
- }
-
- void expect_cache_connect(MockParentImageCache& mparent_image_cache, int ret_val) {
- auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), connect());
-
- expect.WillOnce((Invoke([ret_val]() {
- return ret_val;
- })));
- }
-
- void expect_cache_async_connect(MockParentImageCache& mparent_image_cache, int ret_val,
- Context* on_finish) {
- auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), connect(_));
-
- expect.WillOnce(WithArg<0>(Invoke([on_finish, ret_val](Context* ctx) {
- ctx->complete(ret_val);
- on_finish->complete(ret_val);
- })));
- }
-
- void expect_cache_lookup_object(MockParentImageCache& mparent_image_cache,
- Context* on_finish) {
- auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()),
- internal_lookup(_, _, _, _));
-
- expect.WillOnce(WithArg<3>(Invoke([on_finish](std::string oid) {
- on_finish->complete(0);
- })));
- }
-
- void expect_cache_close(MockParentImageCache& mparent_image_cache, int ret_val) {
- auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), close());
-
- expect.WillOnce((Invoke([]() {
- })));
- }
-
- void expect_cache_stop(MockParentImageCache& mparent_image_cache, int ret_val) {
- auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), stop());
-
- expect.WillOnce((Invoke([]() {
- })));
- }
-
- void expect_cache_register(MockParentImageCache& mparent_image_cache, Context* mock_handle_register, int ret_val) {
- auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), register_client(_));
-
- expect.WillOnce(WithArg<0>(Invoke([mock_handle_register, ret_val](Context* ctx) {
- if(ret_val == 0) {
- mock_handle_register->complete(true);
- } else {
- mock_handle_register->complete(false);
- }
- ctx->complete(true);
- return ret_val;
- })));
- }
-
- void expect_io_object_dispatcher_register_state(MockParentImageCache& mparent_image_cache,
- int ret_val) {
- auto& expect = EXPECT_CALL((*(mparent_image_cache.get_image_ctx()->io_object_dispatcher)),
- register_dispatch(_));
-
- expect.WillOnce(WithArg<0>(Invoke([&mparent_image_cache]
- (io::ObjectDispatchInterface* object_dispatch) {
- ASSERT_EQ(object_dispatch, &mparent_image_cache);
- })));
- }
-};
-
-TEST_F(TestMockParentImageCache, test_initialization_success) {
- librbd::ImageCtx* ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
- MockParentImageCacheImageCtx mock_image_ctx(*ictx);
- mock_image_ctx.child = &mock_image_ctx;
-
- auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx);
-
- expect_cache_run(*mock_parent_image_cache, 0);
- C_SaferCond cond;
- Context* handle_connect = new LambdaContext([&cond](int ret) {
- ASSERT_EQ(ret, 0);
- cond.complete(0);
- });
- expect_cache_async_connect(*mock_parent_image_cache, 0, handle_connect);
- Context* ctx = new LambdaContext([](bool reg) {
- ASSERT_EQ(reg, true);
- });
- expect_cache_register(*mock_parent_image_cache, ctx, 0);
- expect_cache_session_state(*mock_parent_image_cache, true);
- expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0);
- expect_cache_close(*mock_parent_image_cache, 0);
- expect_cache_stop(*mock_parent_image_cache, 0);
-
- mock_parent_image_cache->init();
- cond.wait();
-
- ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(),
- io::OBJECT_DISPATCH_LAYER_PARENT_CACHE);
- ASSERT_EQ(mock_parent_image_cache->get_state(), true);
- expect_cache_session_state(*mock_parent_image_cache, true);
- ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), true);
-
- mock_parent_image_cache->get_cache_client()->close();
- mock_parent_image_cache->get_cache_client()->stop();
-
- delete mock_parent_image_cache;
-}
-
-TEST_F(TestMockParentImageCache, test_initialization_fail_at_connect) {
- librbd::ImageCtx* ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
- MockParentImageCacheImageCtx mock_image_ctx(*ictx);
- mock_image_ctx.child = &mock_image_ctx;
-
- auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx);
-
- expect_cache_run(*mock_parent_image_cache, 0);
- C_SaferCond cond;
- Context* handle_connect = new LambdaContext([&cond](int ret) {
- ASSERT_EQ(ret, -1);
- cond.complete(0);
- });
- expect_cache_async_connect(*mock_parent_image_cache, -1, handle_connect);
- expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0);
- expect_cache_session_state(*mock_parent_image_cache, false);
- expect_cache_close(*mock_parent_image_cache, 0);
- expect_cache_stop(*mock_parent_image_cache, 0);
-
- mock_parent_image_cache->init();
-
- // initialization fails.
- ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(),
- io::OBJECT_DISPATCH_LAYER_PARENT_CACHE);
- ASSERT_EQ(mock_parent_image_cache->get_state(), true);
- ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), false);
-
- mock_parent_image_cache->get_cache_client()->close();
- mock_parent_image_cache->get_cache_client()->stop();
-
- delete mock_parent_image_cache;
-
-}
-
-TEST_F(TestMockParentImageCache, test_initialization_fail_at_register) {
- librbd::ImageCtx* ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
- MockParentImageCacheImageCtx mock_image_ctx(*ictx);
- mock_image_ctx.child = &mock_image_ctx;
-
- auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx);
-
- expect_cache_run(*mock_parent_image_cache, 0);
- C_SaferCond cond;
- Context* handle_connect = new LambdaContext([&cond](int ret) {
- ASSERT_EQ(ret, 0);
- cond.complete(0);
- });
- expect_cache_async_connect(*mock_parent_image_cache, 0, handle_connect);
- Context* ctx = new LambdaContext([](bool reg) {
- ASSERT_EQ(reg, false);
- });
- expect_cache_register(*mock_parent_image_cache, ctx, -1);
- expect_cache_session_state(*mock_parent_image_cache, true);
- expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0);
- expect_cache_close(*mock_parent_image_cache, 0);
- expect_cache_stop(*mock_parent_image_cache, 0);
-
- mock_parent_image_cache->init();
- cond.wait();
-
- ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(),
- io::OBJECT_DISPATCH_LAYER_PARENT_CACHE);
- ASSERT_EQ(mock_parent_image_cache->get_state(), true);
- expect_cache_session_state(*mock_parent_image_cache, true);
- ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), true);
-
- mock_parent_image_cache->get_cache_client()->close();
- mock_parent_image_cache->get_cache_client()->stop();
-
- delete mock_parent_image_cache;
-}
-
-TEST_F(TestMockParentImageCache, test_disble_interface) {
- librbd::ImageCtx* ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
- MockParentImageCacheImageCtx mock_image_ctx(*ictx);
- mock_image_ctx.child = &mock_image_ctx;
-
- auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx);
-
- std::string temp_oid("12345");
- ceph::bufferlist temp_bl;
- ::SnapContext *temp_snapc = nullptr;
- io::DispatchResult* temp_dispatch_result = nullptr;
- io::Extents temp_buffer_extents;
- int* temp_op_flags = nullptr;
- uint64_t* temp_journal_tid = nullptr;
- Context** temp_on_finish = nullptr;
- Context* temp_on_dispatched = nullptr;
- ZTracer::Trace* temp_trace = nullptr;
- io::LightweightBufferExtents buffer_extents;
-
- ASSERT_EQ(mock_parent_image_cache->discard(0, 0, 0, *temp_snapc, 0, *temp_trace, temp_op_flags,
- temp_journal_tid, temp_dispatch_result, temp_on_finish, temp_on_dispatched), false);
- ASSERT_EQ(mock_parent_image_cache->write(0, 0, std::move(temp_bl), *temp_snapc, 0,
- *temp_trace, temp_op_flags, temp_journal_tid, temp_dispatch_result,
- temp_on_finish, temp_on_dispatched), false);
- ASSERT_EQ(mock_parent_image_cache->write_same(0, 0, 0, std::move(buffer_extents),
- std::move(temp_bl), *temp_snapc, 0, *temp_trace, temp_op_flags,
- temp_journal_tid, temp_dispatch_result, temp_on_finish, temp_on_dispatched), false );
- ASSERT_EQ(mock_parent_image_cache->compare_and_write(0, 0, std::move(temp_bl), std::move(temp_bl),
- *temp_snapc, 0, *temp_trace, temp_journal_tid, temp_op_flags, temp_journal_tid,
- temp_dispatch_result, temp_on_finish, temp_on_dispatched), false);
- ASSERT_EQ(mock_parent_image_cache->flush(io::FLUSH_SOURCE_USER, *temp_trace, temp_journal_tid,
- temp_dispatch_result, temp_on_finish, temp_on_dispatched), false);
- ASSERT_EQ(mock_parent_image_cache->invalidate_cache(nullptr), false);
- ASSERT_EQ(mock_parent_image_cache->reset_existence_cache(nullptr), false);
-
- delete mock_parent_image_cache;
-
-}
-
-TEST_F(TestMockParentImageCache, test_read) {
- librbd::ImageCtx* ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
- MockParentImageCacheImageCtx mock_image_ctx(*ictx);
- mock_image_ctx.child = &mock_image_ctx;
-
- auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx);
-
- expect_cache_run(*mock_parent_image_cache, 0);
- C_SaferCond conn_cond;
- Context* handle_connect = new LambdaContext([&conn_cond](int ret) {
- ASSERT_EQ(ret, 0);
- conn_cond.complete(0);
- });
- expect_cache_async_connect(*mock_parent_image_cache, 0, handle_connect);
- Context* ctx = new LambdaContext([](bool reg) {
- ASSERT_EQ(reg, true);
- });
- expect_cache_register(*mock_parent_image_cache, ctx, 0);
- expect_cache_session_state(*mock_parent_image_cache, true);
- expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0);
- expect_cache_close(*mock_parent_image_cache, 0);
- expect_cache_stop(*mock_parent_image_cache, 0);
-
- mock_parent_image_cache->init();
- conn_cond.wait();
-
- ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(),
- io::OBJECT_DISPATCH_LAYER_PARENT_CACHE);
- ASSERT_EQ(mock_parent_image_cache->get_state(), true);
- expect_cache_session_state(*mock_parent_image_cache, true);
- ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), true);
-
- C_SaferCond cond;
- Context* on_finish = &cond;
-
- auto& expect = EXPECT_CALL(*(mock_parent_image_cache->get_cache_client()), is_session_work());
- expect.WillOnce(Return(true)).WillOnce(Return(true));
-
- expect_cache_lookup_object(*mock_parent_image_cache, on_finish);
-
- mock_parent_image_cache->read(0, 0, 4096, CEPH_NOSNAP, 0, {},
- nullptr, nullptr, nullptr, nullptr, &on_finish, nullptr);
- ASSERT_EQ(0, cond.wait());
-
- mock_parent_image_cache->get_cache_client()->close();
- mock_parent_image_cache->get_cache_client()->stop();
- delete mock_parent_image_cache;
-}
-
-} // namespace librbd