]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: fix parent cache races and error handling 36077/head
authorJason Dillaman <dillaman@redhat.com>
Mon, 13 Jul 2020 20:11:06 +0000 (16:11 -0400)
committerJason Dillaman <dillaman@redhat.com>
Wed, 15 Jul 2020 13:36:35 +0000 (09:36 -0400)
If the plugin fails to connect to the daemon at start-up it will
crash the process due to a resource deadlock exception being
thrown as the client is destroyed. Additionally, librbd will support
concurrent IO thread processing in the future so the client needs
to be protected by a lock.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/librbd/cache/ParentCacheObjectDispatch.cc
src/librbd/cache/ParentCacheObjectDispatch.h
src/test/librbd/CMakeLists.txt
src/test/librbd/cache/test_mock_ParentCacheObjectDispatch.cc [new file with mode: 0644]
src/test/librbd/cache/test_mock_ParentImageCache.cc [deleted file]

index 088384b1525d78eaef6c1e41de946afcd1e82b77..73d3727431010342bb572fbd49c577436df7e732 100644 (file)
@@ -26,17 +26,20 @@ namespace cache {
 
 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>
@@ -52,18 +55,10 @@ void ParentCacheObjectDispatch<I>::init(Context* on_finish) {
     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>
@@ -77,36 +72,18 @@ bool ParentCacheObjectDispatch<I>::read(
   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,
@@ -165,18 +142,29 @@ int ParentCacheObjectDispatch<I>::handle_register_client(bool reg) {
 }
 
 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(
@@ -197,21 +185,19 @@ int ParentCacheObjectDispatch<I>::create_cache_session(Context* on_finish, bool
     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;
index 42222dd9d2b865b187737efce4f819da991d6c90..2c7b52341415ad6a6897e25d73536e8b9706b150 100644 (file)
@@ -5,8 +5,9 @@
 #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 {
@@ -104,10 +105,6 @@ public:
       uint64_t journal_tid, uint64_t new_journal_tid) {
   }
 
-  bool get_state() {
-    return m_initialized;
-  }
-
   ImageCtxT* get_image_ctx() {
     return m_image_ctx;
   }
@@ -127,12 +124,13 @@ private:
          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
index 2cfd785935e02516741a4b1f8282818262242f8c..e57842ef98262a57e2cd1b94f2eef86502e89f30 100644 (file)
@@ -51,7 +51,7 @@ set(unittest_librbd_srcs
   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
diff --git a/src/test/librbd/cache/test_mock_ParentCacheObjectDispatch.cc b/src/test/librbd/cache/test_mock_ParentCacheObjectDispatch.cc
new file mode 100644 (file)
index 0000000..3b36e44
--- /dev/null
@@ -0,0 +1,341 @@
+// -*- 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
diff --git a/src/test/librbd/cache/test_mock_ParentImageCache.cc b/src/test/librbd/cache/test_mock_ParentImageCache.cc
deleted file mode 100644 (file)
index 64394ef..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-// -*- 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