]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd-mirror: bootstrap and related state machines now uses StateBuilder
authorJason Dillaman <dillaman@redhat.com>
Wed, 8 Jan 2020 14:21:30 +0000 (09:21 -0500)
committerJason Dillaman <dillaman@redhat.com>
Fri, 10 Jan 2020 00:23:10 +0000 (19:23 -0500)
This removes all the journal-specific variables from the image replayer
and bootstrap state machines. Instead, these details are hidden behind
the abstract StateBuilder class and its derived journal class.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
25 files changed:
src/test/rbd_mirror/image_replayer/journal/test_mock_CreateLocalImageRequest.cc
src/test/rbd_mirror/image_replayer/journal/test_mock_PrepareReplayRequest.cc
src/test/rbd_mirror/image_replayer/journal/test_mock_Replayer.cc
src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc
src/test/rbd_mirror/image_replayer/test_mock_PrepareLocalImageRequest.cc
src/test/rbd_mirror/image_replayer/test_mock_PrepareRemoteImageRequest.cc
src/test/rbd_mirror/mock/MockBaseRequest.h [new file with mode: 0644]
src/test/rbd_mirror/test_mock_ImageReplayer.cc
src/tools/rbd_mirror/ImageReplayer.cc
src/tools/rbd_mirror/ImageReplayer.h
src/tools/rbd_mirror/InstanceReplayer.cc
src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc
src/tools/rbd_mirror/image_replayer/BootstrapRequest.h
src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.cc
src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.h
src/tools/rbd_mirror/image_replayer/PrepareRemoteImageRequest.cc
src/tools/rbd_mirror/image_replayer/PrepareRemoteImageRequest.h
src/tools/rbd_mirror/image_replayer/journal/CreateLocalImageRequest.cc
src/tools/rbd_mirror/image_replayer/journal/CreateLocalImageRequest.h
src/tools/rbd_mirror/image_replayer/journal/PrepareReplayRequest.cc
src/tools/rbd_mirror/image_replayer/journal/PrepareReplayRequest.h
src/tools/rbd_mirror/image_replayer/journal/Replayer.cc
src/tools/rbd_mirror/image_replayer/journal/Replayer.h
src/tools/rbd_mirror/image_replayer/journal/StateBuilder.cc
src/tools/rbd_mirror/image_replayer/journal/StateBuilder.h

index 5c310cd5c01febe8a7968934fef2ca7b61e914c3..6fc7580165ec00151975b5f6aa2836a423bd1099 100644 (file)
@@ -7,6 +7,7 @@
 #include "tools/rbd_mirror/Threads.h"
 #include "tools/rbd_mirror/image_replayer/CreateImageRequest.h"
 #include "tools/rbd_mirror/image_replayer/journal/CreateLocalImageRequest.h"
+#include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
 #include "test/journal/mock/MockJournaler.h"
 #include "test/librbd/mock/MockImageCtx.h"
 #include "test/rbd_mirror/mock/MockContextWQ.h"
@@ -90,6 +91,19 @@ struct CreateImageRequest<librbd::MockTestImageCtx> {
 CreateImageRequest<librbd::MockTestImageCtx>*
   CreateImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
 
+namespace journal {
+
+template<>
+struct StateBuilder<librbd::MockTestImageCtx> {
+  std::string local_image_id;
+
+  std::string remote_mirror_uuid;
+  ::journal::MockJournalerProxy* remote_journaler = nullptr;
+  cls::journal::ClientState remote_client_state;
+  librbd::journal::MirrorPeerClientMeta remote_client_meta;
+};
+
+} // namespace journal
 } // namespace image_replayer
 } // namespace mirror
 } // namespace rbd
@@ -111,6 +125,7 @@ public:
   typedef CreateLocalImageRequest<librbd::MockTestImageCtx> MockCreateLocalImageRequest;
   typedef Threads<librbd::MockTestImageCtx> MockThreads;
   typedef CreateImageRequest<librbd::MockTestImageCtx> MockCreateImageRequest;
+  typedef StateBuilder<librbd::MockTestImageCtx> MockStateBuilder;
 
   void SetUp() override {
     TestMockFixture::SetUp();
@@ -168,15 +183,12 @@ public:
 
   MockCreateLocalImageRequest* create_request(
       MockThreads& mock_threads,
-      ::journal::MockJournaler& mock_journaler,
+      MockStateBuilder& mock_state_builder,
       const std::string& global_image_id,
-      const std::string& remote_mirror_uuid,
-      librbd::journal::MirrorPeerClientMeta* mirror_peer_client_meta,
-      std::string* local_image_id, Context* on_finish) {
+      Context* on_finish) {
     return new MockCreateLocalImageRequest(
       &mock_threads, m_local_io_ctx, m_mock_remote_image_ctx,
-      &mock_journaler, global_image_id, remote_mirror_uuid,
-      mirror_peer_client_meta, nullptr, local_image_id, on_finish);
+      global_image_id, nullptr, &mock_state_builder, on_finish);
   }
 
   librbd::ImageCtx *m_remote_image_ctx;
@@ -204,17 +216,16 @@ TEST_F(TestMockImageReplayerJournalCreateLocalImageRequest, Success) {
 
   C_SaferCond ctx;
   MockThreads mock_threads;
-  std::string local_image_id;
+  MockStateBuilder mock_state_builder;
   auto request = create_request(
-    mock_threads, mock_journaler, "global image id", "remote mirror uuid",
-    &mirror_peer_client_meta, &local_image_id, &ctx);
+    mock_threads, mock_state_builder, "global image id", &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
 
-  ASSERT_EQ("local image id", local_image_id);
-  ASSERT_EQ("local image id", mirror_peer_client_meta.image_id);
+  ASSERT_EQ("local image id", mock_state_builder.local_image_id);
+  ASSERT_EQ("local image id", mock_state_builder.remote_client_meta.image_id);
   ASSERT_EQ(librbd::journal::MIRROR_PEER_STATE_SYNCING,
-            mirror_peer_client_meta.state);
+            mock_state_builder.remote_client_meta.state);
 }
 
 TEST_F(TestMockImageReplayerJournalCreateLocalImageRequest, UnregisterError) {
@@ -226,11 +237,9 @@ TEST_F(TestMockImageReplayerJournalCreateLocalImageRequest, UnregisterError) {
 
   C_SaferCond ctx;
   MockThreads mock_threads;
-  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
-  std::string local_image_id;
+  MockStateBuilder mock_state_builder;
   auto request = create_request(
-    mock_threads, mock_journaler, "global image id", "remote mirror uuid",
-    &mirror_peer_client_meta, &local_image_id, &ctx);
+    mock_threads, mock_state_builder, "global image id", &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
@@ -252,10 +261,9 @@ TEST_F(TestMockImageReplayerJournalCreateLocalImageRequest, RegisterError) {
 
   C_SaferCond ctx;
   MockThreads mock_threads;
-  std::string local_image_id;
+  MockStateBuilder mock_state_builder;
   auto request = create_request(
-    mock_threads, mock_journaler, "global image id", "remote mirror uuid",
-    &mirror_peer_client_meta, &local_image_id, &ctx);
+    mock_threads, mock_state_builder, "global image id", &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
@@ -281,10 +289,9 @@ TEST_F(TestMockImageReplayerJournalCreateLocalImageRequest, CreateImageError) {
 
   C_SaferCond ctx;
   MockThreads mock_threads;
-  std::string local_image_id;
+  MockStateBuilder mock_state_builder;
   auto request = create_request(
-    mock_threads, mock_journaler, "global image id", "remote mirror uuid",
-    &mirror_peer_client_meta, &local_image_id, &ctx);
+    mock_threads, mock_state_builder, "global image id", &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
@@ -316,10 +323,9 @@ TEST_F(TestMockImageReplayerJournalCreateLocalImageRequest, CreateImageDuplicate
 
   C_SaferCond ctx;
   MockThreads mock_threads;
-  std::string local_image_id;
+  MockStateBuilder mock_state_builder;
   auto request = create_request(
-    mock_threads, mock_journaler, "global image id", "remote mirror uuid",
-    &mirror_peer_client_meta, &local_image_id, &ctx);
+    mock_threads, mock_state_builder, "global image id", &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
 }
@@ -348,10 +354,9 @@ TEST_F(TestMockImageReplayerJournalCreateLocalImageRequest, UpdateClientImageErr
 
   C_SaferCond ctx;
   MockThreads mock_threads;
-  std::string local_image_id;
+  MockStateBuilder mock_state_builder;
   auto request = create_request(
-    mock_threads, mock_journaler, "global image id", "remote mirror uuid",
-    &mirror_peer_client_meta, &local_image_id, &ctx);
+    mock_threads, mock_state_builder, "global image id", &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
index a2dbc5a69d27fbe3dc08aac4ced97a0a6f3f2dab..9f75e69e609a60f193251905947f0747adcb15f5 100644 (file)
@@ -6,6 +6,7 @@
 #include "librbd/journal/TypeTraits.h"
 #include "tools/rbd_mirror/Threads.h"
 #include "tools/rbd_mirror/image_replayer/journal/PrepareReplayRequest.h"
+#include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
 #include "test/journal/mock/MockJournaler.h"
 #include "test/librbd/mock/MockImageCtx.h"
 #include "test/librbd/mock/MockJournal.h"
@@ -32,6 +33,35 @@ struct TypeTraits<librbd::MockTestImageCtx> {
 } // namespace journal
 } // namespace rbd
 
+namespace rbd {
+namespace mirror {
+namespace image_replayer {
+namespace journal {
+
+template<>
+struct StateBuilder<librbd::MockTestImageCtx> {
+  StateBuilder(librbd::MockTestImageCtx& local_image_ctx,
+               ::journal::MockJournaler& remote_journaler,
+               const librbd::journal::MirrorPeerClientMeta& remote_client_meta)
+    : local_image_ctx(&local_image_ctx),
+      local_image_id(local_image_ctx.id),
+      remote_journaler(&remote_journaler),
+      remote_client_meta(remote_client_meta) {
+  }
+
+  librbd::MockTestImageCtx* local_image_ctx;
+  std::string local_image_id;
+
+  std::string remote_mirror_uuid = "remote mirror uuid";
+  ::journal::MockJournaler* remote_journaler = nullptr;
+  librbd::journal::MirrorPeerClientMeta remote_client_meta;
+};
+
+} // namespace journal
+} // namespace image_replayer
+} // namespace mirror
+} // namespace rbd
+
 // template definitions
 #include "tools/rbd_mirror/image_replayer/journal/PrepareReplayRequest.cc"
 
@@ -52,6 +82,7 @@ using ::testing::WithArg;
 class TestMockImageReplayerJournalPrepareReplayRequest : public TestMockFixture {
 public:
   typedef PrepareReplayRequest<librbd::MockTestImageCtx> MockPrepareReplayRequest;
+  typedef StateBuilder<librbd::MockTestImageCtx> MockStateBuilder;
   typedef std::list<cls::journal::Tag> Tags;
 
   void SetUp() override {
@@ -122,16 +153,12 @@ public:
   }
 
   MockPrepareReplayRequest* create_request(
-      librbd::MockTestImageCtx& mock_local_image_ctx,
-      ::journal::MockJournaler& mock_remote_journaler,
+      MockStateBuilder& mock_state_builder,
       librbd::mirror::PromotionState remote_promotion_state,
       const std::string& local_mirror_uuid,
-      const std::string& remote_mirror_uuid,
-      librbd::journal::MirrorPeerClientMeta* client_meta,
       bool* resync_requested, bool* syncing, Context* on_finish) {
     return new MockPrepareReplayRequest(
-      &mock_local_image_ctx, &mock_remote_journaler, remote_promotion_state,
-      local_mirror_uuid, remote_mirror_uuid, client_meta, nullptr,
+      local_mirror_uuid, remote_promotion_state, nullptr, &mock_state_builder,
       resync_requested, syncing, on_finish);
   }
 
@@ -171,13 +198,15 @@ TEST_F(TestMockImageReplayerJournalPrepareReplayRequest, Success) {
   C_SaferCond ctx;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      mirror_peer_client_meta);
   bool resync_requested;
   bool syncing;
   auto request = create_request(
-    mock_local_image_ctx, mock_remote_journaler,
-    librbd::mirror::PROMOTION_STATE_PRIMARY, "local mirror uuid",
-    "remote mirror uuid", &mirror_peer_client_meta, &resync_requested,
-    &syncing, &ctx);
+    mock_state_builder, librbd::mirror::PROMOTION_STATE_PRIMARY,
+    "local mirror uuid", &resync_requested, &syncing, &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
   ASSERT_FALSE(resync_requested);
@@ -193,13 +222,15 @@ TEST_F(TestMockImageReplayerJournalPrepareReplayRequest, NoLocalJournal) {
   ::journal::MockJournaler mock_remote_journaler;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      mirror_peer_client_meta);
   bool resync_requested;
   bool syncing;
   auto request = create_request(
-    mock_local_image_ctx, mock_remote_journaler,
-    librbd::mirror::PROMOTION_STATE_PRIMARY, "local mirror uuid",
-    "remote mirror uuid", &mirror_peer_client_meta, &resync_requested,
-    &syncing, &ctx);
+    mock_state_builder, librbd::mirror::PROMOTION_STATE_PRIMARY,
+    "local mirror uuid", &resync_requested, &syncing, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
@@ -220,13 +251,15 @@ TEST_F(TestMockImageReplayerJournalPrepareReplayRequest, ResyncRequested) {
   ::journal::MockJournaler mock_remote_journaler;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      mirror_peer_client_meta);
   bool resync_requested;
   bool syncing;
   auto request = create_request(
-    mock_local_image_ctx, mock_remote_journaler,
-    librbd::mirror::PROMOTION_STATE_PRIMARY, "local mirror uuid",
-    "remote mirror uuid", &mirror_peer_client_meta, &resync_requested,
-    &syncing, &ctx);
+    mock_state_builder, librbd::mirror::PROMOTION_STATE_PRIMARY,
+    "local mirror uuid", &resync_requested, &syncing, &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
   ASSERT_TRUE(resync_requested);
@@ -247,13 +280,15 @@ TEST_F(TestMockImageReplayerJournalPrepareReplayRequest, ResyncRequestedError) {
   ::journal::MockJournaler mock_remote_journaler;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      mirror_peer_client_meta);
   bool resync_requested;
   bool syncing;
   auto request = create_request(
-    mock_local_image_ctx, mock_remote_journaler,
-    librbd::mirror::PROMOTION_STATE_PRIMARY, "local mirror uuid",
-    "remote mirror uuid", &mirror_peer_client_meta, &resync_requested,
-    &syncing, &ctx);
+    mock_state_builder, librbd::mirror::PROMOTION_STATE_PRIMARY,
+    "local mirror uuid", &resync_requested, &syncing, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
@@ -274,13 +309,15 @@ TEST_F(TestMockImageReplayerJournalPrepareReplayRequest, UnlinkedRemoteNonPrimar
   ::journal::MockJournaler mock_remote_journaler;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      mirror_peer_client_meta);
   bool resync_requested;
   bool syncing;
   auto request = create_request(
-    mock_local_image_ctx, mock_remote_journaler,
-    librbd::mirror::PROMOTION_STATE_NON_PRIMARY, "local mirror uuid",
-    "remote mirror uuid", &mirror_peer_client_meta, &resync_requested,
-    &syncing, &ctx);
+    mock_state_builder, librbd::mirror::PROMOTION_STATE_NON_PRIMARY,
+    "local mirror uuid", &resync_requested, &syncing, &ctx);
   request->send();
   ASSERT_EQ(-EREMOTEIO, ctx.wait());
 }
@@ -301,13 +338,15 @@ TEST_F(TestMockImageReplayerJournalPrepareReplayRequest, Syncing) {
   ::journal::MockJournaler mock_remote_journaler;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      mirror_peer_client_meta);
   bool resync_requested;
   bool syncing;
   auto request = create_request(
-    mock_local_image_ctx, mock_remote_journaler,
-    librbd::mirror::PROMOTION_STATE_PRIMARY, "local mirror uuid",
-    "remote mirror uuid", &mirror_peer_client_meta, &resync_requested,
-    &syncing, &ctx);
+    mock_state_builder, librbd::mirror::PROMOTION_STATE_PRIMARY,
+    "local mirror uuid", &resync_requested, &syncing, &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
   ASSERT_FALSE(resync_requested);
@@ -339,13 +378,15 @@ TEST_F(TestMockImageReplayerJournalPrepareReplayRequest, GetRemoteTagClassError)
   C_SaferCond ctx;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      mirror_peer_client_meta);
   bool resync_requested;
   bool syncing;
   auto request = create_request(
-    mock_local_image_ctx, mock_remote_journaler,
-    librbd::mirror::PROMOTION_STATE_PRIMARY, "local mirror uuid",
-    "remote mirror uuid", &mirror_peer_client_meta, &resync_requested,
-    &syncing, &ctx);
+    mock_state_builder, librbd::mirror::PROMOTION_STATE_PRIMARY,
+    "local mirror uuid", &resync_requested, &syncing, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
@@ -383,13 +424,15 @@ TEST_F(TestMockImageReplayerJournalPrepareReplayRequest, GetRemoteTagsError) {
   C_SaferCond ctx;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      mirror_peer_client_meta);
   bool resync_requested;
   bool syncing;
   auto request = create_request(
-    mock_local_image_ctx, mock_remote_journaler,
-    librbd::mirror::PROMOTION_STATE_PRIMARY, "local mirror uuid",
-    "remote mirror uuid", &mirror_peer_client_meta, &resync_requested,
-    &syncing, &ctx);
+    mock_state_builder, librbd::mirror::PROMOTION_STATE_PRIMARY,
+    "local mirror uuid", &resync_requested, &syncing, &ctx);
   request->send();
   ASSERT_EQ(-EINVAL, ctx.wait());
 }
@@ -452,13 +495,15 @@ TEST_F(TestMockImageReplayerJournalPrepareReplayRequest, LocalDemotedRemoteSynci
 
   C_SaferCond ctx;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      mirror_peer_client_meta);
   bool resync_requested;
   bool syncing;
   auto request = create_request(
-    mock_local_image_ctx, mock_remote_journaler,
-    librbd::mirror::PROMOTION_STATE_PRIMARY, "local mirror uuid",
-    "remote mirror uuid", &mirror_peer_client_meta, &resync_requested,
-    &syncing, &ctx);
+    mock_state_builder, librbd::mirror::PROMOTION_STATE_PRIMARY,
+    "local mirror uuid", &resync_requested, &syncing, &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
   ASSERT_FALSE(resync_requested);
@@ -498,13 +543,15 @@ TEST_F(TestMockImageReplayerJournalPrepareReplayRequest, UpdateClientError) {
   C_SaferCond ctx;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      mirror_peer_client_meta);
   bool resync_requested;
   bool syncing;
   auto request = create_request(
-    mock_local_image_ctx, mock_remote_journaler,
-    librbd::mirror::PROMOTION_STATE_PRIMARY, "local mirror uuid",
-    "remote mirror uuid", &mirror_peer_client_meta, &resync_requested,
-    &syncing, &ctx);
+    mock_state_builder, librbd::mirror::PROMOTION_STATE_PRIMARY,
+    "local mirror uuid", &resync_requested, &syncing, &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
   ASSERT_FALSE(resync_requested);
@@ -529,13 +576,15 @@ TEST_F(TestMockImageReplayerJournalPrepareReplayRequest, NonPrimaryRemoteNotTagO
   ::journal::MockJournaler mock_remote_journaler;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      mirror_peer_client_meta);
   bool resync_requested;
   bool syncing;
   auto request = create_request(
-    mock_local_image_ctx, mock_remote_journaler,
-    librbd::mirror::PROMOTION_STATE_NON_PRIMARY, "local mirror uuid",
-    "remote mirror uuid", &mirror_peer_client_meta, &resync_requested,
-    &syncing, &ctx);
+    mock_state_builder, librbd::mirror::PROMOTION_STATE_NON_PRIMARY,
+    "local mirror uuid", &resync_requested, &syncing, &ctx);
   request->send();
   ASSERT_EQ(-EREMOTEIO, ctx.wait());
 }
@@ -582,13 +631,15 @@ TEST_F(TestMockImageReplayerJournalPrepareReplayRequest, RemoteDemotePromote) {
   C_SaferCond ctx;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      mirror_peer_client_meta);
   bool resync_requested;
   bool syncing;
   auto request = create_request(
-    mock_local_image_ctx, mock_remote_journaler,
-    librbd::mirror::PROMOTION_STATE_PRIMARY, "local mirror uuid",
-    "remote mirror uuid", &mirror_peer_client_meta, &resync_requested,
-    &syncing, &ctx);
+    mock_state_builder, librbd::mirror::PROMOTION_STATE_PRIMARY,
+    "local mirror uuid", &resync_requested, &syncing, &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
   ASSERT_FALSE(resync_requested);
@@ -647,13 +698,15 @@ TEST_F(TestMockImageReplayerJournalPrepareReplayRequest, MultipleRemoteDemotePro
   C_SaferCond ctx;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      mirror_peer_client_meta);
   bool resync_requested;
   bool syncing;
   auto request = create_request(
-    mock_local_image_ctx, mock_remote_journaler,
-    librbd::mirror::PROMOTION_STATE_PRIMARY, "local mirror uuid",
-    "remote mirror uuid", &mirror_peer_client_meta, &resync_requested,
-    &syncing, &ctx);
+    mock_state_builder, librbd::mirror::PROMOTION_STATE_PRIMARY,
+    "local mirror uuid", &resync_requested, &syncing, &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
   ASSERT_FALSE(resync_requested);
@@ -700,13 +753,15 @@ TEST_F(TestMockImageReplayerJournalPrepareReplayRequest, LocalDemoteRemotePromot
   C_SaferCond ctx;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      mirror_peer_client_meta);
   bool resync_requested;
   bool syncing;
   auto request = create_request(
-    mock_local_image_ctx, mock_remote_journaler,
-    librbd::mirror::PROMOTION_STATE_PRIMARY, "local mirror uuid",
-    "remote mirror uuid", &mirror_peer_client_meta, &resync_requested,
-    &syncing, &ctx);
+    mock_state_builder, librbd::mirror::PROMOTION_STATE_PRIMARY,
+    "local mirror uuid", &resync_requested, &syncing, &ctx);
   request->send();
   ASSERT_EQ(0, ctx.wait());
   ASSERT_FALSE(resync_requested);
@@ -751,13 +806,15 @@ TEST_F(TestMockImageReplayerJournalPrepareReplayRequest, SplitBrainForcePromote)
   C_SaferCond ctx;
   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      mirror_peer_client_meta);
   bool resync_requested;
   bool syncing;
   auto request = create_request(
-    mock_local_image_ctx, mock_remote_journaler,
-    librbd::mirror::PROMOTION_STATE_PRIMARY, "local mirror uuid",
-    "remote mirror uuid", &mirror_peer_client_meta, &resync_requested,
-    &syncing, &ctx);
+    mock_state_builder, librbd::mirror::PROMOTION_STATE_PRIMARY,
+    "local mirror uuid", &resync_requested, &syncing, &ctx);
   request->send();
   ASSERT_EQ(-EEXIST, ctx.wait());
 }
index f8df90aac9d89d88000c03d9a0e60da732f90db5..de1513f192bd75342e49274b90e46bf73c794645 100644 (file)
@@ -11,6 +11,7 @@
 #include "tools/rbd_mirror/image_replayer/journal/Replayer.h"
 #include "tools/rbd_mirror/image_replayer/journal/EventPreprocessor.h"
 #include "tools/rbd_mirror/image_replayer/journal/ReplayStatusFormatter.h"
+#include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
 #include "test/journal/mock/MockJournaler.h"
 #include "test/librbd/mock/MockImageCtx.h"
 #include "test/rbd_mirror/mock/MockContextWQ.h"
@@ -209,6 +210,22 @@ struct ReplayStatusFormatter<librbd::MockTestImageCtx> {
   MOCK_METHOD2(get_or_send_update, bool(std::string *description, Context *on_finish));
 };
 
+template<>
+struct StateBuilder<librbd::MockTestImageCtx> {
+  StateBuilder(librbd::MockTestImageCtx& local_image_ctx,
+               ::journal::MockJournaler& remote_journaler,
+               const librbd::journal::MirrorPeerClientMeta& remote_client_meta)
+    : local_image_ctx(&local_image_ctx),
+      remote_journaler(&remote_journaler),
+      remote_client_meta(remote_client_meta) {
+  }
+
+  librbd::MockTestImageCtx* local_image_ctx;
+  std::string remote_mirror_uuid = "remote mirror uuid";
+  ::journal::MockJournaler* remote_journaler = nullptr;
+  librbd::journal::MirrorPeerClientMeta remote_client_meta;
+};
+
 EventPreprocessor<librbd::MockTestImageCtx>* EventPreprocessor<librbd::MockTestImageCtx>::s_instance = nullptr;
 ReplayStatusFormatter<librbd::MockTestImageCtx>* ReplayStatusFormatter<librbd::MockTestImageCtx>::s_instance = nullptr;
 
@@ -241,6 +258,7 @@ public:
   typedef Replayer<librbd::MockTestImageCtx> MockReplayer;
   typedef EventPreprocessor<librbd::MockTestImageCtx> MockEventPreprocessor;
   typedef ReplayStatusFormatter<librbd::MockTestImageCtx> MockReplayStatusFormatter;
+  typedef StateBuilder<librbd::MockTestImageCtx> MockStateBuilder;
   typedef Threads<librbd::MockTestImageCtx> MockThreads;
   typedef CloseImageRequest<librbd::MockTestImageCtx> MockCloseImageRequest;
   typedef librbd::journal::Replay<librbd::MockTestImageCtx> MockReplay;
@@ -290,11 +308,6 @@ public:
       .WillOnce(CompleteContext(r));
   }
 
-  void expect_shut_down(::journal::MockJournaler &mock_journaler, int r) {
-    EXPECT_CALL(mock_journaler, shut_down(_))
-      .WillOnce(CompleteContext(m_threads->work_queue, r));
-  }
-
   void expect_shut_down(MockReplay &mock_replay, bool cancel_ops, int r) {
     EXPECT_CALL(mock_replay, shut_down(cancel_ops, _))
       .WillOnce(WithArg<1>(CompleteContext(m_threads->work_queue, r)));
@@ -496,7 +509,6 @@ public:
     expect_send(mock_close_image_request, 0);
     expect_stop_replay(mock_remote_journaler, 0);
     EXPECT_CALL(mock_remote_journaler, remove_listener(_));
-    expect_shut_down(mock_remote_journaler, 0);
 
     C_SaferCond shutdown_ctx;
     mock_replayer.shut_down(&shutdown_ctx);
@@ -515,13 +527,15 @@ TEST_F(TestMockImageReplayerJournalReplayer, InitShutDown) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -545,22 +559,23 @@ TEST_F(TestMockImageReplayerJournalReplayer, InitShutDown) {
                                         mock_local_journal,
                                         mock_remote_journaler,
                                         mock_local_journal_replay));
-  ASSERT_EQ(nullptr, mock_local_image_ctx_ptr);
 }
 
 TEST_F(TestMockImageReplayerJournalReplayer, InitNoLocalJournal) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
 
   mock_local_image_ctx.journal = nullptr;
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -572,20 +587,21 @@ TEST_F(TestMockImageReplayerJournalReplayer, InitNoLocalJournal) {
   C_SaferCond init_ctx;
   mock_replayer.init(&init_ctx);
   ASSERT_EQ(-EINVAL, init_ctx.wait());
-  ASSERT_EQ(nullptr, mock_local_image_ctx_ptr);
 }
 
 TEST_F(TestMockImageReplayerJournalReplayer, InitRemoteJournalerError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -594,25 +610,25 @@ TEST_F(TestMockImageReplayerJournalReplayer, InitRemoteJournalerError) {
   expect_init(mock_remote_journaler, -EINVAL);
   MockCloseImageRequest mock_close_image_request;
   expect_send(mock_close_image_request, 0);
-  expect_shut_down(mock_remote_journaler, 0);
 
   C_SaferCond init_ctx;
   mock_replayer.init(&init_ctx);
   ASSERT_EQ(-EINVAL, init_ctx.wait());
-  ASSERT_EQ(nullptr, mock_local_image_ctx_ptr);
 }
 
 TEST_F(TestMockImageReplayerJournalReplayer, InitRemoteJournalerGetClientError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -625,25 +641,25 @@ TEST_F(TestMockImageReplayerJournalReplayer, InitRemoteJournalerGetClientError)
   MockCloseImageRequest mock_close_image_request;
   expect_send(mock_close_image_request, 0);
   EXPECT_CALL(mock_remote_journaler, remove_listener(_));
-  expect_shut_down(mock_remote_journaler, 0);
 
   C_SaferCond init_ctx;
   mock_replayer.init(&init_ctx);
   ASSERT_EQ(-EINVAL, init_ctx.wait());
-  ASSERT_EQ(nullptr, mock_local_image_ctx_ptr);
 }
 
 TEST_F(TestMockImageReplayerJournalReplayer, InitLocalJournalStartExternalReplayError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -657,25 +673,25 @@ TEST_F(TestMockImageReplayerJournalReplayer, InitLocalJournalStartExternalReplay
   MockCloseImageRequest mock_close_image_request;
   expect_send(mock_close_image_request, 0);
   EXPECT_CALL(mock_remote_journaler, remove_listener(_));
-  expect_shut_down(mock_remote_journaler, 0);
 
   C_SaferCond init_ctx;
   mock_replayer.init(&init_ctx);
   ASSERT_EQ(-EINVAL, init_ctx.wait());
-  ASSERT_EQ(nullptr, mock_local_image_ctx_ptr);
 }
 
 TEST_F(TestMockImageReplayerJournalReplayer, InitIsPromoted) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -703,12 +719,10 @@ TEST_F(TestMockImageReplayerJournalReplayer, InitIsPromoted) {
   MockCloseImageRequest mock_close_image_request;
   expect_send(mock_close_image_request, 0);
   EXPECT_CALL(mock_remote_journaler, remove_listener(_));
-  expect_shut_down(mock_remote_journaler, 0);
 
   C_SaferCond shutdown_ctx;
   mock_replayer.shut_down(&shutdown_ctx);
   ASSERT_EQ(0, shutdown_ctx.wait());
-  ASSERT_EQ(nullptr, mock_local_image_ctx_ptr);
 }
 
 TEST_F(TestMockImageReplayerJournalReplayer, InitDisconnected) {
@@ -718,13 +732,15 @@ TEST_F(TestMockImageReplayerJournalReplayer, InitDisconnected) {
   mock_local_image_ctx.config.set_val("rbd_mirroring_resync_after_disconnect",
                                       "false");
 
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -740,13 +756,11 @@ TEST_F(TestMockImageReplayerJournalReplayer, InitDisconnected) {
   MockCloseImageRequest mock_close_image_request;
   expect_send(mock_close_image_request, 0);
   EXPECT_CALL(mock_remote_journaler, remove_listener(_));
-  expect_shut_down(mock_remote_journaler, 0);
 
   C_SaferCond init_ctx;
   mock_replayer.init(&init_ctx);
   ASSERT_EQ(-ENOTCONN, init_ctx.wait());
   ASSERT_FALSE(mock_replayer.is_resync_requested());
-  ASSERT_EQ(nullptr, mock_local_image_ctx_ptr);
 }
 
 TEST_F(TestMockImageReplayerJournalReplayer, InitDisconnectedResync) {
@@ -756,13 +770,15 @@ TEST_F(TestMockImageReplayerJournalReplayer, InitDisconnectedResync) {
   mock_local_image_ctx.config.set_val("rbd_mirroring_resync_after_disconnect",
                                       "true");
 
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -778,26 +794,26 @@ TEST_F(TestMockImageReplayerJournalReplayer, InitDisconnectedResync) {
   MockCloseImageRequest mock_close_image_request;
   expect_send(mock_close_image_request, 0);
   EXPECT_CALL(mock_remote_journaler, remove_listener(_));
-  expect_shut_down(mock_remote_journaler, 0);
 
   C_SaferCond init_ctx;
   mock_replayer.init(&init_ctx);
   ASSERT_EQ(-ENOTCONN, init_ctx.wait());
   ASSERT_TRUE(mock_replayer.is_resync_requested());
-  ASSERT_EQ(nullptr, mock_local_image_ctx_ptr);
 }
 
 TEST_F(TestMockImageReplayerJournalReplayer, InitResyncRequested) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -826,25 +842,25 @@ TEST_F(TestMockImageReplayerJournalReplayer, InitResyncRequested) {
   MockCloseImageRequest mock_close_image_request;
   expect_send(mock_close_image_request, 0);
   EXPECT_CALL(mock_remote_journaler, remove_listener(_));
-  expect_shut_down(mock_remote_journaler, 0);
 
   C_SaferCond shutdown_ctx;
   mock_replayer.shut_down(&shutdown_ctx);
   ASSERT_EQ(0, shutdown_ctx.wait());
-  ASSERT_EQ(nullptr, mock_local_image_ctx_ptr);
 }
 
 TEST_F(TestMockImageReplayerJournalReplayer, InitResyncRequestedError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -874,25 +890,25 @@ TEST_F(TestMockImageReplayerJournalReplayer, InitResyncRequestedError) {
   MockCloseImageRequest mock_close_image_request;
   expect_send(mock_close_image_request, 0);
   EXPECT_CALL(mock_remote_journaler, remove_listener(_));
-  expect_shut_down(mock_remote_journaler, 0);
 
   C_SaferCond shutdown_ctx;
   mock_replayer.shut_down(&shutdown_ctx);
   ASSERT_EQ(0, shutdown_ctx.wait());
-  ASSERT_EQ(nullptr, mock_local_image_ctx_ptr);
 }
 
 TEST_F(TestMockImageReplayerJournalReplayer, ShutDownLocalJournalReplayError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -919,25 +935,25 @@ TEST_F(TestMockImageReplayerJournalReplayer, ShutDownLocalJournalReplayError) {
   expect_send(mock_close_image_request, 0);
   expect_stop_replay(mock_remote_journaler, 0);
   EXPECT_CALL(mock_remote_journaler, remove_listener(_));
-  expect_shut_down(mock_remote_journaler, -EPERM);
 
   C_SaferCond shutdown_ctx;
   mock_replayer.shut_down(&shutdown_ctx);
   ASSERT_EQ(-EINVAL, shutdown_ctx.wait());
-  ASSERT_EQ(nullptr, mock_local_image_ctx_ptr);
 }
 
 TEST_F(TestMockImageReplayerJournalReplayer, CloseLocalImageError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -964,25 +980,25 @@ TEST_F(TestMockImageReplayerJournalReplayer, CloseLocalImageError) {
   expect_send(mock_close_image_request, -EINVAL);
   expect_stop_replay(mock_remote_journaler, 0);
   EXPECT_CALL(mock_remote_journaler, remove_listener(_));
-  expect_shut_down(mock_remote_journaler, -EPERM);
 
   C_SaferCond shutdown_ctx;
   mock_replayer.shut_down(&shutdown_ctx);
   ASSERT_EQ(-EINVAL, shutdown_ctx.wait());
-  ASSERT_EQ(nullptr, mock_local_image_ctx_ptr);
 }
 
 TEST_F(TestMockImageReplayerJournalReplayer, StopRemoteJournalerError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -1009,70 +1025,25 @@ TEST_F(TestMockImageReplayerJournalReplayer, StopRemoteJournalerError) {
   expect_send(mock_close_image_request, 0);
   expect_stop_replay(mock_remote_journaler, -EPERM);
   EXPECT_CALL(mock_remote_journaler, remove_listener(_));
-  expect_shut_down(mock_remote_journaler, 0);
 
   C_SaferCond shutdown_ctx;
   mock_replayer.shut_down(&shutdown_ctx);
   ASSERT_EQ(-EPERM, shutdown_ctx.wait());
-  ASSERT_EQ(nullptr, mock_local_image_ctx_ptr);
-}
-
-TEST_F(TestMockImageReplayerJournalReplayer, ShutDownRemoteJournalerError) {
-  librbd::MockTestJournal mock_local_journal;
-  librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
-                                                mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
-  ::journal::MockJournaler mock_remote_journaler;
-  MockReplayerListener mock_replayer_listener;
-  MockThreads mock_threads{m_threads};
-  MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
-
-  expect_work_queue_repeatedly(mock_threads);
-
-  InSequence seq;
-
-  MockReplay mock_local_journal_replay;
-  MockEventPreprocessor mock_event_preprocessor;
-  MockReplayStatusFormatter mock_replay_status_formatter;
-  librbd::journal::Listener* local_journal_listener = nullptr;
-  ::journal::ReplayHandler* remote_replay_handler = nullptr;
-  ::journal::JournalMetadataListener* remote_journaler_listener = nullptr;
-  ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads,
-                                   mock_replayer_listener, mock_local_journal,
-                                   mock_remote_journaler,
-                                   mock_local_journal_replay,
-                                   &local_journal_listener,
-                                   &remote_replay_handler,
-                                   &remote_journaler_listener));
-
-  expect_shut_down(mock_local_journal_replay, true, 0);
-  EXPECT_CALL(mock_local_journal, remove_listener(_));
-  EXPECT_CALL(mock_local_journal, stop_external_replay());
-  MockCloseImageRequest mock_close_image_request;
-  expect_send(mock_close_image_request, 0);
-  expect_stop_replay(mock_remote_journaler, 0);
-  EXPECT_CALL(mock_remote_journaler, remove_listener(_));
-  expect_shut_down(mock_remote_journaler, -EPERM);
-
-  C_SaferCond shutdown_ctx;
-  mock_replayer.shut_down(&shutdown_ctx);
-  ASSERT_EQ(-EPERM, shutdown_ctx.wait());
-  ASSERT_EQ(nullptr, mock_local_image_ctx_ptr);
 }
 
 TEST_F(TestMockImageReplayerJournalReplayer, Replay) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   ::journal::MockReplayEntry mock_replay_entry;
   expect_work_queue_repeatedly(mock_threads);
@@ -1141,13 +1112,15 @@ TEST_F(TestMockImageReplayerJournalReplayer, DecodeError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   ::journal::MockReplayEntry mock_replay_entry;
   expect_work_queue_repeatedly(mock_threads);
@@ -1208,13 +1181,15 @@ TEST_F(TestMockImageReplayerJournalReplayer, DelayedReplay) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   ::journal::MockReplayEntry mock_replay_entry;
   expect_work_queue_repeatedly(mock_threads);
@@ -1319,13 +1294,15 @@ TEST_F(TestMockImageReplayerJournalReplayer, ReplayNoMemoryError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -1362,13 +1339,15 @@ TEST_F(TestMockImageReplayerJournalReplayer, LocalJournalForcePromoted) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -1402,13 +1381,15 @@ TEST_F(TestMockImageReplayerJournalReplayer, LocalJournalResyncRequested) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -1444,16 +1425,18 @@ TEST_F(TestMockImageReplayerJournalReplayer, RemoteJournalDisconnected) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   mock_local_image_ctx.config.set_val("rbd_mirroring_resync_after_disconnect",
                                       "true");
 
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -1497,13 +1480,15 @@ TEST_F(TestMockImageReplayerJournalReplayer, Flush) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -1540,13 +1525,15 @@ TEST_F(TestMockImageReplayerJournalReplayer, FlushError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -1582,13 +1569,15 @@ TEST_F(TestMockImageReplayerJournalReplayer, FlushCommitPositionError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   expect_work_queue_repeatedly(mock_threads);
 
@@ -1626,14 +1615,18 @@ TEST_F(TestMockImageReplayerJournalReplayer, ReplayFlushShutDownError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
+  ::journal::MockReplayEntry mock_replay_entry;
+  expect_get_commit_tid_in_debug(mock_replay_entry);
   expect_work_queue_repeatedly(mock_threads);
 
   InSequence seq;
@@ -1652,7 +1645,6 @@ TEST_F(TestMockImageReplayerJournalReplayer, ReplayFlushShutDownError) {
                                    &remote_replay_handler,
                                    &remote_journaler_listener));
 
-  ::journal::MockReplayEntry mock_replay_entry;
   expect_try_pop_front(mock_remote_journaler, 1, true);
   expect_shut_down(mock_local_journal_replay, false, -EINVAL);
   EXPECT_CALL(mock_local_journal, stop_external_replay());
@@ -1667,7 +1659,6 @@ TEST_F(TestMockImageReplayerJournalReplayer, ReplayFlushShutDownError) {
   expect_send(mock_close_image_request, 0);
   expect_stop_replay(mock_remote_journaler, 0);
   EXPECT_CALL(mock_remote_journaler, remove_listener(_));
-  expect_shut_down(mock_remote_journaler, 0);
 
   C_SaferCond shutdown_ctx;
   mock_replayer.shut_down(&shutdown_ctx);
@@ -1678,14 +1669,18 @@ TEST_F(TestMockImageReplayerJournalReplayer, ReplayFlushStartError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
+  ::journal::MockReplayEntry mock_replay_entry;
+  expect_get_commit_tid_in_debug(mock_replay_entry);
   expect_work_queue_repeatedly(mock_threads);
 
   InSequence seq;
@@ -1704,7 +1699,6 @@ TEST_F(TestMockImageReplayerJournalReplayer, ReplayFlushStartError) {
                                    &remote_replay_handler,
                                    &remote_journaler_listener));
 
-  ::journal::MockReplayEntry mock_replay_entry;
   expect_try_pop_front(mock_remote_journaler, 1, true);
   expect_shut_down(mock_local_journal_replay, false, 0);
   EXPECT_CALL(mock_local_journal, stop_external_replay());
@@ -1720,7 +1714,6 @@ TEST_F(TestMockImageReplayerJournalReplayer, ReplayFlushStartError) {
   expect_send(mock_close_image_request, 0);
   expect_stop_replay(mock_remote_journaler, 0);
   EXPECT_CALL(mock_remote_journaler, remove_listener(_));
-  expect_shut_down(mock_remote_journaler, 0);
 
   C_SaferCond shutdown_ctx;
   mock_replayer.shut_down(&shutdown_ctx);
@@ -1731,14 +1724,18 @@ TEST_F(TestMockImageReplayerJournalReplayer, GetTagError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
+  ::journal::MockReplayEntry mock_replay_entry;
+  expect_get_commit_tid_in_debug(mock_replay_entry);
   expect_work_queue_repeatedly(mock_threads);
 
   InSequence seq;
@@ -1761,7 +1758,6 @@ TEST_F(TestMockImageReplayerJournalReplayer, GetTagError) {
     {1, 0, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
                             librbd::Journal<>::LOCAL_MIRROR_UUID,
                             true, 0, 0})};
-  ::journal::MockReplayEntry mock_replay_entry;
   expect_try_pop_front(mock_remote_journaler, tag.tid, true);
   expect_shut_down(mock_local_journal_replay, false, 0);
   EXPECT_CALL(mock_local_journal, stop_external_replay());
@@ -1784,13 +1780,15 @@ TEST_F(TestMockImageReplayerJournalReplayer, AllocateTagDemotion) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   ::journal::MockReplayEntry mock_replay_entry;
   expect_work_queue_repeatedly(mock_threads);
@@ -1846,16 +1844,19 @@ TEST_F(TestMockImageReplayerJournalReplayer, AllocateTagError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   ::journal::MockReplayEntry mock_replay_entry;
   expect_work_queue_repeatedly(mock_threads);
+  expect_get_commit_tid_in_debug(mock_replay_entry);
   expect_get_tag_tid_in_debug(mock_local_journal);
 
   InSequence seq;
@@ -1903,13 +1904,15 @@ TEST_F(TestMockImageReplayerJournalReplayer, PreprocessError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   ::journal::MockReplayEntry mock_replay_entry;
   expect_work_queue_repeatedly(mock_threads);
@@ -1965,13 +1968,15 @@ TEST_F(TestMockImageReplayerJournalReplayer, ProcessError) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   ::journal::MockReplayEntry mock_replay_entry;
   expect_work_queue_repeatedly(mock_threads);
@@ -2033,13 +2038,15 @@ TEST_F(TestMockImageReplayerJournalReplayer, ImageNameUpdated) {
   librbd::MockTestJournal mock_local_journal;
   librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx,
                                                 mock_local_journal};
-  librbd::MockTestImageCtx* mock_local_image_ctx_ptr = &mock_local_image_ctx;
   ::journal::MockJournaler mock_remote_journaler;
   MockReplayerListener mock_replayer_listener;
   MockThreads mock_threads{m_threads};
+  MockStateBuilder mock_state_builder(mock_local_image_ctx,
+                                      mock_remote_journaler,
+                                      {});
   MockReplayer mock_replayer{
-    &mock_local_image_ctx_ptr, &mock_remote_journaler, "local mirror uuid",
-    "remote mirror uuid", &mock_replayer_listener, &mock_threads};
+    &mock_threads, "local mirror uuid", &mock_state_builder,
+    &mock_replayer_listener};
 
   ::journal::MockReplayEntry mock_replay_entry;
   expect_work_queue_repeatedly(mock_threads);
index ee83b6a5121767c29eaeac474cbbc6d360e972fb..9770c61378b366485c0996fb799cddfbaca2d854 100644 (file)
@@ -4,6 +4,7 @@
 #include "test/rbd_mirror/test_mock_fixture.h"
 #include "librbd/journal/TypeTraits.h"
 #include "librbd/mirror/GetInfoRequest.h"
+#include "tools/rbd_mirror/BaseRequest.h"
 #include "tools/rbd_mirror/InstanceWatcher.h"
 #include "tools/rbd_mirror/Threads.h"
 #include "tools/rbd_mirror/image_replayer/BootstrapRequest.h"
 #include "tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.h"
 #include "tools/rbd_mirror/image_replayer/PrepareRemoteImageRequest.h"
 #include "tools/rbd_mirror/image_replayer/StateBuilder.h"
-#include "tools/rbd_mirror/image_replayer/journal/CreateLocalImageRequest.h"
-#include "tools/rbd_mirror/image_replayer/journal/PrepareReplayRequest.h"
-#include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
-#include "test/journal/mock/MockJournaler.h"
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
 #include "test/librbd/mock/MockImageCtx.h"
-#include "test/librbd/mock/MockJournal.h"
 #include "test/rbd_mirror/mock/image_sync/MockSyncPointHandler.h"
+#include "test/rbd_mirror/mock/MockBaseRequest.h"
 
 namespace librbd {
 
@@ -34,15 +31,6 @@ struct MockTestImageCtx : public librbd::MockImageCtx {
 
 } // anonymous namespace
 
-namespace journal {
-
-template <>
-struct TypeTraits<librbd::MockTestImageCtx> {
-  typedef ::journal::MockJournaler Journaler;
-};
-
-} // namespace journal
-
 namespace mirror {
 
 template<>
@@ -228,22 +216,19 @@ struct OpenLocalImageRequest<librbd::MockTestImageCtx> {
 template<>
 struct PrepareLocalImageRequest<librbd::MockTestImageCtx> {
   static PrepareLocalImageRequest* s_instance;
-  std::string *local_image_id = nullptr;
   std::string *local_image_name = nullptr;
-  std::string *tag_owner = nullptr;
+  StateBuilder<librbd::MockTestImageCtx>** state_builder = nullptr;
   Context *on_finish = nullptr;
 
   static PrepareLocalImageRequest* create(librados::IoCtx &,
                                           const std::string &global_image_id,
-                                          std::string *local_image_id,
                                           std::string *local_image_name,
-                                          std::string *tag_owner,
+                                          StateBuilder<librbd::MockTestImageCtx>** state_builder,
                                           ContextWQ *work_queue,
                                           Context *on_finish) {
     ceph_assert(s_instance != nullptr);
-    s_instance->local_image_id = local_image_id;
     s_instance->local_image_name = local_image_name;
-    s_instance->tag_owner = tag_owner;
+    s_instance->state_builder = state_builder;
     s_instance->on_finish = on_finish;
     return s_instance;
   }
@@ -258,11 +243,7 @@ struct PrepareLocalImageRequest<librbd::MockTestImageCtx> {
 template<>
 struct PrepareRemoteImageRequest<librbd::MockTestImageCtx> {
   static PrepareRemoteImageRequest* s_instance;
-  std::string *remote_mirror_uuid = nullptr;
-  std::string *remote_image_id = nullptr;
-  ::journal::MockJournaler **remote_journaler = nullptr;
-  cls::journal::ClientState *client_state;
-  librbd::journal::MirrorPeerClientMeta *client_meta = nullptr;
+  StateBuilder<librbd::MockTestImageCtx>** state_builder = nullptr;
   Context *on_finish = nullptr;
 
   static PrepareRemoteImageRequest* create(Threads<librbd::MockTestImageCtx> *threads,
@@ -270,20 +251,11 @@ struct PrepareRemoteImageRequest<librbd::MockTestImageCtx> {
                                            librados::IoCtx &,
                                            const std::string &global_image_id,
                                            const std::string &local_mirror_uuid,
-                                           const std::string &local_image_id,
                                            ::journal::CacheManagerHandler *cache_manager_handler,
-                                           std::string *remote_mirror_uuid,
-                                           std::string *remote_image_id,
-                                           ::journal::MockJournaler **remote_journaler,
-                                           cls::journal::ClientState *client_state,
-                                           librbd::journal::MirrorPeerClientMeta *client_meta,
+                                           StateBuilder<librbd::MockTestImageCtx>** state_builder,
                                            Context *on_finish) {
     ceph_assert(s_instance != nullptr);
-    s_instance->remote_mirror_uuid = remote_mirror_uuid;
-    s_instance->remote_image_id = remote_image_id;
-    s_instance->remote_journaler = remote_journaler;
-    s_instance->client_state = client_state;
-    s_instance->client_meta = client_meta;
+    s_instance->state_builder = state_builder;
     s_instance->on_finish = on_finish;
     return s_instance;
   }
@@ -297,107 +269,15 @@ struct PrepareRemoteImageRequest<librbd::MockTestImageCtx> {
 
 template<>
 struct StateBuilder<librbd::MockTestImageCtx> {
-  virtual ~StateBuilder() {}
-
-  void destroy_sync_point_handler() {
-  }
-  void destroy() {
-  }
-};
-
-CloseImageRequest<librbd::MockTestImageCtx>*
-  CloseImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
-OpenImageRequest<librbd::MockTestImageCtx>*
-  OpenImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
-OpenLocalImageRequest<librbd::MockTestImageCtx>*
-  OpenLocalImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
-PrepareLocalImageRequest<librbd::MockTestImageCtx>*
-  PrepareLocalImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
-PrepareRemoteImageRequest<librbd::MockTestImageCtx>*
-  PrepareRemoteImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
-
-namespace journal {
-
-template<>
-struct CreateLocalImageRequest<librbd::MockTestImageCtx> {
-  static CreateLocalImageRequest* s_instance;
-
-  librbd::journal::MirrorPeerClientMeta* client_meta = nullptr;
-  std::string* local_image_id;
-  Context *on_finish = nullptr;
-
-  static CreateLocalImageRequest* create(
-      Threads<librbd::MockTestImageCtx>* mock_threads,
-      librados::IoCtx &local_io_ctx,
-      librbd::MockTestImageCtx* mock_remote_image_ctx,
-      ::journal::MockJournaler *mock_remote_journaler,
-      const std::string &global_image_id,
-      const std::string &remote_mirror_uuid,
-      librbd::journal::MirrorPeerClientMeta* client_meta,
-      ProgressContext* progress_ctx,
-      std::string* local_image_id, Context *on_finish) {
-    ceph_assert(s_instance != nullptr);
-    s_instance->client_meta = client_meta;
-    s_instance->local_image_id = local_image_id;
-    s_instance->on_finish = on_finish;
-    return s_instance;
-  }
-
-  CreateLocalImageRequest() {
-    ceph_assert(s_instance == nullptr);
-    s_instance = this;
-  }
-  ~CreateLocalImageRequest() {
-    s_instance = nullptr;
-  }
-
-  MOCK_METHOD0(send, void());
-};
-
-template<>
-struct PrepareReplayRequest<librbd::MockTestImageCtx> {
-  static PrepareReplayRequest* s_instance;
-
-  bool* resync_requested = nullptr;
-  bool* syncing = nullptr;
-  Context *on_finish = nullptr;
-
-  static PrepareReplayRequest* create(
-      librbd::MockTestImageCtx* local_image_ctx,
-      ::journal::MockJournaler* remote_journaler,
-      librbd::mirror::PromotionState remote_promotion_state,
-      const std::string& local_mirror_uuid,
-      const std::string& remote_mirror_uuid,
-      librbd::journal::MirrorPeerClientMeta* client_meta,
-      ProgressContext* progress_ctx,
-      bool* resync_requested, bool* syncing, Context* on_finish) {
-    ceph_assert(s_instance != nullptr);
-    s_instance->resync_requested = resync_requested;
-    s_instance->syncing = syncing;
-    s_instance->on_finish = on_finish;
-    return s_instance;
-  }
-
-  PrepareReplayRequest() {
-    ceph_assert(s_instance == nullptr);
-    s_instance = this;
-  }
-  ~PrepareReplayRequest() {
-    s_instance = nullptr;
-  }
-
-  MOCK_METHOD0(send, void());
-};
-
-template<>
-struct StateBuilder<librbd::MockTestImageCtx>
-  : image_replayer::StateBuilder<librbd::MockTestImageCtx>{
   static StateBuilder* s_instance;
 
-  ::journal::MockJournaler* remote_journaler = nullptr;
-  librbd::journal::MirrorPeerClientMeta remote_client_meta;
-
   image_sync::MockSyncPointHandler mock_sync_point_handler;
+  MockBaseRequest mock_base_request;
+
+  librbd::MockTestImageCtx* local_image_ctx = nullptr;
+  std::string local_image_id;
+  std::string remote_mirror_uuid;
+  std::string remote_image_id;
 
   static StateBuilder* create(const std::string&) {
     ceph_assert(s_instance != nullptr);
@@ -411,16 +291,43 @@ struct StateBuilder<librbd::MockTestImageCtx>
   StateBuilder() {
     s_instance = this;
   }
+
+  MOCK_CONST_METHOD0(is_disconnected, bool());
+  MOCK_CONST_METHOD0(is_local_primary, bool());
+  MOCK_CONST_METHOD0(is_linked, bool());
+
+  MOCK_METHOD6(create_local_image_request,
+               BaseRequest*(Threads<librbd::MockTestImageCtx>*,
+                            librados::IoCtx&,
+                            librbd::MockTestImageCtx*,
+                            const std::string&,
+                            ProgressContext*,
+                            Context*));
+  MOCK_METHOD6(create_prepare_replay_request,
+               BaseRequest*(const std::string&,
+                            librbd::mirror::PromotionState,
+                            ProgressContext*,
+                            bool*, bool*, Context*));
+
+  void destroy_sync_point_handler() {
+  }
+  void destroy() {
+  }
 };
 
-CreateLocalImageRequest<librbd::MockTestImageCtx>*
-  CreateLocalImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
-PrepareReplayRequest<librbd::MockTestImageCtx>*
-  PrepareReplayRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+CloseImageRequest<librbd::MockTestImageCtx>*
+  CloseImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+OpenImageRequest<librbd::MockTestImageCtx>*
+  OpenImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+OpenLocalImageRequest<librbd::MockTestImageCtx>*
+  OpenLocalImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+PrepareLocalImageRequest<librbd::MockTestImageCtx>*
+  PrepareLocalImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+PrepareRemoteImageRequest<librbd::MockTestImageCtx>*
+  PrepareRemoteImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
 StateBuilder<librbd::MockTestImageCtx>*
   StateBuilder<librbd::MockTestImageCtx>::s_instance = nullptr;
 
-} // namespace journal
 } // namespace image_replayer
 } // namespace mirror
 } // namespace rbd
@@ -440,6 +347,7 @@ using ::testing::Return;
 using ::testing::SetArgPointee;
 using ::testing::StrEq;
 using ::testing::WithArg;
+using ::testing::WithArgs;
 
 MATCHER_P(IsSameIoCtx, io_ctx, "") {
   return &get_mock_io_ctx(arg) == &get_mock_io_ctx(*io_ctx);
@@ -456,9 +364,7 @@ public:
   typedef OpenLocalImageRequest<librbd::MockTestImageCtx> MockOpenLocalImageRequest;
   typedef PrepareLocalImageRequest<librbd::MockTestImageCtx> MockPrepareLocalImageRequest;
   typedef PrepareRemoteImageRequest<librbd::MockTestImageCtx> MockPrepareRemoteImageRequest;
-  typedef journal::CreateLocalImageRequest<librbd::MockTestImageCtx> MockCreateLocalImageRequest;
-  typedef journal::PrepareReplayRequest<librbd::MockTestImageCtx> MockPrepareReplayRequest;
-  typedef journal::StateBuilder<librbd::MockTestImageCtx> MockStateBuilder;
+  typedef StateBuilder<librbd::MockTestImageCtx> MockStateBuilder;
   typedef librbd::mirror::GetInfoRequest<librbd::MockTestImageCtx> MockGetMirrorInfoRequest;
   typedef std::list<cls::journal::Tag> Tags;
 
@@ -474,44 +380,51 @@ public:
   }
 
   void expect_send(MockPrepareLocalImageRequest &mock_request,
-                   const std::string &local_image_id,
-                   const std::string &local_image_name,
-                   const std::string &tag_owner,
-                   int r) {
+                   MockStateBuilder& mock_state_builder,
+                   const std::string& local_image_id,
+                   const std::string& local_image_name, int r) {
     EXPECT_CALL(mock_request, send())
-      .WillOnce(Invoke([&mock_request, local_image_id, local_image_name,
-                        tag_owner, r]() {
+      .WillOnce(Invoke([&mock_request, &mock_state_builder, local_image_id,
+                        local_image_name, r]() {
           if (r == 0) {
-            *mock_request.local_image_id = local_image_id;
+            *mock_request.state_builder = &mock_state_builder;
+            mock_state_builder.local_image_id = local_image_id;
             *mock_request.local_image_name = local_image_name;
-            *mock_request.tag_owner = tag_owner;
           }
           mock_request.on_finish->complete(r);
         }));
   }
 
   void expect_send(MockPrepareRemoteImageRequest& mock_request,
-                   ::journal::MockJournaler& mock_remote_journaler,
-                   const std::string& mirror_uuid, const std::string& image_id,
-                   cls::journal::ClientState client_state,
-                   const librbd::journal::MirrorPeerClientMeta& mirror_peer_client_meta,
+                   MockStateBuilder& mock_state_builder,
+                   const std::string& remote_mirror_uuid,
+                   const std::string& remote_image_id,
                    int r) {
     EXPECT_CALL(mock_request, send())
-      .WillOnce(Invoke([&mock_request, &mock_remote_journaler, image_id,
-                        mirror_uuid, client_state, mirror_peer_client_meta,
-                        r]() {
+      .WillOnce(Invoke([&mock_request, &mock_state_builder, remote_mirror_uuid,
+                        remote_image_id, r]() {
                   if (r >= 0) {
-                    *mock_request.remote_journaler = &mock_remote_journaler;
-                    *mock_request.client_state = client_state;
-                    *mock_request.client_meta = mirror_peer_client_meta;
+                    *mock_request.state_builder = &mock_state_builder;
+                    mock_state_builder.remote_image_id = remote_image_id;
                   }
 
-                  *mock_request.remote_mirror_uuid = mirror_uuid;
-                  *mock_request.remote_image_id = image_id;
+                  mock_state_builder.remote_mirror_uuid = remote_mirror_uuid;
                   mock_request.on_finish->complete(r);
                 }));
   }
 
+  void expect_is_local_primary(MockStateBuilder& mock_state_builder,
+                               bool is_primary) {
+    EXPECT_CALL(mock_state_builder, is_local_primary())
+      .WillOnce(Return(is_primary));
+  }
+
+  void expect_is_disconnected(MockStateBuilder& mock_state_builder,
+                              bool is_disconnected) {
+    EXPECT_CALL(mock_state_builder, is_disconnected())
+      .WillOnce(Return(is_disconnected));
+  }
+
   void expect_open_image(MockOpenImageRequest &mock_open_image_request,
                          librados::IoCtx &io_ctx, const std::string &image_id,
                          librbd::MockTestImageCtx &mock_image_ctx, int r) {
@@ -563,36 +476,43 @@ public:
         }));
   }
 
-  void expect_create_local_image(
-      MockCreateLocalImageRequest &mock_create_local_image_request,
-      const std::string& local_image_id, int r) {
-    EXPECT_CALL(mock_create_local_image_request, send())
-      .WillOnce(Invoke([this, &mock_create_local_image_request, local_image_id,
-                        r]() {
+  void expect_create_local_image(MockStateBuilder& mock_state_builder,
+                                 const std::string& local_image_id, int r) {
+    EXPECT_CALL(mock_state_builder,
+                create_local_image_request(_, _, _, _, _, _))
+      .WillOnce(WithArg<5>(
+        Invoke([this, &mock_state_builder, local_image_id, r](Context* ctx) {
           if (r >= 0) {
-            mock_create_local_image_request.client_meta->state =
-              librbd::journal::MIRROR_PEER_STATE_SYNCING;
-            mock_create_local_image_request.client_meta->image_id =
-              local_image_id;
-            *mock_create_local_image_request.local_image_id = local_image_id;
+            mock_state_builder.local_image_id = local_image_id;
           }
+          mock_state_builder.mock_base_request.on_finish = ctx;
+          return &mock_state_builder.mock_base_request;
+        })));
+    EXPECT_CALL(mock_state_builder.mock_base_request, send())
+      .WillOnce(Invoke([this, &mock_state_builder, r]() {
           m_threads->work_queue->queue(
-            mock_create_local_image_request.on_finish, r);
+            mock_state_builder.mock_base_request.on_finish, r);
         }));
   }
 
-  void expect_prepare_replay(
-      MockPrepareReplayRequest& mock_prepare_replay_request,
-      bool resync_requested, bool syncing, int r) {
-    EXPECT_CALL(mock_prepare_replay_request, send())
-      .WillOnce(Invoke([this, &mock_prepare_replay_request, resync_requested,
-                        syncing, r]() {
+  void expect_prepare_replay(MockStateBuilder& mock_state_builder,
+                             bool resync_requested, bool syncing, int r) {
+    EXPECT_CALL(mock_state_builder,
+                create_prepare_replay_request(_, _, _, _, _, _))
+      .WillOnce(WithArgs<3, 4, 5>(
+        Invoke([this, &mock_state_builder, resync_requested, syncing, r]
+               (bool* resync, bool* sync, Context* ctx) {
           if (r >= 0) {
-            *mock_prepare_replay_request.resync_requested = resync_requested;
-            *mock_prepare_replay_request.syncing = syncing;
+            *resync = resync_requested;
+            *sync = syncing;
           }
-          m_threads->work_queue->queue(mock_prepare_replay_request.on_finish,
-                                       r);
+          mock_state_builder.mock_base_request.on_finish = ctx;
+          return &mock_state_builder.mock_base_request;
+        })));
+    EXPECT_CALL(mock_state_builder.mock_base_request, send())
+      .WillOnce(Invoke([this, &mock_state_builder, r]() {
+          m_threads->work_queue->queue(
+            mock_state_builder.mock_base_request.on_finish, r);
         }));
   }
 
@@ -617,22 +537,14 @@ public:
                                     global_image_id,
                                     local_mirror_uuid,
                                     nullptr, nullptr,
-                                    &m_local_test_image_ctx,
-                                    &m_local_image_id,
-                                    &m_remote_image_id,
-                                    &m_remote_mirror_uuid,
-                                    &m_mock_remote_journaler,
+                                    &m_mock_state_builder,
                                     &m_do_resync, on_finish);
   }
 
   librbd::ImageCtx *m_remote_image_ctx;
   librbd::ImageCtx *m_local_image_ctx = nullptr;
 
-  librbd::MockTestImageCtx *m_local_test_image_ctx = nullptr;
-  std::string m_local_image_id;
-  std::string m_remote_image_id;
-  std::string m_remote_mirror_uuid;
-  ::journal::MockJournaler *m_mock_remote_journaler = nullptr;
+  MockStateBuilder* m_mock_state_builder = nullptr;
   bool m_do_resync = false;
 };
 
@@ -640,23 +552,18 @@ TEST_F(TestMockImageReplayerBootstrapRequest, Success) {
   InSequence seq;
 
   // prepare local image
+  MockStateBuilder mock_state_builder;
   MockPrepareLocalImageRequest mock_prepare_local_image_request;
-  expect_send(mock_prepare_local_image_request, m_local_image_ctx->id,
-              m_local_image_ctx->name, "remote mirror uuid", 0);
+  expect_send(mock_prepare_local_image_request, mock_state_builder,
+              m_local_image_ctx->id, m_local_image_ctx->name, 0);
 
   // prepare remote image
   MockPrepareRemoteImageRequest mock_prepare_remote_image_request;
-  ::journal::MockJournaler mock_remote_journaler;
-  cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
-  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
-    m_local_image_ctx->id};
-  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
-  expect_send(mock_prepare_remote_image_request, mock_remote_journaler,
-              "remote mirror uuid", m_remote_image_ctx->id, client_state,
-              mirror_peer_client_meta, 0);
+  expect_send(mock_prepare_remote_image_request, mock_state_builder,
+              "remote mirror uuid", m_remote_image_ctx->id, 0);
+  expect_is_local_primary(mock_state_builder, false);
 
   // open the remote image
-  librbd::MockJournal mock_journal;
   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
   MockOpenImageRequest mock_open_image_request;
   expect_open_image(mock_open_image_request, m_remote_io_ctx,
@@ -671,14 +578,13 @@ TEST_F(TestMockImageReplayerBootstrapRequest, Success) {
 
   // open the local image
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
-  mock_local_image_ctx.journal = &mock_journal;
   MockOpenLocalImageRequest mock_open_local_image_request;
   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
                           mock_local_image_ctx.id, &mock_local_image_ctx, 0);
 
   // prepare replay
-  MockPrepareReplayRequest mock_prepare_replay_request;
-  expect_prepare_replay(mock_prepare_replay_request, false, false, 0);
+  expect_prepare_replay(mock_state_builder, false, false, 0);
+  expect_is_disconnected(mock_state_builder, false);
 
   // close remote image
   MockCloseImageRequest mock_close_image_request;
@@ -699,22 +605,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, OpenLocalImageError) {
 
   // prepare local image
   MockPrepareLocalImageRequest mock_prepare_local_image_request;
-  expect_send(mock_prepare_local_image_request, m_local_image_ctx->id,
-              m_local_image_ctx->name, "remote mirror uuid", 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_prepare_local_image_request, mock_state_builder,
+              m_local_image_ctx->id, m_local_image_ctx->name, 0);
 
   // prepare remote image
   MockPrepareRemoteImageRequest mock_prepare_remote_image_request;
-  ::journal::MockJournaler mock_remote_journaler;
-  cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
-  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
-    m_local_image_ctx->id};
-  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
-  expect_send(mock_prepare_remote_image_request, mock_remote_journaler,
-              "remote mirror uuid", m_remote_image_ctx->id, client_state,
-              mirror_peer_client_meta, 0);
+  expect_send(mock_prepare_remote_image_request, mock_state_builder,
+              "remote mirror uuid", m_remote_image_ctx->id, 0);
+  expect_is_local_primary(mock_state_builder, false);
 
   // open the remote image
-  librbd::MockJournal mock_journal;
   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
   MockOpenImageRequest mock_open_image_request;
   expect_open_image(mock_open_image_request, m_remote_io_ctx,
@@ -729,7 +630,6 @@ TEST_F(TestMockImageReplayerBootstrapRequest, OpenLocalImageError) {
 
   // open the local image
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
-  mock_local_image_ctx.journal = &mock_journal;
   MockOpenLocalImageRequest mock_open_local_image_request;
   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
                           mock_local_image_ctx.id, &mock_local_image_ctx,
@@ -754,22 +654,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, OpenLocalImageDNE) {
 
   // prepare local image
   MockPrepareLocalImageRequest mock_prepare_local_image_request;
-  expect_send(mock_prepare_local_image_request, m_local_image_ctx->id,
-              m_local_image_ctx->name, "remote mirror uuid", 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_prepare_local_image_request, mock_state_builder,
+              m_local_image_ctx->id, m_local_image_ctx->name, 0);
 
   // prepare remote image
   MockPrepareRemoteImageRequest mock_prepare_remote_image_request;
-  ::journal::MockJournaler mock_remote_journaler;
-  cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
-  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
-    m_local_image_ctx->id};
-  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
-  expect_send(mock_prepare_remote_image_request, mock_remote_journaler,
-              "remote mirror uuid", m_remote_image_ctx->id, client_state,
-              mirror_peer_client_meta, 0);
+  expect_send(mock_prepare_remote_image_request, mock_state_builder,
+              "remote mirror uuid", m_remote_image_ctx->id, 0);
+  expect_is_local_primary(mock_state_builder, false);
 
   // open the remote image
-  librbd::MockJournal mock_journal;
   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
   MockOpenImageRequest mock_open_image_request;
   expect_open_image(mock_open_image_request, m_remote_io_ctx,
@@ -784,24 +679,21 @@ TEST_F(TestMockImageReplayerBootstrapRequest, OpenLocalImageDNE) {
 
   // open the local image
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
-  mock_local_image_ctx.journal = &mock_journal;
   MockOpenLocalImageRequest mock_open_local_image_request;
   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
                           mock_local_image_ctx.id, &mock_local_image_ctx,
                           -ENOENT);
 
   // create local image
-  MockCreateLocalImageRequest mock_create_local_image_request;
-  expect_create_local_image(mock_create_local_image_request, "local image id",
-                            0);
+  expect_create_local_image(mock_state_builder, "local image id", 0);
 
   // re-open the local image
   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
                           "local image id", &mock_local_image_ctx, 0);
 
   // prepare replay
-  MockPrepareReplayRequest mock_prepare_replay_request;
-  expect_prepare_replay(mock_prepare_replay_request, false, false, 0);
+  expect_prepare_replay(mock_state_builder, false, false, 0);
+  expect_is_disconnected(mock_state_builder, false);
 
   // close remote image
   MockCloseImageRequest mock_close_image_request;
@@ -822,22 +714,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, OpenLocalImagePrimary) {
 
   // prepare local image
   MockPrepareLocalImageRequest mock_prepare_local_image_request;
-  expect_send(mock_prepare_local_image_request, m_local_image_ctx->id,
-              m_local_image_ctx->name, "remote mirror uuid", 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_prepare_local_image_request, mock_state_builder,
+              m_local_image_ctx->id, m_local_image_ctx->name, 0);
 
   // prepare remote image
   MockPrepareRemoteImageRequest mock_prepare_remote_image_request;
-  ::journal::MockJournaler mock_remote_journaler;
-  cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
-  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
-    m_local_image_ctx->id};
-  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
-  expect_send(mock_prepare_remote_image_request, mock_remote_journaler,
-              "remote mirror uuid", m_remote_image_ctx->id, client_state,
-              mirror_peer_client_meta, 0);
+  expect_send(mock_prepare_remote_image_request, mock_state_builder,
+              "remote mirror uuid", m_remote_image_ctx->id, 0);
+  expect_is_local_primary(mock_state_builder, false);
 
   // open the remote image
-  librbd::MockJournal mock_journal;
   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
   MockOpenImageRequest mock_open_image_request;
   expect_open_image(mock_open_image_request, m_remote_io_ctx,
@@ -852,7 +739,6 @@ TEST_F(TestMockImageReplayerBootstrapRequest, OpenLocalImagePrimary) {
 
   // open the local image
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
-  mock_local_image_ctx.journal = &mock_journal;
   MockOpenLocalImageRequest mock_open_local_image_request;
   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
                           mock_local_image_ctx.id, &mock_local_image_ctx,
@@ -877,20 +763,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, CreateLocalImageError) {
 
   // prepare local image
   MockPrepareLocalImageRequest mock_prepare_local_image_request;
-  expect_send(mock_prepare_local_image_request, "", "", "", 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_prepare_local_image_request, mock_state_builder, "", "",
+              -ENOENT);
 
   // prepare remote image
   MockPrepareRemoteImageRequest mock_prepare_remote_image_request;
-  ::journal::MockJournaler mock_remote_journaler;
-  cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
-  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
-  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
-  expect_send(mock_prepare_remote_image_request, mock_remote_journaler,
-              "remote mirror uuid", m_remote_image_ctx->id, client_state,
-              mirror_peer_client_meta, 0);
+  expect_send(mock_prepare_remote_image_request, mock_state_builder,
+              "remote mirror uuid", m_remote_image_ctx->id, 0);
+  expect_is_local_primary(mock_state_builder, false);
 
   // open the remote image
-  librbd::MockJournal mock_journal;
   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
   MockOpenImageRequest mock_open_image_request;
   expect_open_image(mock_open_image_request, m_remote_io_ctx,
@@ -904,9 +787,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, CreateLocalImageError) {
                                 librbd::mirror::PROMOTION_STATE_PRIMARY, 0);
 
   // create local image
-  MockCreateLocalImageRequest mock_create_local_image_request;
-  expect_create_local_image(mock_create_local_image_request, "local image id",
-                            -EINVAL);
+  expect_create_local_image(mock_state_builder, "local image id", -EINVAL);
 
   // close remote image
   MockCloseImageRequest mock_close_image_request;
@@ -927,22 +808,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplayError) {
 
   // prepare local image
   MockPrepareLocalImageRequest mock_prepare_local_image_request;
-  expect_send(mock_prepare_local_image_request, m_local_image_ctx->id,
-              m_local_image_ctx->name, "remote mirror uuid", 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_prepare_local_image_request, mock_state_builder,
+              m_local_image_ctx->id, m_local_image_ctx->name, 0);
 
   // prepare remote image
   MockPrepareRemoteImageRequest mock_prepare_remote_image_request;
-  ::journal::MockJournaler mock_remote_journaler;
-  cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
-  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
-    m_local_image_ctx->id};
-  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
-  expect_send(mock_prepare_remote_image_request, mock_remote_journaler,
-              "remote mirror uuid", m_remote_image_ctx->id, client_state,
-              mirror_peer_client_meta, 0);
+  expect_send(mock_prepare_remote_image_request, mock_state_builder,
+              "remote mirror uuid", m_remote_image_ctx->id, 0);
+  expect_is_local_primary(mock_state_builder, false);
 
   // open the remote image
-  librbd::MockJournal mock_journal;
   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
   MockOpenImageRequest mock_open_image_request;
   expect_open_image(mock_open_image_request, m_remote_io_ctx,
@@ -957,20 +833,15 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplayError) {
 
   // open the local image
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
-  mock_local_image_ctx.journal = &mock_journal;
   MockOpenLocalImageRequest mock_open_local_image_request;
   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
                           mock_local_image_ctx.id, &mock_local_image_ctx, 0);
 
   // prepare replay
-  MockPrepareReplayRequest mock_prepare_replay_request;
-  expect_prepare_replay(mock_prepare_replay_request, false, false, -EINVAL);
-
-  // close local image
-  MockCloseImageRequest mock_close_image_request;
-  expect_close_image(mock_close_image_request, mock_local_image_ctx, 0);
+  expect_prepare_replay(mock_state_builder, false, false, -EINVAL);
 
   // close remote image
+  MockCloseImageRequest mock_close_image_request;
   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
 
   C_SaferCond ctx;
@@ -988,22 +859,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplayResyncRequested) {
 
   // prepare local image
   MockPrepareLocalImageRequest mock_prepare_local_image_request;
-  expect_send(mock_prepare_local_image_request, m_local_image_ctx->id,
-              m_local_image_ctx->name, "remote mirror uuid", 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_prepare_local_image_request, mock_state_builder,
+              m_local_image_ctx->id, m_local_image_ctx->name, 0);
 
   // prepare remote image
   MockPrepareRemoteImageRequest mock_prepare_remote_image_request;
-  ::journal::MockJournaler mock_remote_journaler;
-  cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
-  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
-    m_local_image_ctx->id};
-  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
-  expect_send(mock_prepare_remote_image_request, mock_remote_journaler,
-              "remote mirror uuid", m_remote_image_ctx->id, client_state,
-              mirror_peer_client_meta, 0);
+  expect_send(mock_prepare_remote_image_request, mock_state_builder,
+              "remote mirror uuid", m_remote_image_ctx->id, 0);
+  expect_is_local_primary(mock_state_builder, false);
 
   // open the remote image
-  librbd::MockJournal mock_journal;
   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
   MockOpenImageRequest mock_open_image_request;
   expect_open_image(mock_open_image_request, m_remote_io_ctx,
@@ -1018,14 +884,12 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplayResyncRequested) {
 
   // open the local image
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
-  mock_local_image_ctx.journal = &mock_journal;
   MockOpenLocalImageRequest mock_open_local_image_request;
   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
                           mock_local_image_ctx.id, &mock_local_image_ctx, 0);
 
   // prepare replay
-  MockPrepareReplayRequest mock_prepare_replay_request;
-  expect_prepare_replay(mock_prepare_replay_request, true, false, 0);
+  expect_prepare_replay(mock_state_builder, true, false, 0);
 
   // close remote image
   MockCloseImageRequest mock_close_image_request;
@@ -1047,22 +911,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplaySyncing) {
 
   // prepare local image
   MockPrepareLocalImageRequest mock_prepare_local_image_request;
-  expect_send(mock_prepare_local_image_request, m_local_image_ctx->id,
-              m_local_image_ctx->name, "remote mirror uuid", 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_prepare_local_image_request, mock_state_builder,
+              m_local_image_ctx->id, m_local_image_ctx->name, 0);
 
   // prepare remote image
   MockPrepareRemoteImageRequest mock_prepare_remote_image_request;
-  ::journal::MockJournaler mock_remote_journaler;
-  cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
-  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
-    m_local_image_ctx->id};
-  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
-  expect_send(mock_prepare_remote_image_request, mock_remote_journaler,
-              "remote mirror uuid", m_remote_image_ctx->id, client_state,
-              mirror_peer_client_meta, 0);
+  expect_send(mock_prepare_remote_image_request, mock_state_builder,
+              "remote mirror uuid", m_remote_image_ctx->id, 0);
+  expect_is_local_primary(mock_state_builder, false);
 
   // open the remote image
-  librbd::MockJournal mock_journal;
   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
   MockOpenImageRequest mock_open_image_request;
   expect_open_image(mock_open_image_request, m_remote_io_ctx,
@@ -1077,17 +936,15 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplaySyncing) {
 
   // open the local image
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
-  mock_local_image_ctx.journal = &mock_journal;
   MockOpenLocalImageRequest mock_open_local_image_request;
   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
                           mock_local_image_ctx.id, &mock_local_image_ctx, 0);
 
   // prepare replay
-  MockPrepareReplayRequest mock_prepare_replay_request;
-  expect_prepare_replay(mock_prepare_replay_request, false, true, 0);
+  expect_prepare_replay(mock_state_builder, false, true, 0);
+  expect_is_disconnected(mock_state_builder, false);
 
   // image sync
-  MockStateBuilder mock_state_builder;
   MockImageSync mock_image_sync;
   expect_image_sync(mock_image_sync, 0);
 
@@ -1110,22 +967,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplayDisconnected) {
 
   // prepare local image
   MockPrepareLocalImageRequest mock_prepare_local_image_request;
-  expect_send(mock_prepare_local_image_request, m_local_image_ctx->id,
-              m_local_image_ctx->name, "remote mirror uuid", 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_prepare_local_image_request, mock_state_builder,
+              m_local_image_ctx->id, m_local_image_ctx->name, 0);
 
   // prepare remote image
   MockPrepareRemoteImageRequest mock_prepare_remote_image_request;
-  ::journal::MockJournaler mock_remote_journaler;
-  cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
-  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
-    m_local_image_ctx->id};
-  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
-  expect_send(mock_prepare_remote_image_request, mock_remote_journaler,
-              "remote mirror uuid", m_remote_image_ctx->id, client_state,
-              mirror_peer_client_meta, 0);
+  expect_send(mock_prepare_remote_image_request, mock_state_builder,
+              "remote mirror uuid", m_remote_image_ctx->id, 0);
+  expect_is_local_primary(mock_state_builder, false);
 
   // open the remote image
-  librbd::MockJournal mock_journal;
   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
   MockOpenImageRequest mock_open_image_request;
   expect_open_image(mock_open_image_request, m_remote_io_ctx,
@@ -1140,14 +992,13 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplayDisconnected) {
 
   // open the local image
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
-  mock_local_image_ctx.journal = &mock_journal;
   MockOpenLocalImageRequest mock_open_local_image_request;
   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
                           mock_local_image_ctx.id, &mock_local_image_ctx, 0);
 
   // prepare replay
-  MockPrepareReplayRequest mock_prepare_replay_request;
-  expect_prepare_replay(mock_prepare_replay_request, false, false, 0);
+  expect_prepare_replay(mock_state_builder, false, false, 0);
+  expect_is_disconnected(mock_state_builder, false);
 
   // close remote image
   MockCloseImageRequest mock_close_image_request;
@@ -1168,22 +1019,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, ImageSyncError) {
 
   // prepare local image
   MockPrepareLocalImageRequest mock_prepare_local_image_request;
-  expect_send(mock_prepare_local_image_request, m_local_image_ctx->id,
-              m_local_image_ctx->name, "remote mirror uuid", 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_prepare_local_image_request, mock_state_builder,
+              m_local_image_ctx->id, m_local_image_ctx->name, 0);
 
   // prepare remote image
   MockPrepareRemoteImageRequest mock_prepare_remote_image_request;
-  ::journal::MockJournaler mock_remote_journaler;
-  cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
-  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
-    m_local_image_ctx->id};
-  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
-  expect_send(mock_prepare_remote_image_request, mock_remote_journaler,
-              "remote mirror uuid", m_remote_image_ctx->id, client_state,
-              mirror_peer_client_meta, 0);
+  expect_send(mock_prepare_remote_image_request, mock_state_builder,
+              "remote mirror uuid", m_remote_image_ctx->id, 0);
+  expect_is_local_primary(mock_state_builder, false);
 
   // open the remote image
-  librbd::MockJournal mock_journal;
   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
   MockOpenImageRequest mock_open_image_request;
   expect_open_image(mock_open_image_request, m_remote_io_ctx,
@@ -1198,17 +1044,15 @@ TEST_F(TestMockImageReplayerBootstrapRequest, ImageSyncError) {
 
   // open the local image
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
-  mock_local_image_ctx.journal = &mock_journal;
   MockOpenLocalImageRequest mock_open_local_image_request;
   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
                           mock_local_image_ctx.id, &mock_local_image_ctx, 0);
 
   // prepare replay
-  MockPrepareReplayRequest mock_prepare_replay_request;
-  expect_prepare_replay(mock_prepare_replay_request, false, true, 0);
+  expect_prepare_replay(mock_state_builder, false, true, 0);
+  expect_is_disconnected(mock_state_builder, false);
 
   // image sync
-  MockStateBuilder mock_state_builder;
   MockImageSync mock_image_sync;
   expect_image_sync(mock_image_sync, -EINVAL);
 
@@ -1231,22 +1075,17 @@ TEST_F(TestMockImageReplayerBootstrapRequest, ImageSyncCanceled) {
 
   // prepare local image
   MockPrepareLocalImageRequest mock_prepare_local_image_request;
-  expect_send(mock_prepare_local_image_request, m_local_image_ctx->id,
-              m_local_image_ctx->name, "remote mirror uuid", 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_prepare_local_image_request, mock_state_builder,
+              m_local_image_ctx->id, m_local_image_ctx->name, 0);
 
   // prepare remote image
   MockPrepareRemoteImageRequest mock_prepare_remote_image_request;
-  ::journal::MockJournaler mock_remote_journaler;
-  cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
-  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
-    m_local_image_ctx->id};
-  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
-  expect_send(mock_prepare_remote_image_request, mock_remote_journaler,
-              "remote mirror uuid", m_remote_image_ctx->id, client_state,
-              mirror_peer_client_meta, 0);
+  expect_send(mock_prepare_remote_image_request, mock_state_builder,
+              "remote mirror uuid", m_remote_image_ctx->id, 0);
+  expect_is_local_primary(mock_state_builder, false);
 
   // open the remote image
-  librbd::MockJournal mock_journal;
   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
   MockOpenImageRequest mock_open_image_request;
   expect_open_image(mock_open_image_request, m_remote_io_ctx,
@@ -1261,14 +1100,13 @@ TEST_F(TestMockImageReplayerBootstrapRequest, ImageSyncCanceled) {
 
   // open the local image
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
-  mock_local_image_ctx.journal = &mock_journal;
   MockOpenLocalImageRequest mock_open_local_image_request;
   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
                           mock_local_image_ctx.id, &mock_local_image_ctx, 0);
 
   // prepare replay
-  MockPrepareReplayRequest mock_prepare_replay_request;
-  expect_prepare_replay(mock_prepare_replay_request, false, true, 0);
+  expect_prepare_replay(mock_state_builder, false, true, 0);
+  expect_is_disconnected(mock_state_builder, false);
 
   // close remote image
   MockCloseImageRequest mock_close_image_request;
@@ -1285,88 +1123,22 @@ TEST_F(TestMockImageReplayerBootstrapRequest, ImageSyncCanceled) {
   ASSERT_EQ(-ECANCELED, ctx.wait());
 }
 
-TEST_F(TestMockImageReplayerBootstrapRequest, CloseLocalImageError) {
-  InSequence seq;
-
-  // prepare local image
-  MockPrepareLocalImageRequest mock_prepare_local_image_request;
-  expect_send(mock_prepare_local_image_request, m_local_image_ctx->id,
-              m_local_image_ctx->name, "remote mirror uuid", 0);
-
-  // prepare remote image
-  MockPrepareRemoteImageRequest mock_prepare_remote_image_request;
-  ::journal::MockJournaler mock_remote_journaler;
-  cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
-  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
-    m_local_image_ctx->id};
-  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
-  expect_send(mock_prepare_remote_image_request, mock_remote_journaler,
-              "remote mirror uuid", m_remote_image_ctx->id, client_state,
-              mirror_peer_client_meta, 0);
-
-  // open the remote image
-  librbd::MockJournal mock_journal;
-  librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
-  MockOpenImageRequest mock_open_image_request;
-  expect_open_image(mock_open_image_request, m_remote_io_ctx,
-                    mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
-
-  // test if remote image is primary
-  MockGetMirrorInfoRequest mock_get_mirror_info_request;
-  expect_get_remote_mirror_info(mock_get_mirror_info_request,
-                                {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid",
-                                 cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
-                                librbd::mirror::PROMOTION_STATE_PRIMARY, 0);
-
-  // open the local image
-  librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
-  mock_local_image_ctx.journal = &mock_journal;
-  MockOpenLocalImageRequest mock_open_local_image_request;
-  expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
-                          mock_local_image_ctx.id, &mock_local_image_ctx, 0);
-
-  // prepare replay
-  MockPrepareReplayRequest mock_prepare_replay_request;
-  expect_prepare_replay(mock_prepare_replay_request, false, false, -EREMOTEIO);
-
-  // close local image
-  MockCloseImageRequest mock_close_image_request;
-  expect_close_image(mock_close_image_request, mock_local_image_ctx, -EINVAL);
-
-  // close remote image
-  expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
-
-  C_SaferCond ctx;
-  MockThreads mock_threads(m_threads);
-  MockInstanceWatcher mock_instance_watcher;
-  MockBootstrapRequest *request = create_request(
-    &mock_threads, &mock_instance_watcher, "global image id",
-    "local mirror uuid", &ctx);
-  request->send();
-  ASSERT_EQ(-EREMOTEIO, ctx.wait());
-}
-
 TEST_F(TestMockImageReplayerBootstrapRequest, CloseRemoteImageError) {
   InSequence seq;
 
   // prepare local image
   MockPrepareLocalImageRequest mock_prepare_local_image_request;
-  expect_send(mock_prepare_local_image_request, m_local_image_ctx->id,
-              m_local_image_ctx->name, "remote mirror uuid", 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_prepare_local_image_request, mock_state_builder,
+              m_local_image_ctx->id, m_local_image_ctx->name, 0);
 
   // prepare remote image
   MockPrepareRemoteImageRequest mock_prepare_remote_image_request;
-  ::journal::MockJournaler mock_remote_journaler;
-  cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
-  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
-    m_local_image_ctx->id};
-  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
-  expect_send(mock_prepare_remote_image_request, mock_remote_journaler,
-              "remote mirror uuid", m_remote_image_ctx->id, client_state,
-              mirror_peer_client_meta, 0);
+  expect_send(mock_prepare_remote_image_request, mock_state_builder,
+              "remote mirror uuid", m_remote_image_ctx->id, 0);
+  expect_is_local_primary(mock_state_builder, false);
 
   // open the remote image
-  librbd::MockJournal mock_journal;
   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
   MockOpenImageRequest mock_open_image_request;
   expect_open_image(mock_open_image_request, m_remote_io_ctx,
@@ -1381,14 +1153,13 @@ TEST_F(TestMockImageReplayerBootstrapRequest, CloseRemoteImageError) {
 
   // open the local image
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
-  mock_local_image_ctx.journal = &mock_journal;
   MockOpenLocalImageRequest mock_open_local_image_request;
   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
                           mock_local_image_ctx.id, &mock_local_image_ctx, 0);
 
   // prepare replay
-  MockPrepareReplayRequest mock_prepare_replay_request;
-  expect_prepare_replay(mock_prepare_replay_request, false, false, 0);
+  expect_prepare_replay(mock_state_builder, false, false, 0);
+  expect_is_disconnected(mock_state_builder, false);
 
   MockCloseImageRequest mock_close_image_request;
   expect_close_image(mock_close_image_request, mock_remote_image_ctx, -EINVAL);
index 64843155123efa0c24d9df6b62667630cbab3a45..de3fe6cafb36b7cfbe8ea0208840ccea68ca83e3 100644 (file)
@@ -6,6 +6,8 @@
 #include "librbd/journal/TypeTraits.h"
 #include "tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h"
 #include "tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.h"
+#include "tools/rbd_mirror/image_replayer/StateBuilder.h"
+#include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
 #include "test/journal/mock/MockJournaler.h"
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
 #include "test/librbd/mock/MockImageCtx.h"
@@ -51,8 +53,36 @@ struct GetMirrorImageIdRequest<librbd::MockTestImageCtx> {
   MOCK_METHOD0(send, void());
 };
 
+template<>
+struct StateBuilder<librbd::MockTestImageCtx> {
+  virtual ~StateBuilder() {}
+};
+
 GetMirrorImageIdRequest<librbd::MockTestImageCtx>* GetMirrorImageIdRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
 
+namespace journal {
+
+template<>
+struct StateBuilder<librbd::MockTestImageCtx>
+  : public image_replayer::StateBuilder<librbd::MockTestImageCtx> {
+  static StateBuilder* s_instance;
+
+  std::string local_image_id;
+  std::string local_tag_owner;
+
+  static StateBuilder* create(const std::string&) {
+    ceph_assert(s_instance != nullptr);
+    return s_instance;
+  }
+
+  StateBuilder() {
+    s_instance = this;
+  }
+};
+
+StateBuilder<librbd::MockTestImageCtx>* StateBuilder<librbd::MockTestImageCtx>::s_instance = nullptr;
+
+} // namespace journal
 } // namespace image_replayer
 } // namespace mirror
 } // namespace rbd
@@ -77,6 +107,8 @@ class TestMockImageReplayerPrepareLocalImageRequest : public TestMockFixture {
 public:
   typedef PrepareLocalImageRequest<librbd::MockTestImageCtx> MockPrepareLocalImageRequest;
   typedef GetMirrorImageIdRequest<librbd::MockTestImageCtx> MockGetMirrorImageIdRequest;
+  typedef StateBuilder<librbd::MockTestImageCtx> MockStateBuilder;
+  typedef journal::StateBuilder<librbd::MockTestImageCtx> MockJournalStateBuilder;
 
   void expect_get_mirror_image_id(MockGetMirrorImageIdRequest& mock_get_mirror_image_id_request,
                                   const std::string& image_id, int r) {
@@ -146,23 +178,25 @@ TEST_F(TestMockImageReplayerPrepareLocalImageRequest, Success) {
   librbd::MockJournal mock_journal;
   expect_get_tag_owner(mock_journal, "local image id", "remote mirror uuid", 0);
 
-  std::string local_image_id;
+  MockJournalStateBuilder mock_journal_state_builder;
+  MockStateBuilder* mock_state_builder = nullptr;
   std::string local_image_name;
-  std::string tag_owner;
   C_SaferCond ctx;
   auto req = MockPrepareLocalImageRequest::create(m_local_io_ctx,
                                                   "global image id",
-                                                  &local_image_id,
                                                   &local_image_name,
-                                                  &tag_owner,
+                                                  &mock_state_builder,
                                                   m_threads->work_queue,
                                                   &ctx);
   req->send();
 
   ASSERT_EQ(0, ctx.wait());
-  ASSERT_EQ(std::string("local image id"), local_image_id);
+  ASSERT_TRUE(mock_state_builder != nullptr);
   ASSERT_EQ(std::string("local image name"), local_image_name);
-  ASSERT_EQ(std::string("remote mirror uuid"), tag_owner);
+  ASSERT_EQ(std::string("local image id"),
+            mock_journal_state_builder.local_image_id);
+  ASSERT_EQ(std::string("remote mirror uuid"),
+            mock_journal_state_builder.local_tag_owner);
 }
 
 TEST_F(TestMockImageReplayerPrepareLocalImageRequest, MirrorImageIdError) {
@@ -170,15 +204,14 @@ TEST_F(TestMockImageReplayerPrepareLocalImageRequest, MirrorImageIdError) {
   MockGetMirrorImageIdRequest mock_get_mirror_image_id_request;
   expect_get_mirror_image_id(mock_get_mirror_image_id_request, "", -EINVAL);
 
-  std::string local_image_id;
+  MockJournalStateBuilder mock_journal_state_builder;
+  MockStateBuilder* mock_state_builder = nullptr;
   std::string local_image_name;
-  std::string tag_owner;
   C_SaferCond ctx;
   auto req = MockPrepareLocalImageRequest::create(m_local_io_ctx,
                                                   "global image id",
-                                                  &local_image_id,
                                                   &local_image_name,
-                                                  &tag_owner,
+                                                  &mock_state_builder,
                                                   m_threads->work_queue,
                                                   &ctx);
   req->send();
@@ -193,15 +226,14 @@ TEST_F(TestMockImageReplayerPrepareLocalImageRequest, DirGetNameError) {
                              0);
   expect_dir_get_name(m_local_io_ctx, "", -ENOENT);
 
-  std::string local_image_id;
+  MockJournalStateBuilder mock_journal_state_builder;
+  MockStateBuilder* mock_state_builder = nullptr;
   std::string local_image_name;
-  std::string tag_owner;
   C_SaferCond ctx;
   auto req = MockPrepareLocalImageRequest::create(m_local_io_ctx,
                                                   "global image id",
-                                                  &local_image_id,
                                                   &local_image_name,
-                                                  &tag_owner,
+                                                  &mock_state_builder,
                                                   m_threads->work_queue,
                                                   &ctx);
   req->send();
@@ -220,15 +252,14 @@ TEST_F(TestMockImageReplayerPrepareLocalImageRequest, MirrorImageError) {
                           cls::rbd::MIRROR_IMAGE_STATE_DISABLED,
                           "", -EINVAL);
 
-  std::string local_image_id;
+  MockJournalStateBuilder mock_journal_state_builder;
+  MockStateBuilder* mock_state_builder = nullptr;
   std::string local_image_name;
-  std::string tag_owner;
   C_SaferCond ctx;
   auto req = MockPrepareLocalImageRequest::create(m_local_io_ctx,
                                                   "global image id",
-                                                  &local_image_id,
                                                   &local_image_name,
-                                                  &tag_owner,
+                                                  &mock_state_builder,
                                                   m_threads->work_queue,
                                                   &ctx);
   req->send();
@@ -251,15 +282,14 @@ TEST_F(TestMockImageReplayerPrepareLocalImageRequest, TagOwnerError) {
   expect_get_tag_owner(mock_journal, "local image id", "remote mirror uuid",
                        -ENOENT);
 
-  std::string local_image_id;
+  MockJournalStateBuilder mock_journal_state_builder;
+  MockStateBuilder* mock_state_builder = nullptr;
   std::string local_image_name;
-  std::string tag_owner;
   C_SaferCond ctx;
   auto req = MockPrepareLocalImageRequest::create(m_local_io_ctx,
                                                   "global image id",
-                                                  &local_image_id,
                                                   &local_image_name,
-                                                  &tag_owner,
+                                                  &mock_state_builder,
                                                   m_threads->work_queue,
                                                   &ctx);
   req->send();
index 6755e6f05b2fc148e6a0c7108f7f96ad73c5d844..dd48bef31350f9f7d61e23a0103dccc1442785de 100644 (file)
@@ -7,6 +7,8 @@
 #include "tools/rbd_mirror/Threads.h"
 #include "tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h"
 #include "tools/rbd_mirror/image_replayer/PrepareRemoteImageRequest.h"
+#include "tools/rbd_mirror/image_replayer/StateBuilder.h"
+#include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
 #include "test/journal/mock/MockJournaler.h"
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
 #include "test/librbd/mock/MockImageCtx.h"
@@ -73,8 +75,43 @@ struct GetMirrorImageIdRequest<librbd::MockTestImageCtx> {
   MOCK_METHOD0(send, void());
 };
 
+template<>
+struct StateBuilder<librbd::MockTestImageCtx> {
+  std::string local_image_id;
+  std::string remote_mirror_uuid;
+  std::string remote_image_id;
+
+  virtual ~StateBuilder() {}
+
+  MOCK_CONST_METHOD0(get_mirror_image_mode, cls::rbd::MirrorImageMode());
+};
+
 GetMirrorImageIdRequest<librbd::MockTestImageCtx>* GetMirrorImageIdRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
 
+namespace journal {
+
+template<>
+struct StateBuilder<librbd::MockTestImageCtx>
+  : public image_replayer::StateBuilder<librbd::MockTestImageCtx> {
+  static StateBuilder* s_instance;
+
+  ::journal::MockJournalerProxy* remote_journaler = nullptr;
+  cls::journal::ClientState remote_client_state;
+  librbd::journal::MirrorPeerClientMeta remote_client_meta;
+
+  static StateBuilder* create(const std::string&) {
+    ceph_assert(s_instance != nullptr);
+    return s_instance;
+  }
+
+  StateBuilder() {
+    s_instance = this;
+  }
+};
+
+StateBuilder<librbd::MockTestImageCtx>* StateBuilder<librbd::MockTestImageCtx>::s_instance = nullptr;
+
+} // namespace journal
 } // namespace image_replayer
 } // namespace mirror
 } // namespace rbd
@@ -99,6 +136,14 @@ public:
   typedef Threads<librbd::MockTestImageCtx> MockThreads;
   typedef PrepareRemoteImageRequest<librbd::MockTestImageCtx> MockPrepareRemoteImageRequest;
   typedef GetMirrorImageIdRequest<librbd::MockTestImageCtx> MockGetMirrorImageIdRequest;
+  typedef StateBuilder<librbd::MockTestImageCtx> MockStateBuilder;
+  typedef journal::StateBuilder<librbd::MockTestImageCtx> MockJournalStateBuilder;
+
+  void expect_get_mirror_image_mode(MockStateBuilder& mock_state_builder,
+                                    cls::rbd::MirrorImageMode mirror_image_mode) {
+    EXPECT_CALL(mock_state_builder, get_mirror_image_mode())
+      .WillOnce(Return(mirror_image_mode));
+  }
 
   void expect_get_mirror_image_id(MockGetMirrorImageIdRequest& mock_get_mirror_image_id_request,
                                   const std::string& image_id, int r) {
@@ -122,8 +167,8 @@ public:
                       Return(r)));
   }
 
-  void expect_get_mirror_mode(librados::IoCtx &io_ctx,
-                              cls::rbd::MirrorImageMode mode, int r) {
+  void expect_get_mirror_image(librados::IoCtx &io_ctx,
+                               cls::rbd::MirrorImageMode mode, int r) {
     cls::rbd::MirrorImage mirror_image;
     mirror_image.mode = mode;
 
@@ -165,7 +210,7 @@ public:
 };
 
 TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, Success) {
-  journal::MockJournaler mock_remote_journaler;
+  ::journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
 
   InSequence seq;
@@ -174,8 +219,8 @@ TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, Success) {
   expect_get_mirror_image_id(mock_get_mirror_image_id_request,
                              "remote image id", 0);
 
-  expect_get_mirror_mode(m_remote_io_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
-                         0);
+  expect_get_mirror_image(m_remote_io_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
+                          0);
 
   EXPECT_CALL(mock_remote_journaler, construct());
 
@@ -189,35 +234,32 @@ TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, Success) {
   expect_journaler_get_client(mock_remote_journaler, "local mirror uuid",
                               client, 0);
 
-  std::string remote_mirror_uuid;
-  std::string remote_image_id;
-  journal::MockJournalerProxy *remote_journaler = nullptr;
-  cls::journal::ClientState client_state;
-  librbd::journal::MirrorPeerClientMeta client_meta;
+  MockJournalStateBuilder mock_journal_state_builder;
+  MockStateBuilder* mock_state_builder = nullptr;
   C_SaferCond ctx;
   auto req = MockPrepareRemoteImageRequest::create(&mock_threads,
                                                    m_local_io_ctx,
                                                    m_remote_io_ctx,
                                                    "global image id",
                                                    "local mirror uuid",
-                                                   "local image id",
-                                                   nullptr, &remote_mirror_uuid,
-                                                   &remote_image_id,
-                                                   &remote_journaler,
-                                                   &client_state, &client_meta,
+                                                   nullptr,
+                                                   &mock_state_builder,
                                                    &ctx);
   req->send();
 
   ASSERT_EQ(0, ctx.wait());
-  ASSERT_EQ(std::string("remote mirror uuid"), remote_mirror_uuid);
-  ASSERT_EQ(std::string("remote image id"), remote_image_id);
-  ASSERT_TRUE(remote_journaler != nullptr);
-  ASSERT_EQ(cls::journal::CLIENT_STATE_DISCONNECTED, client_state);
-  delete remote_journaler;
+  ASSERT_TRUE(mock_state_builder != nullptr);
+  ASSERT_EQ(std::string("remote mirror uuid"),
+            mock_journal_state_builder.remote_mirror_uuid);
+  ASSERT_EQ(std::string("remote image id"),
+            mock_journal_state_builder.remote_image_id);
+  ASSERT_TRUE(mock_journal_state_builder.remote_journaler != nullptr);
+  ASSERT_EQ(cls::journal::CLIENT_STATE_DISCONNECTED,
+            mock_journal_state_builder.remote_client_state);
 }
 
 TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, SuccessNotRegistered) {
-  journal::MockJournaler mock_remote_journaler;
+  ::journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
 
   InSequence seq;
@@ -226,8 +268,11 @@ TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, SuccessNotRegistered) {
   expect_get_mirror_image_id(mock_get_mirror_image_id_request,
                              "remote image id", 0);
 
-  expect_get_mirror_mode(m_remote_io_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
-                         0);
+  expect_get_mirror_image(m_remote_io_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
+                          0);
+  MockJournalStateBuilder mock_journal_state_builder;
+  expect_get_mirror_image_mode(mock_journal_state_builder,
+                               cls::rbd::MIRROR_IMAGE_MODE_JOURNAL);
 
   EXPECT_CALL(mock_remote_journaler, construct());
 
@@ -241,66 +286,57 @@ TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, SuccessNotRegistered) {
   librbd::journal::ClientData client_data{mirror_peer_client_meta};
   expect_journaler_register_client(mock_remote_journaler, client_data, 0);
 
-  std::string remote_mirror_uuid;
-  std::string remote_image_id;
-  journal::MockJournalerProxy *remote_journaler = nullptr;
-  cls::journal::ClientState client_state;
-  librbd::journal::MirrorPeerClientMeta client_meta;
+  mock_journal_state_builder.local_image_id = "local image id";
+  MockStateBuilder* mock_state_builder = &mock_journal_state_builder;
   C_SaferCond ctx;
   auto req = MockPrepareRemoteImageRequest::create(&mock_threads,
                                                    m_local_io_ctx,
                                                    m_remote_io_ctx,
                                                    "global image id",
                                                    "local mirror uuid",
-                                                   "local image id",
-                                                   nullptr, &remote_mirror_uuid,
-                                                   &remote_image_id,
-                                                   &remote_journaler,
-                                                   &client_state, &client_meta,
+                                                   nullptr,
+                                                   &mock_state_builder,
                                                    &ctx);
   req->send();
 
   ASSERT_EQ(0, ctx.wait());
-  ASSERT_EQ(std::string("remote mirror uuid"), remote_mirror_uuid);
-  ASSERT_EQ(std::string("remote image id"), remote_image_id);
-  ASSERT_TRUE(remote_journaler != nullptr);
-  ASSERT_EQ(cls::journal::CLIENT_STATE_CONNECTED, client_state);
-  delete remote_journaler;
+  ASSERT_TRUE(mock_state_builder != nullptr);
+  ASSERT_EQ(std::string("remote mirror uuid"),
+            mock_journal_state_builder.remote_mirror_uuid);
+  ASSERT_EQ(std::string("remote image id"),
+            mock_journal_state_builder.remote_image_id);
+  ASSERT_TRUE(mock_journal_state_builder.remote_journaler != nullptr);
+  ASSERT_EQ(cls::journal::CLIENT_STATE_CONNECTED,
+            mock_journal_state_builder.remote_client_state);
 }
 
 TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, MirrorUuidError) {
-  journal::MockJournaler mock_remote_journaler;
+  ::journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
 
   InSequence seq;
   expect_mirror_uuid_get(m_remote_io_ctx, "", -EINVAL);
 
-  std::string remote_mirror_uuid;
-  std::string remote_image_id;
-  journal::MockJournalerProxy *remote_journaler = nullptr;
-  cls::journal::ClientState client_state;
-  librbd::journal::MirrorPeerClientMeta client_meta;
+  MockJournalStateBuilder mock_journal_state_builder;
+  MockStateBuilder* mock_state_builder = nullptr;
   C_SaferCond ctx;
   auto req = MockPrepareRemoteImageRequest::create(&mock_threads,
                                                    m_local_io_ctx,
                                                    m_remote_io_ctx,
                                                    "global image id",
                                                    "local mirror uuid",
-                                                   "", nullptr,
-                                                   &remote_mirror_uuid,
-                                                   &remote_image_id,
-                                                   &remote_journaler,
-                                                   &client_state, &client_meta,
+                                                   nullptr,
+                                                   &mock_state_builder,
                                                    &ctx);
   req->send();
 
   ASSERT_EQ(-EINVAL, ctx.wait());
-  ASSERT_EQ(std::string(""), remote_mirror_uuid);
-  ASSERT_TRUE(remote_journaler == nullptr);
+  ASSERT_EQ(std::string(""), mock_journal_state_builder.remote_mirror_uuid);
+  ASSERT_TRUE(mock_journal_state_builder.remote_journaler == nullptr);
 }
 
 TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, MirrorImageIdError) {
-  journal::MockJournaler mock_remote_journaler;
+  ::journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
 
   InSequence seq;
@@ -308,32 +344,27 @@ TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, MirrorImageIdError) {
   MockGetMirrorImageIdRequest mock_get_mirror_image_id_request;
   expect_get_mirror_image_id(mock_get_mirror_image_id_request, "", -EINVAL);
 
-  std::string remote_mirror_uuid;
-  std::string remote_image_id;
-  journal::MockJournalerProxy *remote_journaler = nullptr;
-  cls::journal::ClientState client_state;
-  librbd::journal::MirrorPeerClientMeta client_meta;
+  MockJournalStateBuilder mock_journal_state_builder;
+  MockStateBuilder* mock_state_builder = &mock_journal_state_builder;
   C_SaferCond ctx;
   auto req = MockPrepareRemoteImageRequest::create(&mock_threads,
                                                    m_local_io_ctx,
                                                    m_remote_io_ctx,
                                                    "global image id",
                                                    "local mirror uuid",
-                                                   "", nullptr,
-                                                   &remote_mirror_uuid,
-                                                   &remote_image_id,
-                                                   &remote_journaler,
-                                                   &client_state, &client_meta,
+                                                   nullptr,
+                                                   &mock_state_builder,
                                                    &ctx);
   req->send();
 
   ASSERT_EQ(-EINVAL, ctx.wait());
-  ASSERT_EQ(std::string("remote mirror uuid"), remote_mirror_uuid);
-  ASSERT_TRUE(remote_journaler == nullptr);
+  ASSERT_EQ(std::string("remote mirror uuid"),
+            mock_journal_state_builder.remote_mirror_uuid);
+  ASSERT_TRUE(mock_journal_state_builder.remote_journaler == nullptr);
 }
 
 TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, MirrorModeError) {
-  journal::MockJournaler mock_remote_journaler;
+  ::journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
 
   InSequence seq;
@@ -342,34 +373,28 @@ TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, MirrorModeError) {
   expect_get_mirror_image_id(mock_get_mirror_image_id_request,
                              "remote image id", 0);
 
-  expect_get_mirror_mode(m_remote_io_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
-                         -EINVAL);
+  expect_get_mirror_image(m_remote_io_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
+                          -EINVAL);
 
-  std::string remote_mirror_uuid;
-  std::string remote_image_id;
-  journal::MockJournalerProxy *remote_journaler = nullptr;
-  cls::journal::ClientState client_state;
-  librbd::journal::MirrorPeerClientMeta client_meta;
+  MockJournalStateBuilder mock_journal_state_builder;
+  MockStateBuilder* mock_state_builder = nullptr;
   C_SaferCond ctx;
   auto req = MockPrepareRemoteImageRequest::create(&mock_threads,
                                                    m_local_io_ctx,
                                                    m_remote_io_ctx,
                                                    "global image id",
                                                    "local mirror uuid",
-                                                   "", nullptr,
-                                                   &remote_mirror_uuid,
-                                                   &remote_image_id,
-                                                   &remote_journaler,
-                                                   &client_state, &client_meta,
+                                                   nullptr,
+                                                   &mock_state_builder,
                                                    &ctx);
   req->send();
 
   ASSERT_EQ(-EINVAL, ctx.wait());
-  ASSERT_TRUE(remote_journaler == nullptr);
+  ASSERT_TRUE(mock_state_builder == nullptr);
 }
 
 TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, GetClientError) {
-  journal::MockJournaler mock_remote_journaler;
+  ::journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
 
   InSequence seq;
@@ -378,8 +403,8 @@ TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, GetClientError) {
   expect_get_mirror_image_id(mock_get_mirror_image_id_request,
                              "remote image id", 0);
 
-  expect_get_mirror_mode(m_remote_io_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
-                         0);
+  expect_get_mirror_image(m_remote_io_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
+                          0);
 
   EXPECT_CALL(mock_remote_journaler, construct());
 
@@ -387,33 +412,25 @@ TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, GetClientError) {
   expect_journaler_get_client(mock_remote_journaler, "local mirror uuid",
                               client, -EINVAL);
 
-  std::string remote_mirror_uuid;
-  std::string remote_image_id;
-  journal::MockJournalerProxy *remote_journaler = nullptr;
-  cls::journal::ClientState client_state;
-  librbd::journal::MirrorPeerClientMeta client_meta;
+  MockJournalStateBuilder mock_journal_state_builder;
+  MockStateBuilder* mock_state_builder = nullptr;
   C_SaferCond ctx;
   auto req = MockPrepareRemoteImageRequest::create(&mock_threads,
                                                    m_local_io_ctx,
                                                    m_remote_io_ctx,
                                                    "global image id",
                                                    "local mirror uuid",
-                                                   "local image id",
-                                                   nullptr, &remote_mirror_uuid,
-                                                   &remote_image_id,
-                                                   &remote_journaler,
-                                                   &client_state, &client_meta,
+                                                   nullptr,
+                                                   &mock_state_builder,
                                                    &ctx);
   req->send();
 
   ASSERT_EQ(-EINVAL, ctx.wait());
-  ASSERT_EQ(std::string("remote mirror uuid"), remote_mirror_uuid);
-  ASSERT_EQ(std::string("remote image id"), remote_image_id);
-  ASSERT_TRUE(remote_journaler == nullptr);
+  ASSERT_TRUE(mock_state_builder == nullptr);
 }
 
 TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, RegisterClientError) {
-  journal::MockJournaler mock_remote_journaler;
+  ::journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
 
   InSequence seq;
@@ -422,8 +439,11 @@ TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, RegisterClientError) {
   expect_get_mirror_image_id(mock_get_mirror_image_id_request,
                              "remote image id", 0);
 
-  expect_get_mirror_mode(m_remote_io_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
-                         0);
+  expect_get_mirror_image(m_remote_io_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
+                          0);
+  MockJournalStateBuilder mock_journal_state_builder;
+  expect_get_mirror_image_mode(mock_journal_state_builder,
+                               cls::rbd::MIRROR_IMAGE_MODE_JOURNAL);
 
   EXPECT_CALL(mock_remote_journaler, construct());
 
@@ -437,29 +457,20 @@ TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, RegisterClientError) {
   librbd::journal::ClientData client_data{mirror_peer_client_meta};
   expect_journaler_register_client(mock_remote_journaler, client_data, -EINVAL);
 
-  std::string remote_mirror_uuid;
-  std::string remote_image_id;
-  journal::MockJournalerProxy *remote_journaler = nullptr;
-  cls::journal::ClientState client_state;
-  librbd::journal::MirrorPeerClientMeta client_meta;
+  mock_journal_state_builder.local_image_id = "local image id";
+  MockStateBuilder* mock_state_builder = &mock_journal_state_builder;
   C_SaferCond ctx;
   auto req = MockPrepareRemoteImageRequest::create(&mock_threads,
                                                    m_local_io_ctx,
                                                    m_remote_io_ctx,
                                                    "global image id",
                                                    "local mirror uuid",
-                                                   "local image id",
-                                                   nullptr, &remote_mirror_uuid,
-                                                   &remote_image_id,
-                                                   &remote_journaler,
-                                                   &client_state, &client_meta,
+                                                   nullptr,
+                                                   &mock_state_builder,
                                                    &ctx);
   req->send();
 
   ASSERT_EQ(-EINVAL, ctx.wait());
-  ASSERT_EQ(std::string("remote mirror uuid"), remote_mirror_uuid);
-  ASSERT_EQ(std::string("remote image id"), remote_image_id);
-  ASSERT_TRUE(remote_journaler == nullptr);
 }
 
 } // namespace image_replayer
diff --git a/src/test/rbd_mirror/mock/MockBaseRequest.h b/src/test/rbd_mirror/mock/MockBaseRequest.h
new file mode 100644 (file)
index 0000000..c85eab4
--- /dev/null
@@ -0,0 +1,26 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_MOCK_BASE_REQUEST_H
+#define CEPH_MOCK_BASE_REQUEST_H
+
+#include "tools/rbd_mirror/BaseRequest.h"
+#include <gmock/gmock.h>
+
+struct Context;
+
+namespace rbd {
+namespace mirror {
+
+struct MockBaseRequest : public BaseRequest {
+  MockBaseRequest() : BaseRequest(nullptr) {}
+
+  Context* on_finish = nullptr;
+
+  MOCK_METHOD0(send, void());
+};
+
+} // namespace mirror
+} // namepace rbd
+
+#endif // CEPH_MOCK_BASE_REQUEST_H
index fb30f3b113b2aaa417b2540b1af5f718b187d9c7..183dca020f0188a5d8b907109a57bb786816e413 100644 (file)
 #include "tools/rbd_mirror/MirrorStatusUpdater.h"
 #include "tools/rbd_mirror/Threads.h"
 #include "tools/rbd_mirror/image_replayer/BootstrapRequest.h"
-#include "tools/rbd_mirror/image_replayer/CloseImageRequest.h"
 #include "tools/rbd_mirror/image_replayer/Replayer.h"
 #include "tools/rbd_mirror/image_replayer/ReplayerListener.h"
+#include "tools/rbd_mirror/image_replayer/StateBuilder.h"
 #include "tools/rbd_mirror/image_replayer/Utils.h"
-#include "tools/rbd_mirror/image_replayer/journal/Replayer.h"
 #include "test/rbd_mirror/test_mock_fixture.h"
-#include "test/journal/mock/MockJournaler.h"
 #include "test/librbd/mock/MockImageCtx.h"
 #include "test/rbd_mirror/mock/MockContextWQ.h"
 #include "test/rbd_mirror/mock/MockSafeTimer.h"
@@ -33,14 +31,6 @@ struct MockTestImageCtx : public MockImageCtx {
 
 } // anonymous namespace
 
-namespace journal {
-
-template <>
-struct TypeTraits<MockTestImageCtx> {
-  typedef ::journal::MockJournalerProxy Journaler;
-};
-
-} // namespace journal
 } // namespace librbd
 
 namespace rbd {
@@ -103,8 +93,8 @@ namespace image_replayer {
 template<>
 struct BootstrapRequest<librbd::MockTestImageCtx> {
   static BootstrapRequest* s_instance;
-  librbd::MockTestImageCtx **image_ctx = nullptr;
-  std::string* local_image_id = nullptr;
+
+  StateBuilder<librbd::MockTestImageCtx>** state_builder = nullptr;
   bool *do_resync = nullptr;
   Context *on_finish = nullptr;
 
@@ -117,15 +107,10 @@ struct BootstrapRequest<librbd::MockTestImageCtx> {
       const std::string &local_mirror_uuid,
       ::journal::CacheManagerHandler *cache_manager_handler,
       rbd::mirror::ProgressContext *progress_ctx,
-      librbd::MockTestImageCtx **local_image_ctx,
-      std::string* local_image_id,
-      std::string* remote_image_id,
-      std::string* remote_mirror_uuid,
-      ::journal::MockJournalerProxy** remote_journaler,
+      StateBuilder<librbd::MockTestImageCtx>** state_builder,
       bool *do_resync, Context *on_finish) {
     ceph_assert(s_instance != nullptr);
-    s_instance->image_ctx = local_image_ctx;
-    s_instance->local_image_id = local_image_id;
+    s_instance->state_builder = state_builder;
     s_instance->do_resync = do_resync;
     s_instance->on_finish = on_finish;
     return s_instance;
@@ -159,61 +144,9 @@ struct BootstrapRequest<librbd::MockTestImageCtx> {
   MOCK_METHOD0(cancel, void());
 };
 
-template<>
-struct CloseImageRequest<librbd::MockTestImageCtx> {
-  static CloseImageRequest* s_instance;
-  librbd::MockTestImageCtx **image_ctx = nullptr;
-  Context *on_finish = nullptr;
-
-  static CloseImageRequest* create(librbd::MockTestImageCtx **image_ctx,
-                                   Context *on_finish) {
-    ceph_assert(s_instance != nullptr);
-    s_instance->image_ctx = image_ctx;
-    s_instance->on_finish = on_finish;
-    return s_instance;
-  }
-
-  CloseImageRequest() {
-    ceph_assert(s_instance == nullptr);
-    s_instance = this;
-  }
-
-  ~CloseImageRequest() {
-    ceph_assert(s_instance == this);
-    s_instance = nullptr;
-  }
-
-  MOCK_METHOD0(send, void());
-};
-
-BootstrapRequest<librbd::MockTestImageCtx>* BootstrapRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
-CloseImageRequest<librbd::MockTestImageCtx>* CloseImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
-
-namespace journal {
-
-template <>
-struct Replayer<librbd::MockTestImageCtx> : public image_replayer::Replayer {
-  static Replayer* s_instance;
-  librbd::MockTestImageCtx** local_image_ctx;
+struct MockReplayer : public Replayer {
   image_replayer::ReplayerListener* replayer_listener;
 
-  static Replayer* create(librbd::MockTestImageCtx** local_image_ctx,
-                          ::journal::MockJournalerProxy* remote_journaler,
-                          const std::string& local_mirror_uuid,
-                          const std::string& remote_mirror_uuid,
-                          image_replayer::ReplayerListener* replayer_listener,
-                          Threads<librbd::MockTestImageCtx>* threads) {
-    ceph_assert(s_instance != nullptr);
-    ceph_assert(local_image_ctx != nullptr);
-    s_instance->local_image_ctx = local_image_ctx;
-    s_instance->replayer_listener = replayer_listener;
-    return s_instance;
-  }
-
-  Replayer() {
-    s_instance = this;
-  }
-
   MOCK_METHOD0(destroy, void());
 
   MOCK_METHOD1(init, void(Context*));
@@ -228,9 +161,30 @@ struct Replayer<librbd::MockTestImageCtx> : public image_replayer::Replayer {
   MOCK_CONST_METHOD0(get_error_description, std::string());
 };
 
-Replayer<librbd::MockTestImageCtx>* Replayer<librbd::MockTestImageCtx>::s_instance = nullptr;
+template <>
+struct StateBuilder<librbd::MockTestImageCtx> {
+  static StateBuilder* s_instance;
+
+  librbd::MockTestImageCtx* local_image_ctx = nullptr;
+  std::string local_image_id;
+  std::string remote_image_id;
+
+  void destroy() {
+  }
+
+  MOCK_METHOD1(close, void(Context*));
+  MOCK_METHOD3(create_replayer, Replayer*(Threads<librbd::MockTestImageCtx>*,
+                                          const std::string&,
+                                          ReplayerListener*));
+
+  StateBuilder() {
+    s_instance = this;
+  }
+};
+
+BootstrapRequest<librbd::MockTestImageCtx>* BootstrapRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+StateBuilder<librbd::MockTestImageCtx>* StateBuilder<librbd::MockTestImageCtx>::s_instance = nullptr;
 
-} // namespace journal
 } // namespace image_replayer
 } // namespace mirror
 } // namespace rbd
@@ -258,8 +212,8 @@ public:
   typedef ImageDeleter<librbd::MockTestImageCtx> MockImageDeleter;
   typedef MirrorStatusUpdater<librbd::MockTestImageCtx> MockMirrorStatusUpdater;
   typedef image_replayer::BootstrapRequest<librbd::MockTestImageCtx> MockBootstrapRequest;
-  typedef image_replayer::CloseImageRequest<librbd::MockTestImageCtx> MockCloseImageRequest;
-  typedef image_replayer::journal::Replayer<librbd::MockTestImageCtx> MockJournalReplayer;
+  typedef image_replayer::StateBuilder<librbd::MockTestImageCtx> MockStateBuilder;
+  typedef image_replayer::MockReplayer MockReplayer;
   typedef ImageReplayer<librbd::MockTestImageCtx> MockImageReplayer;
   typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher;
 
@@ -320,53 +274,66 @@ public:
     return bl;
   }
 
-  void expect_send(MockBootstrapRequest &mock_bootstrap_request,
-                   librbd::MockTestImageCtx &mock_local_image_ctx,
+  void expect_send(MockBootstrapRequest& mock_bootstrap_request,
+                   MockStateBuilder& mock_state_builder,
+                   librbd::MockTestImageCtx& mock_local_image_ctx,
                    bool do_resync, int r) {
     EXPECT_CALL(mock_bootstrap_request, send())
-      .WillOnce(Invoke([&mock_bootstrap_request, &mock_local_image_ctx,
-                        do_resync, r]() {
+      .WillOnce(Invoke([this, &mock_bootstrap_request, &mock_state_builder,
+                        &mock_local_image_ctx, do_resync, r]() {
+            if (r == 0 || r == -ENOLINK) {
+              mock_state_builder.local_image_id = mock_local_image_ctx.id;
+              mock_state_builder.remote_image_id = m_remote_image_ctx->id;
+              *mock_bootstrap_request.state_builder = &mock_state_builder;
+            }
             if (r == 0) {
-              *mock_bootstrap_request.image_ctx = &mock_local_image_ctx;
+              mock_state_builder.local_image_ctx = &mock_local_image_ctx;
               *mock_bootstrap_request.do_resync = do_resync;
-            } else if (r == -ENOLINK) {
-              *mock_bootstrap_request.local_image_id = mock_local_image_ctx.id;
+            }
+            if (r < 0) {
+              mock_state_builder.remote_image_id = "";
             }
             mock_bootstrap_request.on_finish->complete(r);
           }));
   }
 
-  void expect_init(MockJournalReplayer& mock_journal_replayer, int r) {
-    EXPECT_CALL(mock_journal_replayer, init(_))
-      .WillOnce(Invoke([this, &mock_journal_replayer, r](Context* ctx) {
-                  if (r < 0) {
-                    *mock_journal_replayer.local_image_ctx = nullptr;
-                  }
+  void expect_create_replayer(MockStateBuilder& mock_state_builder,
+                              MockReplayer& mock_replayer) {
+    EXPECT_CALL(mock_state_builder, create_replayer(_, _, _))
+      .WillOnce(WithArg<2>(
+        Invoke([this, &mock_replayer]
+               (image_replayer::ReplayerListener* replayer_listener) {
+          mock_replayer.replayer_listener = replayer_listener;
+          return &mock_replayer;
+        })));
+  }
+
+  void expect_close(MockStateBuilder& mock_state_builder, int r) {
+    EXPECT_CALL(mock_state_builder, close(_))
+      .WillOnce(Invoke([this, r](Context* ctx) {
                   m_threads->work_queue->queue(ctx, r);
                 }));
   }
 
-  void expect_shut_down(MockJournalReplayer& mock_journal_replayer, int r) {
-    EXPECT_CALL(mock_journal_replayer, shut_down(_))
-      .WillOnce(Invoke([this, &mock_journal_replayer, r](Context* ctx) {
-                  *mock_journal_replayer.local_image_ctx = nullptr;
+  void expect_init(MockReplayer& mock_replayer, int r) {
+    EXPECT_CALL(mock_replayer, init(_))
+      .WillOnce(Invoke([this, &mock_replayer, r](Context* ctx) {
                   m_threads->work_queue->queue(ctx, r);
                 }));
-    EXPECT_CALL(mock_journal_replayer, destroy());
   }
 
-  void expect_get_replay_status(MockJournalReplayer& mock_journal_replayer) {
-    EXPECT_CALL(mock_journal_replayer, get_replay_status(_, _))
-      .WillRepeatedly(DoAll(WithArg<1>(CompleteContext(-EEXIST)),
-                            Return(true)));
+  void expect_shut_down(MockReplayer& mock_replayer, int r) {
+    EXPECT_CALL(mock_replayer, shut_down(_))
+      .WillOnce(Invoke([this, &mock_replayer, r](Context* ctx) {
+                  m_threads->work_queue->queue(ctx, r);
+                }));
+    EXPECT_CALL(mock_replayer, destroy());
   }
 
-  void expect_send(MockCloseImageRequest &mock_close_image_request, int r) {
-    EXPECT_CALL(mock_close_image_request, send())
-      .WillOnce(Invoke([&mock_close_image_request, r]() {
-            *mock_close_image_request.image_ctx = nullptr;
-            mock_close_image_request.on_finish->complete(r);
-          }));
+  void expect_get_replay_status(MockReplayer& mock_replayer) {
+    EXPECT_CALL(mock_replayer, get_replay_status(_, _))
+      .WillRepeatedly(DoAll(WithArg<1>(CompleteContext(-EEXIST)),
+                            Return(true)));
   }
 
   void expect_set_mirror_image_status_repeatedly() {
@@ -415,21 +382,24 @@ TEST_F(TestMockImageReplayer, StartStop) {
   create_local_image();
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
 
-  journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
   expect_work_queue_repeatedly(mock_threads);
   expect_add_event_after_repeatedly(mock_threads);
 
   MockImageDeleter mock_image_deleter;
-  MockBootstrapRequest mock_bootstrap_request;
-  MockJournalReplayer mock_journal_replayer;
+  MockReplayer mock_replayer;
 
-  expect_get_replay_status(mock_journal_replayer);
+  expect_get_replay_status(mock_replayer);
   expect_set_mirror_image_status_repeatedly();
 
   InSequence seq;
-  expect_send(mock_bootstrap_request, mock_local_image_ctx, false, 0);
-  expect_init(mock_journal_replayer, 0);
+  MockBootstrapRequest mock_bootstrap_request;
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
+              false, 0);
+
+  expect_create_replayer(mock_state_builder, mock_replayer);
+  expect_init(mock_replayer, 0);
 
   create_image_replayer(mock_threads);
 
@@ -440,7 +410,8 @@ TEST_F(TestMockImageReplayer, StartStop) {
             m_image_replayer->get_health_state());
 
   // STOP
-  expect_shut_down(mock_journal_replayer, 0);
+  expect_shut_down(mock_replayer, 0);
+  expect_close(mock_state_builder, 0);
   expect_mirror_image_status_exists(false);
 
   C_SaferCond stop_ctx;
@@ -454,19 +425,20 @@ TEST_F(TestMockImageReplayer, LocalImagePrimary) {
   create_local_image();
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
 
-  journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
   expect_work_queue_repeatedly(mock_threads);
   expect_add_event_after_repeatedly(mock_threads);
 
   MockImageDeleter mock_image_deleter;
+  MockBootstrapRequest mock_bootstrap_request;
 
   expect_set_mirror_image_status_repeatedly();
 
   InSequence seq;
 
-  MockBootstrapRequest mock_bootstrap_request;
-  expect_send(mock_bootstrap_request, mock_local_image_ctx, false, -ENOMSG);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
+              false, -ENOMSG);
 
   expect_mirror_image_status_exists(false);
 
@@ -481,7 +453,6 @@ TEST_F(TestMockImageReplayer, BootstrapRemoteDeleted) {
   create_local_image();
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
 
-  journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
   expect_work_queue_repeatedly(mock_threads);
   expect_add_event_after_repeatedly(mock_threads);
@@ -493,7 +464,11 @@ TEST_F(TestMockImageReplayer, BootstrapRemoteDeleted) {
   InSequence seq;
 
   MockBootstrapRequest mock_bootstrap_request;
-  expect_send(mock_bootstrap_request, mock_local_image_ctx, false, -ENOLINK);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
+              false, -ENOLINK);
+
+  expect_close(mock_state_builder, 0);
 
   expect_trash_move(mock_image_deleter, "global image id", false, 0);
   expect_mirror_image_status_exists(false);
@@ -509,7 +484,6 @@ TEST_F(TestMockImageReplayer, BootstrapResyncRequested) {
   create_local_image();
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
 
-  journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
   expect_work_queue_repeatedly(mock_threads);
   expect_add_event_after_repeatedly(mock_threads);
@@ -521,10 +495,11 @@ TEST_F(TestMockImageReplayer, BootstrapResyncRequested) {
   InSequence seq;
 
   MockBootstrapRequest mock_bootstrap_request;
-  expect_send(mock_bootstrap_request, mock_local_image_ctx, true, 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
+              true, 0);
 
-  MockCloseImageRequest mock_close_image_request;
-  expect_send(mock_close_image_request, 0);
+  expect_close(mock_state_builder, 0);
 
   expect_trash_move(mock_image_deleter, "global image id", true, 0);
   expect_mirror_image_status_exists(false);
@@ -540,7 +515,6 @@ TEST_F(TestMockImageReplayer, BootstrapError) {
   create_local_image();
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
 
-  journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
   expect_work_queue_repeatedly(mock_threads);
   expect_add_event_after_repeatedly(mock_threads);
@@ -551,7 +525,9 @@ TEST_F(TestMockImageReplayer, BootstrapError) {
   expect_set_mirror_image_status_repeatedly();
 
   InSequence seq;
-  expect_send(mock_bootstrap_request, mock_local_image_ctx, false, -EINVAL);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
+              false, -EINVAL);
 
   expect_mirror_image_status_exists(false);
 
@@ -566,7 +542,6 @@ TEST_F(TestMockImageReplayer, BootstrapCancel) {
   create_local_image();
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
 
-  journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
   expect_work_queue_repeatedly(mock_threads);
   expect_add_event_after_repeatedly(mock_threads);
@@ -580,6 +555,7 @@ TEST_F(TestMockImageReplayer, BootstrapCancel) {
   create_image_replayer(mock_threads);
 
   MockBootstrapRequest mock_bootstrap_request;
+  MockStateBuilder mock_state_builder;
   EXPECT_CALL(mock_bootstrap_request, send())
     .WillOnce(Invoke([this, &mock_bootstrap_request]() {
         m_image_replayer->stop();
@@ -600,21 +576,24 @@ TEST_F(TestMockImageReplayer, StopError) {
   create_local_image();
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
 
-  journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
   expect_work_queue_repeatedly(mock_threads);
   expect_add_event_after_repeatedly(mock_threads);
 
   MockImageDeleter mock_image_deleter;
   MockBootstrapRequest mock_bootstrap_request;
-  MockJournalReplayer mock_journal_replayer;
+  MockReplayer mock_replayer;
 
-  expect_get_replay_status(mock_journal_replayer);
+  expect_get_replay_status(mock_replayer);
   expect_set_mirror_image_status_repeatedly();
 
   InSequence seq;
-  expect_send(mock_bootstrap_request, mock_local_image_ctx, false, 0);
-  expect_init(mock_journal_replayer, 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
+              false, 0);
+
+  expect_create_replayer(mock_state_builder, mock_replayer);
+  expect_init(mock_replayer, 0);
 
   create_image_replayer(mock_threads);
 
@@ -624,7 +603,8 @@ TEST_F(TestMockImageReplayer, StopError) {
 
   // STOP (errors are ignored)
 
-  expect_shut_down(mock_journal_replayer, -EINVAL);
+  expect_shut_down(mock_replayer, -EINVAL);
+  expect_close(mock_state_builder, -EINVAL);
   expect_mirror_image_status_exists(false);
 
   C_SaferCond stop_ctx;
@@ -636,23 +616,28 @@ TEST_F(TestMockImageReplayer, ReplayerError) {
   create_local_image();
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
 
-  journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
   expect_work_queue_repeatedly(mock_threads);
   expect_add_event_after_repeatedly(mock_threads);
 
   MockImageDeleter mock_image_deleter;
   MockBootstrapRequest mock_bootstrap_request;
-  MockJournalReplayer mock_journal_replayer;
+  MockReplayer mock_replayer;
 
   expect_set_mirror_image_status_repeatedly();
 
   InSequence seq;
-  expect_send(mock_bootstrap_request, mock_local_image_ctx, false, 0);
-  expect_init(mock_journal_replayer, -EINVAL);
-  EXPECT_CALL(mock_journal_replayer, get_error_description())
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
+              false, 0);
+
+  expect_create_replayer(mock_state_builder, mock_replayer);
+  expect_init(mock_replayer, -EINVAL);
+  EXPECT_CALL(mock_replayer, get_error_description())
     .WillOnce(Return("FAIL"));
-  EXPECT_CALL(mock_journal_replayer, destroy());
+
+  EXPECT_CALL(mock_replayer, destroy());
+  expect_close(mock_state_builder, -EINVAL);
 
   expect_mirror_image_status_exists(false);
   create_image_replayer(mock_threads);
@@ -667,21 +652,24 @@ TEST_F(TestMockImageReplayer, ReplayerResync) {
   create_local_image();
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
 
-  journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
   expect_work_queue_repeatedly(mock_threads);
   expect_add_event_after_repeatedly(mock_threads);
 
   MockImageDeleter mock_image_deleter;
   MockBootstrapRequest mock_bootstrap_request;
-  MockJournalReplayer mock_journal_replayer;
+  MockReplayer mock_replayer;
 
-  expect_get_replay_status(mock_journal_replayer);
+  expect_get_replay_status(mock_replayer);
   expect_set_mirror_image_status_repeatedly();
 
   InSequence seq;
-  expect_send(mock_bootstrap_request, mock_local_image_ctx, false, 0);
-  expect_init(mock_journal_replayer, 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
+              false, 0);
+
+  expect_create_replayer(mock_state_builder, mock_replayer);
+  expect_init(mock_replayer, 0);
 
   create_image_replayer(mock_threads);
 
@@ -690,12 +678,13 @@ TEST_F(TestMockImageReplayer, ReplayerResync) {
   ASSERT_EQ(0, start_ctx.wait());
 
   // NOTIFY
-  EXPECT_CALL(mock_journal_replayer, is_resync_requested())
+  EXPECT_CALL(mock_replayer, is_resync_requested())
     .WillOnce(Return(true));
-  expect_shut_down(mock_journal_replayer, 0);
+  expect_shut_down(mock_replayer, 0);
+  expect_close(mock_state_builder, 0);
   expect_trash_move(mock_image_deleter, "global image id", true, 0);
   expect_mirror_image_status_exists(false);
-  mock_journal_replayer.replayer_listener->handle_notification();
+  mock_replayer.replayer_listener->handle_notification();
   ASSERT_FALSE(m_image_replayer->is_running());
 
   wait_for_stopped();
@@ -706,21 +695,24 @@ TEST_F(TestMockImageReplayer, ReplayerInterrupted) {
   create_local_image();
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
 
-  journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
   expect_work_queue_repeatedly(mock_threads);
   expect_add_event_after_repeatedly(mock_threads);
 
   MockImageDeleter mock_image_deleter;
   MockBootstrapRequest mock_bootstrap_request;
-  MockJournalReplayer mock_journal_replayer;
+  MockReplayer mock_replayer;
 
-  expect_get_replay_status(mock_journal_replayer);
+  expect_get_replay_status(mock_replayer);
   expect_set_mirror_image_status_repeatedly();
 
   InSequence seq;
-  expect_send(mock_bootstrap_request, mock_local_image_ctx, false, 0);
-  expect_init(mock_journal_replayer, 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
+              false, 0);
+
+  expect_create_replayer(mock_state_builder, mock_replayer);
+  expect_init(mock_replayer, 0);
 
   create_image_replayer(mock_threads);
 
@@ -729,17 +721,18 @@ TEST_F(TestMockImageReplayer, ReplayerInterrupted) {
   ASSERT_EQ(0, start_ctx.wait());
 
   // NOTIFY
-  EXPECT_CALL(mock_journal_replayer, is_resync_requested())
+  EXPECT_CALL(mock_replayer, is_resync_requested())
     .WillOnce(Return(false));
-  EXPECT_CALL(mock_journal_replayer, is_replaying())
+  EXPECT_CALL(mock_replayer, is_replaying())
     .WillOnce(Return(false));
-  EXPECT_CALL(mock_journal_replayer, get_error_code())
+  EXPECT_CALL(mock_replayer, get_error_code())
     .WillOnce(Return(-EINVAL));
-  EXPECT_CALL(mock_journal_replayer, get_error_description())
+  EXPECT_CALL(mock_replayer, get_error_description())
     .WillOnce(Return("INVALID"));
-  expect_shut_down(mock_journal_replayer, 0);
+  expect_shut_down(mock_replayer, 0);
+  expect_close(mock_state_builder, 0);
   expect_mirror_image_status_exists(false);
-  mock_journal_replayer.replayer_listener->handle_notification();
+  mock_replayer.replayer_listener->handle_notification();
   ASSERT_FALSE(m_image_replayer->is_running());
 
   wait_for_stopped();
@@ -750,21 +743,24 @@ TEST_F(TestMockImageReplayer, ReplayerRenamed) {
   create_local_image();
   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
 
-  journal::MockJournaler mock_remote_journaler;
   MockThreads mock_threads(m_threads);
   expect_work_queue_repeatedly(mock_threads);
   expect_add_event_after_repeatedly(mock_threads);
 
   MockImageDeleter mock_image_deleter;
   MockBootstrapRequest mock_bootstrap_request;
-  MockJournalReplayer mock_journal_replayer;
+  MockReplayer mock_replayer;
 
-  expect_get_replay_status(mock_journal_replayer);
+  expect_get_replay_status(mock_replayer);
   expect_set_mirror_image_status_repeatedly();
 
   InSequence seq;
-  expect_send(mock_bootstrap_request, mock_local_image_ctx, false, 0);
-  expect_init(mock_journal_replayer, 0);
+  MockStateBuilder mock_state_builder;
+  expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
+              false, 0);
+
+  expect_create_replayer(mock_state_builder, mock_replayer);
+  expect_init(mock_replayer, 0);
 
   create_image_replayer(mock_threads);
 
@@ -773,15 +769,16 @@ TEST_F(TestMockImageReplayer, ReplayerRenamed) {
   ASSERT_EQ(0, start_ctx.wait());
 
   // NOTIFY
-  EXPECT_CALL(mock_journal_replayer, is_resync_requested())
+  EXPECT_CALL(mock_replayer, is_resync_requested())
     .WillOnce(Return(false));
-  EXPECT_CALL(mock_journal_replayer, is_replaying())
+  EXPECT_CALL(mock_replayer, is_replaying())
     .WillOnce(Return(true));
   mock_local_image_ctx.name = "NEW NAME";
-  mock_journal_replayer.replayer_listener->handle_notification();
+  mock_replayer.replayer_listener->handle_notification();
 
   // STOP
-  expect_shut_down(mock_journal_replayer, 0);
+  expect_shut_down(mock_replayer, 0);
+  expect_close(mock_state_builder, 0);
   expect_mirror_image_status_exists(false);
 
   C_SaferCond stop_ctx;
index 766191c040e39bb8f836a4f52a27d00dc466413d..eb030c664fd0a9d0922e7d19a913512333ad112d 100644 (file)
 #include "MirrorStatusUpdater.h"
 #include "Threads.h"
 #include "tools/rbd_mirror/image_replayer/BootstrapRequest.h"
-#include "tools/rbd_mirror/image_replayer/CloseImageRequest.h"
 #include "tools/rbd_mirror/image_replayer/ReplayerListener.h"
+#include "tools/rbd_mirror/image_replayer/StateBuilder.h"
 #include "tools/rbd_mirror/image_replayer/Utils.h"
 #include "tools/rbd_mirror/image_replayer/journal/Replayer.h"
+#include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
 #include <map>
 
 #define dout_context g_ceph_context
@@ -241,7 +242,7 @@ template <typename I>
 ImageReplayer<I>::~ImageReplayer()
 {
   unregister_admin_socket_hook();
-  ceph_assert(m_local_image_ctx == nullptr);
+  ceph_assert(m_state_builder == nullptr);
   ceph_assert(m_on_start_finish == nullptr);
   ceph_assert(m_on_stop_finish == nullptr);
   ceph_assert(m_bootstrap_request == nullptr);
@@ -347,15 +348,13 @@ void ImageReplayer<I>::bootstrap() {
     return;
   }
 
-  m_local_image_id = "";
+  ceph_assert(m_state_builder == nullptr);
   auto ctx = create_context_callback<
       ImageReplayer, &ImageReplayer<I>::handle_bootstrap>(this);
   auto request = image_replayer::BootstrapRequest<I>::create(
       m_threads, m_local_io_ctx, m_remote_image.io_ctx, m_instance_watcher,
       m_global_image_id, m_local_mirror_uuid, m_cache_manager_handler,
-      &m_progress_cxt, &m_local_image_ctx, &m_local_image_id,
-      &m_remote_image.image_id, &m_remote_image.mirror_uuid,
-      &m_remote_journaler, &m_resync_requested, ctx);
+      &m_progress_cxt, &m_state_builder, &m_resync_requested, ctx);
 
   request->get();
   m_bootstrap_request = request;
@@ -372,9 +371,6 @@ void ImageReplayer<I>::handle_bootstrap(int r) {
     std::lock_guard locker{m_lock};
     m_bootstrap_request->put();
     m_bootstrap_request = nullptr;
-    if (m_local_image_ctx) {
-      m_local_image_id = m_local_image_ctx->id;
-    }
   }
 
   if (on_start_interrupted()) {
@@ -409,12 +405,10 @@ template <typename I>
 void ImageReplayer<I>::start_replay() {
   dout(10) << dendl;
 
-  // TODO support journal + snapshot replay
   std::unique_lock locker{m_lock};
   ceph_assert(m_replayer == nullptr);
-  m_replayer = image_replayer::journal::Replayer<I>::create(
-    &m_local_image_ctx, m_remote_journaler, m_local_mirror_uuid,
-    m_remote_image.mirror_uuid, m_replayer_listener, m_threads);
+  m_replayer = m_state_builder->create_replayer(m_threads, m_local_mirror_uuid,
+                                                m_replayer_listener);
 
   auto ctx = create_context_callback<
     ImageReplayer<I>, &ImageReplayer<I>::handle_start_replay>(this);
@@ -438,8 +432,7 @@ void ImageReplayer<I>::handle_start_replay(int r) {
     m_replayer->destroy();
     m_replayer = nullptr;
 
-    derr << "error starting external replay on local image "
-        <<  m_local_image_id << ": " << cpp_strerror(r) << dendl;
+    derr << "error starting replay: " << cpp_strerror(r) << dendl;
     on_start_fail(r, error_description);
     return;
   }
@@ -694,7 +687,7 @@ void ImageReplayer<I>::set_mirror_image_status_update(
     state_desc = m_state_desc;
     mirror_image_status_state = m_mirror_image_status_state;
     last_r = m_last_r;
-    stopping_replay = (m_local_image_ctx != nullptr);
+    stopping_replay = (m_replayer != nullptr);
 
     if (m_bootstrap_request != nullptr) {
       bootstrap_request = m_bootstrap_request;
@@ -823,31 +816,10 @@ void ImageReplayer<I>::shut_down(int r) {
       handle_shut_down(r);
     });
 
-  // destruct the remote journaler created in prepare remote
-  if (m_remote_journaler != nullptr) {
-    ctx = new LambdaContext([this, ctx](int r) {
-      delete m_remote_journaler;
-      m_remote_journaler = nullptr;
-      ctx->complete(0);
-    });
-  }
-
-  // close the local image (if we aborted after a successful bootstrap)
-  if (m_local_image_ctx != nullptr) {
-    ctx = new LambdaContext([this, ctx](int r) {
-      ceph_assert(m_local_image_ctx == nullptr);
-      ctx->complete(0);
-    });
+  // destruct the state builder
+  if (m_state_builder != nullptr) {
     ctx = new LambdaContext([this, ctx](int r) {
-      if (m_local_image_ctx == nullptr) {
-        // never opened or closed via the replayer shutdown
-        ctx->complete(0);
-        return;
-      }
-
-      auto request = image_replayer::CloseImageRequest<I>::create(
-        &m_local_image_ctx, ctx);
-      request->send();
+      m_state_builder->close(ctx);
     });
   }
 
@@ -874,18 +846,19 @@ void ImageReplayer<I>::handle_shut_down(int r) {
   {
     std::lock_guard locker{m_lock};
 
-    if (m_delete_requested && !m_local_image_id.empty()) {
-      ceph_assert(m_remote_image.image_id.empty());
+    if (m_delete_requested && m_state_builder != nullptr &&
+        !m_state_builder->local_image_id.empty()) {
+      ceph_assert(m_state_builder->remote_image_id.empty());
       dout(0) << "remote image no longer exists: scheduling deletion" << dendl;
       unregister_asok_hook = true;
       std::swap(delete_requested, m_delete_requested);
     }
 
     std::swap(resync_requested, m_resync_requested);
-    if (delete_requested || resync_requested) {
-      m_local_image_id = "";
-    } else if (m_last_r == -ENOENT &&
-               m_local_image_id.empty() && m_remote_image.image_id.empty()) {
+    if (!delete_requested && !resync_requested && m_last_r == -ENOENT &&
+        ((m_state_builder == nullptr) ||
+         (m_state_builder->local_image_id.empty() &&
+          m_state_builder->remote_image_id.empty()))) {
       dout(0) << "mirror image no longer exists" << dendl;
       unregister_asok_hook = true;
       m_finished = true;
@@ -934,6 +907,11 @@ void ImageReplayer<I>::handle_shut_down(int r) {
     return;
   }
 
+  if (m_state_builder != nullptr) {
+    m_state_builder->destroy();
+    m_state_builder = nullptr;
+  }
+
   dout(10) << "stop complete" << dendl;
   Context *on_start = nullptr;
   Context *on_stop = nullptr;
@@ -969,12 +947,13 @@ void ImageReplayer<I>::handle_replayer_notification() {
 
   {
     // detect a rename of the local image
-    ceph_assert(m_local_image_ctx != nullptr);
-    std::shared_lock image_locker{m_local_image_ctx->image_lock};
-    if (m_local_image_name != m_local_image_ctx->name) {
+    ceph_assert(m_state_builder != nullptr &&
+                m_state_builder->local_image_ctx != nullptr);
+    std::shared_lock image_locker{m_state_builder->local_image_ctx->image_lock};
+    if (m_local_image_name != m_state_builder->local_image_ctx->name) {
       // will re-register with new name after next status update
       dout(10) << "image renamed" << dendl;
-      m_local_image_name = m_local_image_ctx->name;
+      m_local_image_name = m_state_builder->local_image_ctx->name;
     }
   }
 
index 3ac9d16548d4a5d745c583772593edd0b3bb0ecb..9b94d3d7f375e06b48824052b4bf7a52638927af 100644 (file)
@@ -6,13 +6,8 @@
 
 #include "common/AsyncOpTracker.h"
 #include "common/ceph_mutex.h"
-#include "common/WorkQueue.h"
 #include "include/rados/librados.hpp"
-#include "cls/journal/cls_journal_types.h"
 #include "cls/rbd/cls_rbd_types.h"
-#include "librbd/ImageCtx.h"
-#include "librbd/journal/Types.h"
-#include "librbd/journal/TypeTraits.h"
 #include "ProgressContext.h"
 #include "tools/rbd_mirror/Types.h"
 #include "tools/rbd_mirror/image_replayer/Types.h"
 
 class AdminSocketHook;
 
-namespace journal {
-
-struct CacheManagerHandler;
-class Journaler;
-
-} // namespace journal
-
-namespace librbd {
-
-class ImageCtx;
-
-} // namespace librbd
+namespace journal { struct CacheManagerHandler; }
+namespace librbd { class ImageCtx; }
 
 namespace rbd {
 namespace mirror {
@@ -45,6 +30,7 @@ namespace image_replayer {
 
 class Replayer;
 template <typename> class BootstrapRequest;
+template <typename> class StateBuilder;
 
 } // namespace image_replayer
 
@@ -171,8 +157,6 @@ private:
   };
 
   struct RemoteImage {
-    std::string mirror_uuid;
-    std::string image_id;
     librados::IoCtx io_ctx;
     MirrorStatusUpdater<ImageCtxT>* mirror_status_updater = nullptr;
 
@@ -184,7 +168,6 @@ private:
   };
   struct ReplayerListener;
 
-  typedef typename librbd::journal::TypeTraits<ImageCtxT>::Journaler Journaler;
   typedef boost::optional<State> OptionalState;
   typedef boost::optional<cls::rbd::MirrorImageStatusState>
       OptionalMirrorImageStatusState;
@@ -213,7 +196,6 @@ private:
   Peers m_peers;
   RemoteImage m_remote_image;
 
-  std::string m_local_image_id;
   std::string m_local_image_name;
   std::string m_image_spec;
 
@@ -231,11 +213,7 @@ private:
   bool m_delete_requested = false;
   bool m_resync_requested = false;
 
-  ImageCtxT *m_local_image_ctx = nullptr;
-
-  decltype(ImageCtxT::journal) m_local_journal = nullptr;
-  Journaler* m_remote_journaler = nullptr;
-
+  image_replayer::StateBuilder<ImageCtxT>* m_state_builder = nullptr;
   image_replayer::Replayer* m_replayer = nullptr;
   ReplayerListener* m_replayer_listener = nullptr;
 
index 5e6fc66366d5b16b6634fb165bf383ae947c2453..ebf38eff17402be5e09143da9f237819e9725555 100644 (file)
@@ -6,6 +6,7 @@
 #include "common/Timer.h"
 #include "common/debug.h"
 #include "common/errno.h"
+#include "common/WorkQueue.h"
 #include "librbd/Utils.h"
 #include "ImageReplayer.h"
 #include "InstanceReplayer.h"
index 6ebff843131eb6b2bd38a2dacf1cc0962349c087..9a8c0966989806b5a66b87a0734cd1fb89415b18 100644 (file)
 #include "librbd/Utils.h"
 #include "librbd/journal/Types.h"
 #include "librbd/mirror/GetInfoRequest.h"
-#include "tools/rbd_mirror/ProgressContext.h"
+#include "tools/rbd_mirror/BaseRequest.h"
 #include "tools/rbd_mirror/ImageSync.h"
+#include "tools/rbd_mirror/ProgressContext.h"
 #include "tools/rbd_mirror/Threads.h"
 #include "tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.h"
 #include "tools/rbd_mirror/image_replayer/PrepareRemoteImageRequest.h"
-#include "tools/rbd_mirror/image_replayer/journal/CreateLocalImageRequest.h"
-#include "tools/rbd_mirror/image_replayer/journal/PrepareReplayRequest.h"
 #include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
 #include "tools/rbd_mirror/image_replayer/journal/SyncPointHandler.h"
 
@@ -55,11 +54,7 @@ BootstrapRequest<I>::BootstrapRequest(
     const std::string& local_mirror_uuid,
     ::journal::CacheManagerHandler* cache_manager_handler,
     ProgressContext* progress_ctx,
-    I** local_image_ctx,
-    std::string* local_image_id,
-    std::string* remote_image_id,
-    std::string* remote_mirror_uuid,
-    Journaler** remote_journaler,
+    StateBuilder<I>** state_builder,
     bool* do_resync,
     Context* on_finish)
   : CancelableRequest("rbd::mirror::image_replayer::BootstrapRequest",
@@ -73,11 +68,7 @@ BootstrapRequest<I>::BootstrapRequest(
     m_local_mirror_uuid(local_mirror_uuid),
     m_cache_manager_handler(cache_manager_handler),
     m_progress_ctx(progress_ctx),
-    m_local_image_ctx(local_image_ctx),
-    m_local_image_id(local_image_id),
-    m_remote_image_id(remote_image_id),
-    m_remote_mirror_uuid(remote_mirror_uuid),
-    m_remote_journaler(remote_journaler),
+    m_state_builder(state_builder),
     m_do_resync(do_resync),
     m_lock(ceph::make_mutex(unique_lock_name("BootstrapRequest::m_lock",
                                              this))) {
@@ -125,14 +116,13 @@ void BootstrapRequest<I>::prepare_local_image() {
   dout(10) << dendl;
   update_progress("PREPARE_LOCAL_IMAGE");
 
-  *m_local_image_id = "";
+  ceph_assert(*m_state_builder == nullptr);
   m_local_image_name = m_global_image_id;
   auto ctx = create_context_callback<
     BootstrapRequest, &BootstrapRequest<I>::handle_prepare_local_image>(this);
   auto req = image_replayer::PrepareLocalImageRequest<I>::create(
-    m_local_io_ctx, m_global_image_id, m_local_image_id,
-    &m_prepare_local_image_name, &m_local_image_tag_owner,
-    m_threads->work_queue, ctx);
+    m_local_io_ctx, m_global_image_id, &m_prepare_local_image_name,
+    m_state_builder, m_threads->work_queue, ctx);
   req->send();
 }
 
@@ -140,6 +130,7 @@ template <typename I>
 void BootstrapRequest<I>::handle_prepare_local_image(int r) {
   dout(10) << "r=" << r << dendl;
 
+  ceph_assert(r < 0 || *m_state_builder != nullptr);
   if (r == -ENOENT) {
     dout(10) << "local image does not exist" << dendl;
   } else if (r < 0) {
@@ -164,15 +155,11 @@ void BootstrapRequest<I>::prepare_remote_image() {
   dout(10) << dendl;
   update_progress("PREPARE_REMOTE_IMAGE");
 
-  ceph_assert(*m_remote_journaler == nullptr);
-
   Context *ctx = create_context_callback<
     BootstrapRequest, &BootstrapRequest<I>::handle_prepare_remote_image>(this);
   auto req = image_replayer::PrepareRemoteImageRequest<I>::create(
     m_threads, m_local_io_ctx, m_remote_io_ctx, m_global_image_id,
-    m_local_mirror_uuid, *m_local_image_id, m_cache_manager_handler,
-    m_remote_mirror_uuid, m_remote_image_id, m_remote_journaler,
-    &m_client_state, &m_client_meta, ctx);
+    m_local_mirror_uuid, m_cache_manager_handler, m_state_builder, ctx);
   req->send();
 }
 
@@ -180,22 +167,23 @@ template <typename I>
 void BootstrapRequest<I>::handle_prepare_remote_image(int r) {
   dout(10) << "r=" << r << dendl;
 
-  ceph_assert(r < 0 ? *m_remote_journaler == nullptr :
-                      *m_remote_journaler != nullptr);
-  if (r < 0 && !m_local_image_id->empty() &&
-      m_local_image_tag_owner == librbd::Journal<>::LOCAL_MIRROR_UUID) {
-    // local image is primary -- fall-through
-  } else if (r == -ENOENT) {
+  auto state_builder = *m_state_builder;
+  if (state_builder != nullptr && state_builder->is_local_primary()) {
+    dout(5) << "local image is primary" << dendl;
+    finish(-ENOMSG);
+    return;
+  } else if (r == -ENOENT || state_builder == nullptr) {
     dout(10) << "remote image does not exist" << dendl;
 
     // TODO need to support multiple remote images
-    if (m_remote_image_id->empty() && !m_local_image_id->empty() &&
-        m_local_image_tag_owner == *m_remote_mirror_uuid) {
+    if (state_builder != nullptr &&
+        state_builder->remote_image_id.empty() &&
+        !state_builder->local_image_id.empty() &&
+        state_builder->is_linked()) {
       // local image exists and is non-primary and linked to the missing
       // remote image
       finish(-ENOLINK);
     } else {
-      dout(10) << "remote image does not exist" << dendl;
       finish(-ENOENT);
     }
     return;
@@ -205,19 +193,14 @@ void BootstrapRequest<I>::handle_prepare_remote_image(int r) {
     return;
   }
 
-  if (!m_local_image_id->empty() &&
-      m_local_image_tag_owner == librbd::Journal<>::LOCAL_MIRROR_UUID) {
-    dout(5) << "local image is primary" << dendl;
-    finish(-ENOMSG);
-    return;
-  }
-
   open_remote_image();
 }
 
 template <typename I>
 void BootstrapRequest<I>::open_remote_image() {
-  dout(15) << "remote_image_id=" << *m_remote_image_id << dendl;
+  ceph_assert(*m_state_builder != nullptr);
+  auto remote_image_id = (*m_state_builder)->remote_image_id;
+  dout(15) << "remote_image_id=" << remote_image_id << dendl;
 
   update_progress("OPEN_REMOTE_IMAGE");
 
@@ -225,7 +208,7 @@ void BootstrapRequest<I>::open_remote_image() {
     BootstrapRequest<I>, &BootstrapRequest<I>::handle_open_remote_image>(
       this);
   OpenImageRequest<I> *request = OpenImageRequest<I>::create(
-    m_remote_io_ctx, &m_remote_image_ctx, *m_remote_image_id, false,
+    m_remote_io_ctx, &m_remote_image_ctx, remote_image_id, false,
     ctx);
   request->send();
 }
@@ -290,23 +273,18 @@ void BootstrapRequest<I>::handle_get_remote_mirror_info(int r) {
     return;
   }
 
+  ceph_assert(*m_state_builder != nullptr);
   if (m_promotion_state != librbd::mirror::PROMOTION_STATE_PRIMARY &&
-      m_local_image_id->empty()) {
+      (*m_state_builder)->local_image_id.empty()) {
     // no local image and remote isn't primary -- don't sync it
-    dout(5) << "remote image is not primary -- not syncing"
-            << dendl;
+    dout(5) << "remote image is not primary -- not syncing" << dendl;
     m_ret_val = -EREMOTEIO;
     close_remote_image();
     return;
   }
 
-  if (!m_client_meta.image_id.empty()) {
-    // have an image id -- use that to open the image since a deletion (resync)
-    // will leave the old image id registered in the peer
-    *m_local_image_id = m_client_meta.image_id;
-  }
 
-  if (m_local_image_id->empty()) {
+  if ((*m_state_builder)->local_image_id.empty()) {
     create_local_image();
     return;
   }
@@ -316,7 +294,10 @@ void BootstrapRequest<I>::handle_get_remote_mirror_info(int r) {
 
 template <typename I>
 void BootstrapRequest<I>::open_local_image() {
-  dout(15) << "local_image_id=" << *m_local_image_id << dendl;
+  ceph_assert(*m_state_builder != nullptr);
+  auto local_image_id = (*m_state_builder)->local_image_id;
+
+  dout(15) << "local_image_id=" << local_image_id << dendl;
 
   update_progress("OPEN_LOCAL_IMAGE");
 
@@ -324,8 +305,8 @@ void BootstrapRequest<I>::open_local_image() {
     BootstrapRequest<I>, &BootstrapRequest<I>::handle_open_local_image>(
       this);
   OpenLocalImageRequest<I> *request = OpenLocalImageRequest<I>::create(
-    m_local_io_ctx, m_local_image_ctx, *m_local_image_id, m_threads->work_queue,
-    ctx);
+    m_local_io_ctx, &(*m_state_builder)->local_image_ctx, local_image_id,
+    m_threads->work_queue, ctx);
   request->send();
 }
 
@@ -333,19 +314,21 @@ template <typename I>
 void BootstrapRequest<I>::handle_open_local_image(int r) {
   dout(15) << "r=" << r << dendl;
 
+  ceph_assert(*m_state_builder != nullptr);
+  auto local_image_ctx = (*m_state_builder)->local_image_ctx;
+  ceph_assert((r >= 0 && local_image_ctx != nullptr) ||
+              (r < 0 && local_image_ctx == nullptr));
+
   if (r == -ENOENT) {
-    ceph_assert(*m_local_image_ctx == nullptr);
     dout(10) << "local image missing" << dendl;
     create_local_image();
     return;
   } else if (r == -EREMOTEIO) {
-    ceph_assert(*m_local_image_ctx == nullptr);
     dout(10) << "local image is primary -- skipping image replay" << dendl;
     m_ret_val = r;
     close_remote_image();
     return;
   } else if (r < 0) {
-    ceph_assert(*m_local_image_ctx == nullptr);
     derr << "failed to open local image: " << cpp_strerror(r) << dendl;
     m_ret_val = r;
     close_remote_image();
@@ -360,14 +343,12 @@ void BootstrapRequest<I>::prepare_replay() {
   dout(10) << dendl;
   update_progress("PREPARE_REPLAY");
 
-  // TODO support snapshot-based mirroring
+  ceph_assert(*m_state_builder != nullptr);
   auto ctx = create_context_callback<
-    BootstrapRequest<I>,
-    &BootstrapRequest<I>::handle_prepare_replay>(this);
-  auto request = journal::PrepareReplayRequest<I>::create(
-    *m_local_image_ctx, *m_remote_journaler, m_promotion_state,
-    m_local_mirror_uuid, *m_remote_mirror_uuid, &m_client_meta,
-    m_progress_ctx, m_do_resync, &m_syncing, ctx);
+    BootstrapRequest<I>, &BootstrapRequest<I>::handle_prepare_replay>(this);
+  auto request = (*m_state_builder)->create_prepare_replay_request(
+    m_local_mirror_uuid, m_promotion_state, m_progress_ctx, m_do_resync,
+    &m_syncing, ctx);
   request->send();
 }
 
@@ -380,13 +361,13 @@ void BootstrapRequest<I>::handle_prepare_replay(int r) {
       derr << "failed to prepare local replay: " << cpp_strerror(r) << dendl;
     }
     m_ret_val = r;
-    close_local_image();
+    close_remote_image();
     return;
   } else if (*m_do_resync) {
     dout(10) << "local image resync requested" << dendl;
     close_remote_image();
     return;
-  } else if (m_client_state == cls::journal::CLIENT_STATE_DISCONNECTED) {
+  } else if ((*m_state_builder)->is_disconnected()) {
     dout(10) << "client flagged disconnected -- skipping bootstrap" << dendl;
     // The caller is expected to detect disconnect initializing remote journal.
     m_ret_val = 0;
@@ -406,14 +387,13 @@ void BootstrapRequest<I>::create_local_image() {
   dout(10) << dendl;
   update_progress("CREATE_LOCAL_IMAGE");
 
-  // TODO support snapshot-based mirroring
+  ceph_assert(*m_state_builder != nullptr);
   auto ctx = create_context_callback<
     BootstrapRequest<I>,
     &BootstrapRequest<I>::handle_create_local_image>(this);
-  auto request = journal::CreateLocalImageRequest<I>::create(
-    m_threads, m_local_io_ctx, m_remote_image_ctx, *m_remote_journaler,
-    m_global_image_id, *m_remote_mirror_uuid, &m_client_meta, m_progress_ctx,
-    m_local_image_id, ctx);
+  auto request = (*m_state_builder)->create_local_image_request(
+    m_threads, m_local_io_ctx, m_remote_image_ctx, m_global_image_id,
+    m_progress_ctx, ctx);
   request->send();
 }
 
@@ -432,8 +412,6 @@ void BootstrapRequest<I>::handle_create_local_image(int r) {
     return;
   }
 
-  m_client_state = cls::journal::CLIENT_STATE_CONNECTED;
-
   open_local_image();
 }
 
@@ -452,17 +430,15 @@ void BootstrapRequest<I>::image_sync() {
   dout(15) << dendl;
   ceph_assert(m_image_sync == nullptr);
 
-  // TODO temporary
-  m_state_builder = journal::StateBuilder<I>::create(m_global_image_id);
-  m_state_builder->remote_journaler = *m_remote_journaler;
-  m_state_builder->remote_client_meta = m_client_meta;
-  auto sync_point_handler = m_state_builder->create_sync_point_handler();
+  auto state_builder = *m_state_builder;
+  auto sync_point_handler = state_builder->create_sync_point_handler();
 
   Context *ctx = create_context_callback<
     BootstrapRequest<I>, &BootstrapRequest<I>::handle_image_sync>(this);
   m_image_sync = ImageSync<I>::create(
-    m_threads, *m_local_image_ctx, m_remote_image_ctx, m_local_mirror_uuid,
-    sync_point_handler, m_instance_watcher, m_progress_ctx, ctx);
+    m_threads, state_builder->local_image_ctx, m_remote_image_ctx,
+    m_local_mirror_uuid, sync_point_handler, m_instance_watcher,
+    m_progress_ctx, ctx);
   m_image_sync->get();
   locker.unlock();
 
@@ -479,12 +455,7 @@ void BootstrapRequest<I>::handle_image_sync(int r) {
     m_image_sync->put();
     m_image_sync = nullptr;
 
-    m_state_builder->destroy_sync_point_handler();
-
-    // TODO
-    m_state_builder->remote_journaler = nullptr;
-    m_state_builder->destroy();
-    m_state_builder = nullptr;
+    (*m_state_builder)->destroy_sync_point_handler();
   }
 
   if (r < 0) {
@@ -499,32 +470,6 @@ void BootstrapRequest<I>::handle_image_sync(int r) {
   close_remote_image();
 }
 
-template <typename I>
-void BootstrapRequest<I>::close_local_image() {
-  dout(15) << dendl;
-
-  update_progress("CLOSE_LOCAL_IMAGE");
-
-  Context *ctx = create_context_callback<
-    BootstrapRequest<I>, &BootstrapRequest<I>::handle_close_local_image>(
-      this);
-  CloseImageRequest<I> *request = CloseImageRequest<I>::create(
-    m_local_image_ctx, ctx);
-  request->send();
-}
-
-template <typename I>
-void BootstrapRequest<I>::handle_close_local_image(int r) {
-  dout(15) << "r=" << r << dendl;
-
-  if (r < 0) {
-    derr << "error encountered closing local image: " << cpp_strerror(r)
-         << dendl;
-  }
-
-  close_remote_image();
-}
-
 template <typename I>
 void BootstrapRequest<I>::close_remote_image() {
   dout(15) << dendl;
index 91093df41b551dc54def19b156e8657ae94e987b..6561495bbfaa5c3795cf5544aa890826fd9221f5 100644 (file)
@@ -7,14 +7,10 @@
 #include "include/int_types.h"
 #include "include/rados/librados.hpp"
 #include "common/ceph_mutex.h"
-#include "cls/journal/cls_journal_types.h"
 #include "cls/rbd/cls_rbd_types.h"
-#include "librbd/journal/Types.h"
-#include "librbd/journal/TypeTraits.h"
 #include "librbd/mirror/Types.h"
 #include "tools/rbd_mirror/CancelableRequest.h"
 #include "tools/rbd_mirror/Types.h"
-#include <list>
 #include <string>
 
 class Context;
@@ -35,15 +31,11 @@ template <typename> struct Threads;
 
 namespace image_replayer {
 
-// TODO
-namespace journal { template <typename> class StateBuilder; }
+template <typename> class StateBuilder;
 
 template <typename ImageCtxT = librbd::ImageCtx>
 class BootstrapRequest : public CancelableRequest {
 public:
-  typedef librbd::journal::TypeTraits<ImageCtxT> TypeTraits;
-  typedef typename TypeTraits::Journaler Journaler;
-  typedef librbd::journal::MirrorPeerClientMeta MirrorPeerClientMeta;
   typedef rbd::mirror::ProgressContext ProgressContext;
 
   static BootstrapRequest* create(
@@ -55,17 +47,12 @@ public:
       const std::string& local_mirror_uuid,
       ::journal::CacheManagerHandler* cache_manager_handler,
       ProgressContext* progress_ctx,
-      ImageCtxT** local_image_ctx,
-      std::string* local_image_id,
-      std::string* remote_image_id,
-      std::string* remote_mirror_uuid,
-      Journaler** remote_journaler,
+      StateBuilder<ImageCtxT>** state_builder,
       bool* do_resync,
       Context* on_finish) {
     return new BootstrapRequest(
       threads, local_io_ctx, remote_io_ctx, instance_watcher, global_image_id,
-      local_mirror_uuid,  cache_manager_handler, progress_ctx, local_image_ctx,
-      local_image_id, remote_image_id, remote_mirror_uuid, remote_journaler,
+      local_mirror_uuid,  cache_manager_handler, progress_ctx, state_builder,
       do_resync, on_finish);
   }
 
@@ -78,11 +65,7 @@ public:
       const std::string& local_mirror_uuid,
       ::journal::CacheManagerHandler* cache_manager_handler,
       ProgressContext* progress_ctx,
-      ImageCtxT** local_image_ctx,
-      std::string* local_image_id,
-      std::string* remote_image_id,
-      std::string* remote_mirror_uuid,
-      Journaler** remote_journaler,
+      StateBuilder<ImageCtxT>** state_builder,
       bool* do_resync,
       Context* on_finish);
   ~BootstrapRequest() override;
@@ -121,17 +104,14 @@ private:
    *              |                                     *   *
    *              |                                     *   *
    *              v                                     *   *
-   *           PREPARE_REPLAY * * * * * * * *           *   *
-   *              |                         *           *   *
-   *              |                         *           *   *
-   *              v (skip if not needed)    v           *   *
-   *           IMAGE_SYNC * * * * > CLOSE_LOCAL_IMAGE   *   *
-   *              |                         |           *   *
-   *              |                         |           *   *
-   *              \-----------------\ /-----/           *   *
-   *                                 |                  *   *
-   *                                 |                  *   *
-   *    /----------------------------/                  *   *
+   *           PREPARE_REPLAY * * * * * * * * * * * * * *   *
+   *              |                                     *   *
+   *              |                                     *   *
+   *              v (skip if not needed)                *   *
+   *           IMAGE_SYNC * * * * * * * * * * * * * * * *   *
+   *              |                                     *   *
+   *              |                                     *   *
+   *    /---------/                                     *   *
    *    |                                               *   *
    *    v                                               *   *
    * CLOSE_REMOTE_IMAGE < * * * * * * * * * * * * * * * *   *
@@ -141,8 +121,6 @@ private:
    *
    * @endverbatim
    */
-  typedef std::list<cls::journal::Tag> Tags;
-
   Threads<ImageCtxT>* m_threads;
   librados::IoCtx &m_local_io_ctx;
   librados::IoCtx &m_remote_io_ctx;
@@ -151,11 +129,7 @@ private:
   std::string m_local_mirror_uuid;
   ::journal::CacheManagerHandler *m_cache_manager_handler;
   ProgressContext *m_progress_ctx;
-  ImageCtxT **m_local_image_ctx;
-  std::string* m_local_image_id;
-  std::string* m_remote_image_id;
-  std::string* m_remote_mirror_uuid;
-  Journaler** m_remote_journaler;
+  StateBuilder<ImageCtxT>** m_state_builder;
   bool *m_do_resync;
 
   mutable ceph::mutex m_lock;
@@ -168,19 +142,11 @@ private:
   int m_ret_val = 0;
 
   std::string m_local_image_name;
-  std::string m_local_image_tag_owner;
   std::string m_prepare_local_image_name;
 
-  cls::journal::ClientState m_client_state =
-    cls::journal::CLIENT_STATE_DISCONNECTED;
-  librbd::journal::MirrorPeerClientMeta m_client_meta;
-
   bool m_syncing = false;
   ImageSync<ImageCtxT> *m_image_sync = nullptr;
 
-  // TODO temporary
-  journal::StateBuilder<ImageCtxT>* m_state_builder = nullptr;
-
   void prepare_local_image();
   void handle_prepare_local_image(int r);
 
@@ -205,9 +171,6 @@ private:
   void image_sync();
   void handle_image_sync(int r);
 
-  void close_local_image();
-  void handle_close_local_image(int r);
-
   void close_remote_image();
   void handle_close_remote_image(int r);
 
index 52bbeb2cc87722752e6d2f1a4e378145ebbfcb90..a5bfb5a19d12ca5c94e6f409ef829eeada2a5965 100644 (file)
@@ -11,6 +11,7 @@
 #include "librbd/Utils.h"
 #include "tools/rbd_mirror/Threads.h"
 #include "tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h"
+#include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
 #include <type_traits>
 
 #define dout_context g_ceph_context
@@ -41,14 +42,14 @@ void PrepareLocalImageRequest<I>::get_local_image_id() {
     PrepareLocalImageRequest<I>,
     &PrepareLocalImageRequest<I>::handle_get_local_image_id>(this);
   auto req = GetMirrorImageIdRequest<I>::create(m_io_ctx, m_global_image_id,
-                                                m_local_image_id, ctx);
+                                                &m_local_image_id, ctx);
   req->send();
 }
 
 template <typename I>
 void PrepareLocalImageRequest<I>::handle_get_local_image_id(int r) {
   dout(10) << "r=" << r << ", "
-           << "local_image_id=" << *m_local_image_id << dendl;
+           << "local_image_id=" << m_local_image_id << dendl;
 
   if (r < 0) {
     finish(r);
@@ -63,7 +64,7 @@ void PrepareLocalImageRequest<I>::get_local_image_name() {
   dout(10) << dendl;
 
   librados::ObjectReadOperation op;
-  librbd::cls_client::dir_get_name_start(&op, *m_local_image_id);
+  librbd::cls_client::dir_get_name_start(&op, m_local_image_id);
 
   m_out_bl.clear();
   librados::AioCompletion *aio_comp = create_rados_callback<
@@ -99,7 +100,7 @@ void PrepareLocalImageRequest<I>::get_mirror_image() {
   dout(10) << dendl;
 
   librados::ObjectReadOperation op;
-  librbd::cls_client::mirror_image_get_start(&op, *m_local_image_id);
+  librbd::cls_client::mirror_image_get_start(&op, m_local_image_id);
 
   m_out_bl.clear();
   auto aio_comp = create_rados_callback<
@@ -157,14 +158,14 @@ void PrepareLocalImageRequest<I>::get_tag_owner() {
   Context *ctx = create_context_callback<
     PrepareLocalImageRequest<I>,
     &PrepareLocalImageRequest<I>::handle_get_tag_owner>(this);
-  Journal::get_tag_owner(m_io_ctx, *m_local_image_id, m_tag_owner,
+  Journal::get_tag_owner(m_io_ctx, m_local_image_id, &m_local_tag_owner,
                          m_work_queue, ctx);
 }
 
 template <typename I>
 void PrepareLocalImageRequest<I>::handle_get_tag_owner(int r) {
   dout(10) << "r=" << r << ", "
-           << "tag_owner=" << *m_tag_owner << dendl;
+           << "tag_owner=" << m_local_tag_owner << dendl;
 
   if (r < 0) {
     derr << "failed to retrieve journal tag owner: " << cpp_strerror(r)
@@ -173,6 +174,12 @@ void PrepareLocalImageRequest<I>::handle_get_tag_owner(int r) {
     return;
   }
 
+  // journal-based local image exists
+  auto state_builder = journal::StateBuilder<I>::create(m_global_image_id);
+  state_builder->local_image_id = m_local_image_id;
+  state_builder->local_tag_owner = m_local_tag_owner;
+  *m_state_builder = state_builder;
+
   finish(0);
 }
 
index f279f1867dde89caa7d8bd7a2c9a6cd52fecc3c4..05c7eb4319cc9dadac29fe4415e7e77d94aea772 100644 (file)
@@ -17,31 +17,33 @@ namespace rbd {
 namespace mirror {
 namespace image_replayer {
 
+template <typename> class StateBuilder;
+
 template <typename ImageCtxT = librbd::ImageCtx>
 class PrepareLocalImageRequest {
 public:
-  static PrepareLocalImageRequest *create(librados::IoCtx &io_ctx,
-                                          const std::string &global_image_id,
-                                          std::string *local_image_id,
-                                          std::string *local_image_name,
-                                          std::string *tag_owner,
-                                          ContextWQ *work_queue,
-                                          Context *on_finish) {
-    return new PrepareLocalImageRequest(io_ctx, global_image_id, local_image_id,
-                                        local_image_name, tag_owner, work_queue,
-                                        on_finish);
+  static PrepareLocalImageRequest *create(
+      librados::IoCtx &io_ctx,
+      const std::string &global_image_id,
+      std::string *local_image_name,
+      StateBuilder<ImageCtxT>** state_builder,
+      ContextWQ *work_queue,
+      Context *on_finish) {
+    return new PrepareLocalImageRequest(io_ctx, global_image_id,
+                                        local_image_name, state_builder,
+                                        work_queue, on_finish);
   }
 
-  PrepareLocalImageRequest(librados::IoCtx &io_ctx,
-                           const std::string &global_image_id,
-                           std::string *local_image_id,
-                           std::string *local_image_name,
-                           std::string *tag_owner,
-                           ContextWQ *work_queue,
-                           Context *on_finish)
+  PrepareLocalImageRequest(
+      librados::IoCtx &io_ctx,
+      const std::string &global_image_id,
+      std::string *local_image_name,
+      StateBuilder<ImageCtxT>** state_builder,
+      ContextWQ *work_queue,
+      Context *on_finish)
     : m_io_ctx(io_ctx), m_global_image_id(global_image_id),
-      m_local_image_id(local_image_id), m_local_image_name(local_image_name),
-      m_tag_owner(tag_owner), m_work_queue(work_queue), m_on_finish(on_finish) {
+      m_local_image_name(local_image_name), m_state_builder(state_builder),
+      m_work_queue(work_queue), m_on_finish(on_finish) {
   }
 
   void send();
@@ -72,13 +74,16 @@ private:
 
   librados::IoCtx &m_io_ctx;
   std::string m_global_image_id;
-  std::string *m_local_image_id;
   std::string *m_local_image_name;
-  std::string *m_tag_owner;
+  StateBuilder<ImageCtxT>** m_state_builder;
   ContextWQ *m_work_queue;
   Context *m_on_finish;
 
   bufferlist m_out_bl;
+  std::string m_local_image_id;
+
+  // journal-based mirroring
+  std::string m_local_tag_owner;
 
   void get_local_image_id();
   void handle_get_local_image_id(int r);
index 9190d09282555206a22f30386e4b0e8c7062a756..462f8b6974025b549f542a99657e946e48f7eba3 100644 (file)
@@ -14,6 +14,7 @@
 #include "tools/rbd_mirror/Threads.h"
 #include "tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h"
 #include "tools/rbd_mirror/image_replayer/Utils.h"
+#include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
 
 #define dout_context g_ceph_context
 #define dout_subsys ceph_subsys_rbd_mirror
@@ -54,8 +55,8 @@ template <typename I>
 void PrepareRemoteImageRequest<I>::handle_get_remote_mirror_uuid(int r) {
   if (r >= 0) {
     auto it = m_out_bl.cbegin();
-    r = librbd::cls_client::mirror_uuid_get_finish(&it, m_remote_mirror_uuid);
-    if (r >= 0 && m_remote_mirror_uuid->empty()) {
+    r = librbd::cls_client::mirror_uuid_get_finish(&it, &m_remote_mirror_uuid);
+    if (r >= 0 && m_remote_mirror_uuid.empty()) {
       r = -ENOENT;
     }
   }
@@ -72,6 +73,13 @@ void PrepareRemoteImageRequest<I>::handle_get_remote_mirror_uuid(int r) {
     return;
   }
 
+  auto state_builder = *m_state_builder;
+  if (state_builder != nullptr) {
+    // if the local image exists but the remote image doesn't, we still
+    // want to populate the remote mirror uuid that we've looked up
+    state_builder->remote_mirror_uuid = m_remote_mirror_uuid;
+  }
+
   get_remote_image_id();
 }
 
@@ -84,14 +92,14 @@ void PrepareRemoteImageRequest<I>::get_remote_image_id() {
     &PrepareRemoteImageRequest<I>::handle_get_remote_image_id>(this);
   auto req = GetMirrorImageIdRequest<I>::create(m_remote_io_ctx,
                                                 m_global_image_id,
-                                                m_remote_image_id, ctx);
+                                                &m_remote_image_id, ctx);
   req->send();
 }
 
 template <typename I>
 void PrepareRemoteImageRequest<I>::handle_get_remote_image_id(int r) {
   dout(10) << "r=" << r << ", "
-           << "remote_image_id=" << *m_remote_image_id << dendl;
+           << "remote_image_id=" << m_remote_image_id << dendl;
 
   if (r < 0) {
     finish(r);
@@ -106,7 +114,7 @@ void PrepareRemoteImageRequest<I>::get_mirror_image() {
   dout(10) << dendl;
 
   librados::ObjectReadOperation op;
-  librbd::cls_client::mirror_image_get_start(&op, *m_remote_image_id);
+  librbd::cls_client::mirror_image_get_start(&op, m_remote_image_id);
 
   auto aio_comp = create_rados_callback<
     PrepareRemoteImageRequest<I>,
@@ -137,6 +145,14 @@ void PrepareRemoteImageRequest<I>::handle_get_mirror_image(int r) {
     return;
   }
 
+  if (*m_state_builder != nullptr &&
+      (*m_state_builder)->get_mirror_image_mode() != mirror_image.mode) {
+    derr << "local and remote mirror image using different mirroring modes "
+         << "for image " << m_global_image_id << ": split-brain" << dendl;
+    finish(-EEXIST);
+    return;
+  }
+
   switch (mirror_image.mode) {
   case cls::rbd::MIRROR_IMAGE_MODE_JOURNAL:
     get_client();
@@ -160,36 +176,36 @@ void PrepareRemoteImageRequest<I>::get_client() {
   journal_settings.commit_interval = cct->_conf.get_val<double>(
     "rbd_mirror_journal_commit_age");
 
-  ceph_assert(*m_remote_journaler == nullptr);
-  *m_remote_journaler = new Journaler(m_threads->work_queue, m_threads->timer,
-                                      &m_threads->timer_lock, m_remote_io_ctx,
-                                      *m_remote_image_id, m_local_mirror_uuid,
-                                      journal_settings,
-                                      m_cache_manager_handler);
+  ceph_assert(m_remote_journaler == nullptr);
+  m_remote_journaler = new Journaler(m_threads->work_queue, m_threads->timer,
+                                     &m_threads->timer_lock, m_remote_io_ctx,
+                                     m_remote_image_id, m_local_mirror_uuid,
+                                     journal_settings, m_cache_manager_handler);
 
   Context *ctx = create_async_context_callback(
     m_threads->work_queue, create_context_callback<
       PrepareRemoteImageRequest<I>,
       &PrepareRemoteImageRequest<I>::handle_get_client>(this));
-  (*m_remote_journaler)->get_client(m_local_mirror_uuid, &m_client, ctx);
+  m_remote_journaler->get_client(m_local_mirror_uuid, &m_client, ctx);
 }
 
 template <typename I>
 void PrepareRemoteImageRequest<I>::handle_get_client(int r) {
   dout(10) << "r=" << r << dendl;
 
+  MirrorPeerClientMeta client_meta;
   if (r == -ENOENT) {
     dout(10) << "client not registered" << dendl;
     register_client();
   } else if (r < 0) {
     derr << "failed to retrieve client: " << cpp_strerror(r) << dendl;
     finish(r);
-  } else if (!util::decode_client_meta(m_client, m_client_meta)) {
+  } else if (!util::decode_client_meta(m_client, &client_meta)) {
     // require operator intervention since the data is corrupt
     finish(-EBADMSG);
   } else {
     // skip registration if it already exists
-    *m_client_state = m_client.state;
+    finalize_journal_state_builder(m_client.state, client_meta);
     finish(0);
   }
 }
@@ -198,11 +214,12 @@ template <typename I>
 void PrepareRemoteImageRequest<I>::register_client() {
   dout(10) << dendl;
 
-  librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
-    m_local_image_id};
-  mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  auto state_builder = *m_state_builder;
+  librbd::journal::MirrorPeerClientMeta client_meta{
+    (state_builder == nullptr ? "" : state_builder->local_image_id)};
+  client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
 
-  librbd::journal::ClientData client_data{mirror_peer_client_meta};
+  librbd::journal::ClientData client_data{client_meta};
   bufferlist client_data_bl;
   encode(client_data, client_data_bl);
 
@@ -210,7 +227,7 @@ void PrepareRemoteImageRequest<I>::register_client() {
     m_threads->work_queue, create_context_callback<
       PrepareRemoteImageRequest<I>,
       &PrepareRemoteImageRequest<I>::handle_register_client>(this));
-  (*m_remote_journaler)->register_client(client_data_bl, ctx);
+  m_remote_journaler->register_client(client_data_bl, ctx);
 }
 
 template <typename I>
@@ -224,20 +241,44 @@ void PrepareRemoteImageRequest<I>::handle_register_client(int r) {
     return;
   }
 
-  *m_client_state = cls::journal::CLIENT_STATE_CONNECTED;
-  *m_client_meta = librbd::journal::MirrorPeerClientMeta(m_local_image_id);
-  m_client_meta->state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
-
+  auto state_builder = *m_state_builder;
+  librbd::journal::MirrorPeerClientMeta client_meta{
+    (state_builder == nullptr ? "" : state_builder->local_image_id)};
+  client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  finalize_journal_state_builder(cls::journal::CLIENT_STATE_CONNECTED,
+                                 client_meta);
   finish(0);
 }
 
+template <typename I>
+void PrepareRemoteImageRequest<I>::finalize_journal_state_builder(
+    cls::journal::ClientState client_state,
+    const MirrorPeerClientMeta& client_meta) {
+  journal::StateBuilder<I>* state_builder = nullptr;
+  if (*m_state_builder != nullptr) {
+    // already verified that it's a matching builder in
+    // 'handle_get_mirror_image'
+    state_builder = dynamic_cast<journal::StateBuilder<I>*>(*m_state_builder);
+    ceph_assert(state_builder != nullptr);
+  } else {
+    state_builder = journal::StateBuilder<I>::create(m_global_image_id);
+    *m_state_builder = state_builder;
+  }
+
+  state_builder->remote_mirror_uuid = m_remote_mirror_uuid;
+  state_builder->remote_image_id = m_remote_image_id;
+  state_builder->remote_journaler = m_remote_journaler;
+  state_builder->remote_client_state = client_state;
+  state_builder->remote_client_meta = client_meta;
+}
+
 template <typename I>
 void PrepareRemoteImageRequest<I>::finish(int r) {
   dout(10) << "r=" << r << dendl;
 
   if (r < 0) {
-    delete *m_remote_journaler;
-    *m_remote_journaler = nullptr;
+    delete m_remote_journaler;
+    m_remote_journaler = nullptr;
   }
 
   m_on_finish->complete(r);
index 21dc5ecac8053463e00561e0e08f1cbcd6d76e34..616c18e13beef145a7299436782e45d148a18270 100644 (file)
@@ -8,6 +8,7 @@
 #include "include/rados/librados_fwd.hpp"
 #include "cls/journal/cls_journal_types.h"
 #include "journal/Settings.h"
+#include "librbd/journal/Types.h"
 #include "librbd/journal/TypeTraits.h"
 #include <string>
 
@@ -26,6 +27,8 @@ template <typename> struct Threads;
 
 namespace image_replayer {
 
+template <typename> class StateBuilder;
+
 template <typename ImageCtxT = librbd::ImageCtx>
 class PrepareRemoteImageRequest {
 public:
@@ -33,50 +36,38 @@ public:
   typedef typename TypeTraits::Journaler Journaler;
   typedef librbd::journal::MirrorPeerClientMeta MirrorPeerClientMeta;
 
-  static PrepareRemoteImageRequest *create(Threads<ImageCtxT> *threads,
-                                           librados::IoCtx &local_io_ctx,
-                                           librados::IoCtx &remote_io_ctx,
-                                           const std::string &global_image_id,
-                                           const std::string &local_mirror_uuid,
-                                           const std::string &local_image_id,
-                                           ::journal::CacheManagerHandler *cache_manager_handler,
-                                           std::string *remote_mirror_uuid,
-                                           std::string *remote_image_id,
-                                           Journaler **remote_journaler,
-                                           cls::journal::ClientState *client_state,
-                                           MirrorPeerClientMeta *client_meta,
-                                           Context *on_finish) {
+  static PrepareRemoteImageRequest *create(
+      Threads<ImageCtxT> *threads,
+      librados::IoCtx &local_io_ctx,
+      librados::IoCtx &remote_io_ctx,
+      const std::string &global_image_id,
+      const std::string &local_mirror_uuid,
+      ::journal::CacheManagerHandler *cache_manager_handler,
+      StateBuilder<ImageCtxT>** state_builder,
+      Context *on_finish) {
     return new PrepareRemoteImageRequest(threads, local_io_ctx, remote_io_ctx,
                                          global_image_id, local_mirror_uuid,
-                                         local_image_id, cache_manager_handler,
-                                         remote_mirror_uuid, remote_image_id,
-                                         remote_journaler, client_state,
-                                         client_meta, on_finish);
+                                         cache_manager_handler, state_builder,
+                                         on_finish);
   }
 
-  PrepareRemoteImageRequest(Threads<ImageCtxT> *threads,
-                            librados::IoCtx &local_io_ctx,
-                            librados::IoCtx &remote_io_ctx,
-                            const std::string &global_image_id,
-                            const std::string &local_mirror_uuid,
-                            const std::string &local_image_id,
-                            ::journal::CacheManagerHandler *cache_manager_handler,
-                            std::string *remote_mirror_uuid,
-                            std::string *remote_image_id,
-                            Journaler **remote_journaler,
-                            cls::journal::ClientState *client_state,
-                            MirrorPeerClientMeta *client_meta,
-                            Context *on_finish)
+  PrepareRemoteImageRequest(
+      Threads<ImageCtxT> *threads,
+      librados::IoCtx &local_io_ctx,
+      librados::IoCtx &remote_io_ctx,
+      const std::string &global_image_id,
+      const std::string &local_mirror_uuid,
+      ::journal::CacheManagerHandler *cache_manager_handler,
+      StateBuilder<ImageCtxT>** state_builder,
+      Context *on_finish)
     : m_threads(threads),
       m_local_io_ctx(local_io_ctx),
       m_remote_io_ctx(remote_io_ctx),
       m_global_image_id(global_image_id),
-      m_local_mirror_uuid(local_mirror_uuid), m_local_image_id(local_image_id),
+      m_local_mirror_uuid(local_mirror_uuid),
       m_cache_manager_handler(cache_manager_handler),
-      m_remote_mirror_uuid(remote_mirror_uuid),
-      m_remote_image_id(remote_image_id),
-      m_remote_journaler(remote_journaler), m_client_state(client_state),
-      m_client_meta(client_meta), m_on_finish(on_finish) {
+      m_state_builder(state_builder),
+      m_on_finish(on_finish) {
   }
 
   void send();
@@ -113,16 +104,16 @@ private:
   librados::IoCtx &m_remote_io_ctx;
   std::string m_global_image_id;
   std::string m_local_mirror_uuid;
-  std::string m_local_image_id;
   ::journal::CacheManagerHandler *m_cache_manager_handler;
-  std::string *m_remote_mirror_uuid;
-  std::string *m_remote_image_id;
-  Journaler **m_remote_journaler;
-  cls::journal::ClientState *m_client_state;
-  MirrorPeerClientMeta *m_client_meta;
+  StateBuilder<ImageCtxT>** m_state_builder;
   Context *m_on_finish;
 
   bufferlist m_out_bl;
+  std::string m_remote_mirror_uuid;
+  std::string m_remote_image_id;
+
+  // journal-based mirroring
+  Journaler *m_remote_journaler = nullptr;
   cls::journal::Client m_client;
 
   void get_remote_mirror_uuid();
@@ -140,6 +131,8 @@ private:
   void register_client();
   void handle_register_client(int r);
 
+  void finalize_journal_state_builder(cls::journal::ClientState client_state,
+                                      const MirrorPeerClientMeta& client_meta);
   void finish(int r);
 };
 
index 01d837a282900ef982c87931b8948eb3b784864d..9403108020cc9166f3d1c1fdf3c3977fa1f7a15e 100644 (file)
@@ -9,8 +9,10 @@
 #include "journal/Journaler.h"
 #include "librbd/ImageCtx.h"
 #include "librbd/Utils.h"
+#include "librbd/journal/Types.h"
 #include "tools/rbd_mirror/ProgressContext.h"
 #include "tools/rbd_mirror/image_replayer/CreateImageRequest.h"
+#include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
 
 #define dout_context g_ceph_context
 #define dout_subsys ceph_subsys_rbd_mirror
@@ -28,7 +30,7 @@ using librbd::util::create_context_callback;
 
 template <typename I>
 void CreateLocalImageRequest<I>::send() {
-  *m_local_image_id = "";
+  m_state_builder->local_image_id = "";
   unregister_client();
 }
 
@@ -40,7 +42,7 @@ void CreateLocalImageRequest<I>::unregister_client() {
   auto ctx = create_context_callback<
     CreateLocalImageRequest<I>,
     &CreateLocalImageRequest<I>::handle_unregister_client>(this);
-  m_remote_journaler->unregister_client(ctx);
+  m_state_builder->remote_journaler->unregister_client(ctx);
 }
 
 template <typename I>
@@ -53,18 +55,20 @@ void CreateLocalImageRequest<I>::handle_unregister_client(int r) {
     return;
   }
 
-  *m_client_meta = librbd::journal::MirrorPeerClientMeta{""};
+  m_state_builder->remote_client_meta = {};
   register_client();
 }
 
 template <typename I>
 void CreateLocalImageRequest<I>::register_client() {
-  ceph_assert(m_local_image_id->empty());
-  *m_local_image_id = librbd::util::generate_image_id<I>(m_local_io_ctx);
-  dout(10) << "local_image_id=" << *m_local_image_id << dendl;
+  ceph_assert(m_state_builder->local_image_id.empty());
+  m_state_builder->local_image_id =
+    librbd::util::generate_image_id<I>(m_local_io_ctx);
+  dout(10) << "local_image_id=" << m_state_builder->local_image_id << dendl;
   update_progress("REGISTER_CLIENT");
 
-  librbd::journal::MirrorPeerClientMeta client_meta{*m_local_image_id};
+  librbd::journal::MirrorPeerClientMeta client_meta{
+    m_state_builder->local_image_id};
   client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
 
   librbd::journal::ClientData client_data{client_meta};
@@ -74,7 +78,7 @@ void CreateLocalImageRequest<I>::register_client() {
   auto ctx = create_context_callback<
     CreateLocalImageRequest<I>,
     &CreateLocalImageRequest<I>::handle_register_client>(this);
-  m_remote_journaler->register_client(client_data_bl, ctx);
+  m_state_builder->remote_journaler->register_client(client_data_bl, ctx);
 }
 
 template <typename I>
@@ -88,15 +92,17 @@ void CreateLocalImageRequest<I>::handle_register_client(int r) {
     return;
   }
 
-  *m_client_meta = librbd::journal::MirrorPeerClientMeta{*m_local_image_id};
-  m_client_meta->state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
+  m_state_builder->remote_client_state = cls::journal::CLIENT_STATE_CONNECTED;
+  m_state_builder->remote_client_meta = {m_state_builder->local_image_id};
+  m_state_builder->remote_client_meta.state =
+    librbd::journal::MIRROR_PEER_STATE_SYNCING;
 
   create_local_image();
 }
 
 template <typename I>
 void CreateLocalImageRequest<I>::create_local_image() {
-  dout(10) << "local_image_id=" << *m_local_image_id << dendl;
+  dout(10) << "local_image_id=" << m_state_builder->local_image_id << dendl;
   update_progress("CREATE_LOCAL_IMAGE");
 
   m_remote_image_ctx->image_lock.lock_shared();
@@ -107,8 +113,9 @@ void CreateLocalImageRequest<I>::create_local_image() {
     CreateLocalImageRequest<I>,
     &CreateLocalImageRequest<I>::handle_create_local_image>(this);
   auto request = CreateImageRequest<I>::create(
-    m_threads, m_local_io_ctx, m_global_image_id, m_remote_mirror_uuid,
-    image_name, *m_local_image_id, m_remote_image_ctx, ctx);
+    m_threads, m_local_io_ctx, m_global_image_id,
+    m_state_builder->remote_mirror_uuid, image_name,
+    m_state_builder->local_image_id, m_remote_image_ctx, ctx);
   request->send();
 }
 template <typename I>
@@ -116,8 +123,9 @@ void CreateLocalImageRequest<I>::handle_create_local_image(int r) {
   dout(10) << "r=" << r << dendl;
 
   if (r == -EBADF) {
-    dout(5) << "image id " << *m_local_image_id << " already in-use" << dendl;
-    *m_local_image_id = "";
+    dout(5) << "image id " << m_state_builder->local_image_id << " "
+            << "already in-use" << dendl;
+    m_state_builder->local_image_id = "";
     update_client_image();
     return;
   } else if (r < 0) {
@@ -135,13 +143,15 @@ void CreateLocalImageRequest<I>::handle_create_local_image(int r) {
 
 template <typename I>
 void CreateLocalImageRequest<I>::update_client_image() {
-  ceph_assert(m_local_image_id->empty());
-  *m_local_image_id = librbd::util::generate_image_id<I>(m_local_io_ctx);
+  ceph_assert(m_state_builder->local_image_id.empty());
+  m_state_builder->local_image_id =
+    librbd::util::generate_image_id<I>(m_local_io_ctx);
 
-  dout(10) << "local_image_id=" << *m_local_image_id << dendl;
+  dout(10) << "local_image_id=" << m_state_builder->local_image_id << dendl;
   update_progress("UPDATE_CLIENT_IMAGE");
 
-  librbd::journal::MirrorPeerClientMeta client_meta{*m_local_image_id};
+  librbd::journal::MirrorPeerClientMeta client_meta{
+    m_state_builder->local_image_id};
   client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
 
   librbd::journal::ClientData client_data(client_meta);
@@ -151,7 +161,7 @@ void CreateLocalImageRequest<I>::update_client_image() {
   auto ctx = create_context_callback<
     CreateLocalImageRequest<I>,
     &CreateLocalImageRequest<I>::handle_update_client_image>(this);
-  m_remote_journaler->update_client(data_bl, ctx);
+  m_state_builder->remote_journaler->update_client(data_bl, ctx);
 }
 
 template <typename I>
@@ -164,8 +174,9 @@ void CreateLocalImageRequest<I>::handle_update_client_image(int r) {
     return;
   }
 
-  *m_client_meta = librbd::journal::MirrorPeerClientMeta{*m_local_image_id};
-  m_client_meta->state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
+  m_state_builder->remote_client_meta = {m_state_builder->local_image_id};
+  m_state_builder->remote_client_meta.state =
+    librbd::journal::MIRROR_PEER_STATE_SYNCING;
   create_local_image();
 }
 
index ee96117ea934d8d3bb589717113d8173670e5ed0..1ea19aca2698c3e6ea5ac853ffbba696af56d676 100644 (file)
@@ -5,8 +5,6 @@
 #define RBD_MIRROR_IMAGE_REPLAYER_JOURNAL_CREATE_LOCAL_IMAGE_REQUEST_H
 
 #include "include/rados/librados_fwd.hpp"
-#include "librbd/journal/Types.h"
-#include "librbd/journal/TypeTraits.h"
 #include "tools/rbd_mirror/BaseRequest.h"
 #include <string>
 
@@ -22,41 +20,41 @@ template <typename> struct Threads;
 namespace image_replayer {
 namespace journal {
 
+template <typename> class StateBuilder;
+
 template <typename ImageCtxT>
 class CreateLocalImageRequest : public BaseRequest {
 public:
-  typedef librbd::journal::MirrorPeerClientMeta MirrorPeerClientMeta;
-  typedef librbd::journal::TypeTraits<ImageCtxT> TypeTraits;
-  typedef typename TypeTraits::Journaler Journaler;
   typedef rbd::mirror::ProgressContext ProgressContext;
 
   static CreateLocalImageRequest* create(
-      Threads<ImageCtxT>* threads, librados::IoCtx& local_io_ctx,
-      ImageCtxT* remote_image_ctx, Journaler* remote_journaler,
+      Threads<ImageCtxT>* threads,
+      librados::IoCtx& local_io_ctx,
+      ImageCtxT* remote_image_ctx,
       const std::string& global_image_id,
-      const std::string& remote_mirror_uuid,
-      MirrorPeerClientMeta* client_meta, ProgressContext* progress_ctx,
-      std::string* local_image_id, Context* on_finish) {
+      ProgressContext* progress_ctx,
+      StateBuilder<ImageCtxT>* state_builder,
+      Context* on_finish) {
     return new CreateLocalImageRequest(threads, local_io_ctx, remote_image_ctx,
-                                       remote_journaler, global_image_id,
-                                       remote_mirror_uuid, client_meta,
-                                       progress_ctx, local_image_id, on_finish);
+                                       global_image_id, progress_ctx,
+                                       state_builder, on_finish);
   }
 
   CreateLocalImageRequest(
-      Threads<ImageCtxT>* threads, librados::IoCtx& local_io_ctx,
-      ImageCtxT* remote_image_ctx, Journaler* remote_journaler,
+      Threads<ImageCtxT>* threads,
+      librados::IoCtx& local_io_ctx,
+      ImageCtxT* remote_image_ctx,
       const std::string& global_image_id,
-      const std::string& remote_mirror_uuid,
-      MirrorPeerClientMeta* client_meta, ProgressContext* progress_ctx,
-      std::string* local_image_id, Context* on_finish)
+      ProgressContext* progress_ctx,
+      StateBuilder<ImageCtxT>* state_builder,
+      Context* on_finish)
     : BaseRequest(on_finish),
-      m_threads(threads), m_local_io_ctx(local_io_ctx),
+      m_threads(threads),
+      m_local_io_ctx(local_io_ctx),
       m_remote_image_ctx(remote_image_ctx),
-      m_remote_journaler(remote_journaler),
       m_global_image_id(global_image_id),
-      m_remote_mirror_uuid(remote_mirror_uuid), m_client_meta(client_meta),
-      m_progress_ctx(progress_ctx), m_local_image_id(local_image_id) {
+      m_progress_ctx(progress_ctx),
+      m_state_builder(state_builder) {
   }
 
   void send();
@@ -87,12 +85,9 @@ private:
   Threads<ImageCtxT>* m_threads;
   librados::IoCtx& m_local_io_ctx;
   ImageCtxT* m_remote_image_ctx;
-  Journaler* m_remote_journaler;
   std::string m_global_image_id;
-  std::string m_remote_mirror_uuid;
-  MirrorPeerClientMeta* m_client_meta;
   ProgressContext* m_progress_ctx;
-  std::string* m_local_image_id;
+  StateBuilder<ImageCtxT>* m_state_builder;
 
   void unregister_client();
   void handle_unregister_client(int r);
index 13a4b9a1383aa6c8465b797911dd0b082de0786d..69631f27587ede2a4a9264a323b0bcfa347a829e 100644 (file)
@@ -10,6 +10,7 @@
 #include "librbd/Journal.h"
 #include "librbd/Utils.h"
 #include "tools/rbd_mirror/ProgressContext.h"
+#include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
 
 #define dout_context g_ceph_context
 #define dout_subsys ceph_subsys_rbd_mirror
@@ -30,8 +31,20 @@ void PrepareReplayRequest<I>::send() {
   *m_resync_requested = false;
   *m_syncing = false;
 
-  std::shared_lock image_locker(m_local_image_ctx->image_lock);
-  if (m_local_image_ctx->journal == nullptr) {
+  if (m_state_builder->local_image_id !=
+        m_state_builder->remote_client_meta.image_id) {
+    // somehow our local image has a different image id than the image id
+    // registered in the remote image
+    derr << "split-brain detected: local_image_id="
+         << m_state_builder->local_image_id << ", "
+         << "registered local_image_id="
+         << m_state_builder->remote_client_meta.image_id << dendl;
+    finish(-EEXIST);
+    return;
+  }
+
+  std::shared_lock image_locker(m_state_builder->local_image_ctx->image_lock);
+  if (m_state_builder->local_image_ctx->journal == nullptr) {
     image_locker.unlock();
 
     derr << "local image does not support journaling" << dendl;
@@ -39,7 +52,8 @@ void PrepareReplayRequest<I>::send() {
     return;
   }
 
-  int r = m_local_image_ctx->journal->is_resync_requested(m_resync_requested);
+  int r = m_state_builder->local_image_ctx->journal->is_resync_requested(
+    m_resync_requested);
   if (r < 0) {
     image_locker.unlock();
 
@@ -48,13 +62,13 @@ void PrepareReplayRequest<I>::send() {
     return;
   }
 
-  m_local_tag_tid = m_local_image_ctx->journal->get_tag_tid();
-  m_local_tag_data = m_local_image_ctx->journal->get_tag_data();
+  m_local_tag_tid = m_state_builder->local_image_ctx->journal->get_tag_tid();
+  m_local_tag_data = m_state_builder->local_image_ctx->journal->get_tag_data();
   dout(10) << "local tag=" << m_local_tag_tid << ", "
            << "local tag data=" << m_local_tag_data << dendl;
   image_locker.unlock();
 
-  if (m_local_tag_data.mirror_uuid != m_remote_mirror_uuid &&
+  if (m_local_tag_data.mirror_uuid != m_state_builder->remote_mirror_uuid &&
       m_remote_promotion_state != librbd::mirror::PROMOTION_STATE_PRIMARY) {
     // if the local mirror is not linked to the (now) non-primary image,
     // stop the replay. Otherwise, we ignore that the remote is non-primary
@@ -68,9 +82,10 @@ void PrepareReplayRequest<I>::send() {
   if (*m_resync_requested) {
     finish(0);
     return;
-  } else if (m_client_meta->state ==
+  } else if (m_state_builder->remote_client_meta.state ==
                librbd::journal::MIRROR_PEER_STATE_SYNCING &&
-             m_local_tag_data.mirror_uuid == m_remote_mirror_uuid) {
+             m_local_tag_data.mirror_uuid ==
+               m_state_builder->remote_mirror_uuid) {
     // if the initial sync hasn't completed, we cannot replay
     *m_syncing = true;
     finish(0);
@@ -82,8 +97,9 @@ void PrepareReplayRequest<I>::send() {
 
 template <typename I>
 void PrepareReplayRequest<I>::update_client_state() {
-  if (m_client_meta->state != librbd::journal::MIRROR_PEER_STATE_SYNCING ||
-      m_local_tag_data.mirror_uuid == m_remote_mirror_uuid) {
+  if (m_state_builder->remote_client_meta.state !=
+        librbd::journal::MIRROR_PEER_STATE_SYNCING ||
+      m_local_tag_data.mirror_uuid == m_state_builder->remote_mirror_uuid) {
     get_remote_tag_class();
     return;
   }
@@ -94,7 +110,7 @@ void PrepareReplayRequest<I>::update_client_state() {
   dout(15) << dendl;
   update_progress("UPDATE_CLIENT_STATE");
 
-  librbd::journal::MirrorPeerClientMeta client_meta(*m_client_meta);
+  auto client_meta = m_state_builder->remote_client_meta;
   client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
 
   librbd::journal::ClientData client_data(client_meta);
@@ -104,7 +120,7 @@ void PrepareReplayRequest<I>::update_client_state() {
   auto ctx = create_context_callback<
     PrepareReplayRequest<I>,
     &PrepareReplayRequest<I>::handle_update_client_state>(this);
-  m_remote_journaler->update_client(data_bl, ctx);
+  m_state_builder->remote_journaler->update_client(data_bl, ctx);
 }
 
 template <typename I>
@@ -116,7 +132,8 @@ void PrepareReplayRequest<I>::handle_update_client_state(int r) {
     return;
   }
 
-  m_client_meta->state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+  m_state_builder->remote_client_meta.state =
+    librbd::journal::MIRROR_PEER_STATE_REPLAYING;
   get_remote_tag_class();
 }
 
@@ -128,8 +145,8 @@ void PrepareReplayRequest<I>::get_remote_tag_class() {
   auto ctx = create_context_callback<
     PrepareReplayRequest<I>,
     &PrepareReplayRequest<I>::handle_get_remote_tag_class>(this);
-  m_remote_journaler->get_client(librbd::Journal<>::IMAGE_CLIENT_ID, &m_client,
-                                 ctx);
+  m_state_builder->remote_journaler->get_client(
+    librbd::Journal<>::IMAGE_CLIENT_ID, &m_client, ctx);
 }
 
 template <typename I>
@@ -175,7 +192,8 @@ void PrepareReplayRequest<I>::get_remote_tags() {
   auto ctx = create_context_callback<
     PrepareReplayRequest<I>,
     &PrepareReplayRequest<I>::handle_get_remote_tags>(this);
-  m_remote_journaler->get_tags(m_remote_tag_class, &m_remote_tags, ctx);
+  m_state_builder->remote_journaler->get_tags(m_remote_tag_class,
+                                              &m_remote_tags, ctx);
 }
 
 template <typename I>
@@ -200,7 +218,8 @@ void PrepareReplayRequest<I>::handle_get_remote_tags(int r) {
   // decode the remote tags
   for (auto &remote_tag : m_remote_tags) {
     if (m_local_tag_data.predecessor.commit_valid &&
-        m_local_tag_data.predecessor.mirror_uuid == m_remote_mirror_uuid &&
+        m_local_tag_data.predecessor.mirror_uuid ==
+          m_state_builder->remote_mirror_uuid &&
         m_local_tag_data.predecessor.tag_tid > remote_tag.tid) {
       dout(10) << "skipping processed predecessor remote tag "
                << remote_tag.tid << dendl;
@@ -250,7 +269,8 @@ void PrepareReplayRequest<I>::handle_get_remote_tags(int r) {
           continue;
         }
 
-        if (m_local_tag_data.predecessor.mirror_uuid == m_remote_mirror_uuid &&
+        if (m_local_tag_data.predecessor.mirror_uuid ==
+              m_state_builder->remote_mirror_uuid &&
             remote_tag_data.predecessor.mirror_uuid ==
               librbd::Journal<>::LOCAL_MIRROR_UUID) {
           // remote demoted and local has matching event
@@ -277,7 +297,7 @@ void PrepareReplayRequest<I>::handle_get_remote_tags(int r) {
   }
 
   if (remote_tag_data_valid &&
-      m_local_tag_data.mirror_uuid == m_remote_mirror_uuid) {
+      m_local_tag_data.mirror_uuid == m_state_builder->remote_mirror_uuid) {
     dout(10) << "local image is in clean replay state" << dendl;
   } else if (reconnect_orphan) {
     dout(10) << "remote image was demoted/promoted" << dendl;
index dc38f8b4cb0478f5fd931b5e6e04e786977fb43e..4538c94a4ad94077365f177d2d70631c676983cb 100644 (file)
@@ -7,7 +7,6 @@
 #include "include/int_types.h"
 #include "cls/journal/cls_journal_types.h"
 #include "librbd/journal/Types.h"
-#include "librbd/journal/TypeTraits.h"
 #include "librbd/mirror/Types.h"
 #include "tools/rbd_mirror/BaseRequest.h"
 #include <list>
@@ -24,39 +23,38 @@ class ProgressContext;
 namespace image_replayer {
 namespace journal {
 
+template <typename> class StateBuilder;
+
 template <typename ImageCtxT>
 class PrepareReplayRequest : public BaseRequest {
 public:
-  typedef librbd::journal::TypeTraits<ImageCtxT> TypeTraits;
-  typedef typename TypeTraits::Journaler Journaler;
-  typedef librbd::journal::MirrorPeerClientMeta MirrorPeerClientMeta;
-
   static PrepareReplayRequest* create(
-      ImageCtxT* local_image_ctx, Journaler* remote_journaler,
-      librbd::mirror::PromotionState remote_promotion_state,
       const std::string& local_mirror_uuid,
-      const std::string& remote_mirror_uuid,
-      MirrorPeerClientMeta* client_meta, ProgressContext* progress_ctx,
-      bool* resync_requested, bool* syncing, Context* on_finish) {
+      librbd::mirror::PromotionState remote_promotion_state,
+      ProgressContext* progress_ctx,
+      StateBuilder<ImageCtxT>* state_builder,
+      bool* resync_requested,
+      bool* syncing,
+      Context* on_finish) {
     return new PrepareReplayRequest(
-      local_image_ctx, remote_journaler, remote_promotion_state,
-      local_mirror_uuid, remote_mirror_uuid, client_meta, progress_ctx,
+      local_mirror_uuid, remote_promotion_state, progress_ctx, state_builder,
       resync_requested, syncing, on_finish);
   }
 
   PrepareReplayRequest(
-      ImageCtxT* local_image_ctx, Journaler* remote_journaler,
-      librbd::mirror::PromotionState remote_promotion_state,
       const std::string& local_mirror_uuid,
-      const std::string& remote_mirror_uuid,
-      MirrorPeerClientMeta* client_meta, ProgressContext* progress_ctx,
-      bool* resync_requested, bool* syncing, Context* on_finish)
+      librbd::mirror::PromotionState remote_promotion_state,
+      ProgressContext* progress_ctx,
+      StateBuilder<ImageCtxT>* state_builder,
+      bool* resync_requested,
+      bool* syncing,
+      Context* on_finish)
     : BaseRequest(on_finish),
-      m_local_image_ctx(local_image_ctx), m_remote_journaler(remote_journaler),
-      m_remote_promotion_state(remote_promotion_state),
       m_local_mirror_uuid(local_mirror_uuid),
-      m_remote_mirror_uuid(remote_mirror_uuid), m_client_meta(client_meta),
-      m_progress_ctx(progress_ctx), m_resync_requested(resync_requested),
+      m_remote_promotion_state(remote_promotion_state),
+      m_progress_ctx(progress_ctx),
+      m_state_builder(state_builder),
+      m_resync_requested(resync_requested),
       m_syncing(syncing) {
   }
 
@@ -84,13 +82,10 @@ private:
    */
   typedef std::list<cls::journal::Tag> Tags;
 
-  ImageCtxT* m_local_image_ctx;
-  Journaler* m_remote_journaler;
-  librbd::mirror::PromotionState m_remote_promotion_state;
   std::string m_local_mirror_uuid;
-  std::string m_remote_mirror_uuid;
-  MirrorPeerClientMeta* m_client_meta;
+  librbd::mirror::PromotionState m_remote_promotion_state;
   ProgressContext* m_progress_ctx;
+  StateBuilder<ImageCtxT>* m_state_builder;
   bool* m_resync_requested;
   bool* m_syncing;
 
index 7b58b364040f6b63b0f4ccc19aa06cbff9e3897f..87290b0550183dde9390f12923b20a9ad6c4a204 100644 (file)
@@ -19,6 +19,7 @@
 #include "tools/rbd_mirror/image_replayer/Utils.h"
 #include "tools/rbd_mirror/image_replayer/journal/EventPreprocessor.h"
 #include "tools/rbd_mirror/image_replayer/journal/ReplayStatusFormatter.h"
+#include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
 
 #define dout_context g_ceph_context
 #define dout_subsys ceph_subsys_rbd_mirror
@@ -150,15 +151,14 @@ struct Replayer<I>::LocalJournalListener
 
 template <typename I>
 Replayer<I>::Replayer(
-    I** local_image_ctx, Journaler* remote_journaler,
-    const std::string& local_mirror_uuid, const std::string& remote_mirror_uuid,
-    ReplayerListener* replayer_listener, Threads<I>* threads)
-  : m_local_image_ctx(local_image_ctx),
-    m_remote_journaler(remote_journaler),
+    Threads<I>* threads,
+    const std::string& local_mirror_uuid,
+    StateBuilder<I>* state_builder,
+    ReplayerListener* replayer_listener)
+  : m_threads(threads),
     m_local_mirror_uuid(local_mirror_uuid),
-    m_remote_mirror_uuid(remote_mirror_uuid),
+    m_state_builder(state_builder),
     m_replayer_listener(replayer_listener),
-    m_threads(threads),
     m_lock(ceph::make_mutex(librbd::util::unique_lock_name(
       "rbd::mirror::image_replayer::journal::Replayer", this))) {
   dout(10) << dendl;
@@ -186,7 +186,7 @@ Replayer<I>::~Replayer() {
   ceph_assert(m_replay_status_formatter == nullptr);
   ceph_assert(m_delayed_preprocess_task == nullptr);
   ceph_assert(m_flush_local_replay_task == nullptr);
-  ceph_assert(*m_local_image_ctx == nullptr);
+  ceph_assert(m_state_builder->local_image_ctx == nullptr);
 }
 
 template <typename I>
@@ -195,7 +195,7 @@ void Replayer<I>::init(Context* on_finish) {
 
   ceph_assert(m_local_journal == nullptr);
   {
-    auto local_image_ctx = *m_local_image_ctx;
+    auto local_image_ctx = m_state_builder->local_image_ctx;
     std::shared_lock image_locker{local_image_ctx->image_lock};
     m_image_spec = util::compute_image_spec(local_image_ctx->md_ctx,
                                             local_image_ctx->name);
@@ -208,7 +208,7 @@ void Replayer<I>::init(Context* on_finish) {
   if (m_local_journal == nullptr) {
     std::unique_lock locker{m_lock};
     m_state = STATE_COMPLETE;
-    m_remote_journaler = nullptr;
+    m_state_builder->remote_journaler = nullptr;
 
     handle_replay_complete(locker, -EINVAL, "error accessing local journal");
     close_local_image();
@@ -275,7 +275,7 @@ void Replayer<I>::init_remote_journaler() {
 
   Context *ctx = create_context_callback<
     Replayer, &Replayer<I>::handle_init_remote_journaler>(this);
-  m_remote_journaler->init(ctx);
+  m_state_builder->remote_journaler->init(ctx);
 }
 
 template <typename I>
@@ -293,11 +293,11 @@ void Replayer<I>::handle_init_remote_journaler(int r) {
   // listen for metadata updates to check for disconnect events
   ceph_assert(m_remote_listener == nullptr);
   m_remote_listener = new RemoteJournalerListener(this);
-  m_remote_journaler->add_listener(m_remote_listener);
+  m_state_builder->remote_journaler->add_listener(m_remote_listener);
 
   cls::journal::Client remote_client;
-  r = m_remote_journaler->get_cached_client(m_local_mirror_uuid,
-                                            &remote_client);
+  r = m_state_builder->remote_journaler->get_cached_client(m_local_mirror_uuid,
+                                                           &remote_client);
   if (r < 0) {
     derr << "error retrieving remote journal client: " << cpp_strerror(r)
          << dendl;
@@ -307,7 +307,8 @@ void Replayer<I>::handle_init_remote_journaler(int r) {
   }
 
   std::string error;
-  r = validate_remote_client_state(remote_client, &m_remote_client_meta,
+  r = validate_remote_client_state(remote_client,
+                                   &m_state_builder->remote_client_meta,
                                    &m_resync_requested, &error);
   if (r < 0) {
     handle_replay_complete(locker, r, error);
@@ -335,7 +336,8 @@ void Replayer<I>::handle_start_external_replay(int r) {
   if (r < 0) {
     ceph_assert(m_local_journal_replay == nullptr);
     derr << "error starting external replay on local image "
-         <<  (*m_local_image_ctx)->id << ": " << cpp_strerror(r) << dendl;
+         << m_state_builder->local_image_ctx->id << ": "
+         << cpp_strerror(r) << dendl;
 
     handle_replay_complete(locker, r, "error starting replay on local image");
     close_local_image();
@@ -375,16 +377,18 @@ void Replayer<I>::handle_start_external_replay(int r) {
 
   // start remote journal replay
   m_event_preprocessor = EventPreprocessor<I>::create(
-    **m_local_image_ctx, *m_remote_journaler, m_local_mirror_uuid,
-    &m_remote_client_meta, m_threads->work_queue);
+    *m_state_builder->local_image_ctx, *m_state_builder->remote_journaler,
+    m_local_mirror_uuid, &m_state_builder->remote_client_meta,
+    m_threads->work_queue);
   m_replay_status_formatter = ReplayStatusFormatter<I>::create(
-    m_remote_journaler, m_local_mirror_uuid);
+    m_state_builder->remote_journaler, m_local_mirror_uuid);
 
-  auto cct = static_cast<CephContext *>((*m_local_image_ctx)->cct);
+  auto cct = static_cast<CephContext *>(m_state_builder->local_image_ctx->cct);
   double poll_seconds = cct->_conf.get_val<double>(
     "rbd_mirror_journal_poll_age");
   m_remote_replay_handler = new RemoteReplayHandler(this);
-  m_remote_journaler->start_live_replay(m_remote_replay_handler, poll_seconds);
+  m_state_builder->remote_journaler->start_live_replay(m_remote_replay_handler,
+                                                       poll_seconds);
 
   notify_status_updated();
 }
@@ -489,10 +493,11 @@ void Replayer<I>::close_local_image() {
   // NOTE: it's important to ensure that the local image is fully
   // closed before attempting to close the remote journal in
   // case the remote cluster is unreachable
+  ceph_assert(m_state_builder->local_image_ctx != nullptr);
   auto ctx = create_context_callback<
     Replayer<I>, &Replayer<I>::handle_close_local_image>(this);
   auto request = image_replayer::CloseImageRequest<I>::create(
-    m_local_image_ctx, ctx);
+    &m_state_builder->local_image_ctx, ctx);
   request->send();
 }
 
@@ -507,7 +512,7 @@ void Replayer<I>::handle_close_local_image(int r) {
     handle_replay_error(r, "failed to close local image");
   }
 
-  ceph_assert(*m_local_image_ctx == nullptr);
+  ceph_assert(m_state_builder->local_image_ctx == nullptr);
   stop_remote_journaler_replay();
 }
 
@@ -515,11 +520,11 @@ template <typename I>
 void Replayer<I>::stop_remote_journaler_replay() {
   ceph_assert(ceph_mutex_is_locked_by_me(m_lock));
 
-  if (m_remote_journaler == nullptr) {
+  if (m_state_builder->remote_journaler == nullptr) {
     wait_for_in_flight_ops();
     return;
   } else if (m_remote_replay_handler == nullptr) {
-    shut_down_remote_journaler();
+    wait_for_in_flight_ops();
     return;
   }
 
@@ -527,7 +532,7 @@ void Replayer<I>::stop_remote_journaler_replay() {
   auto ctx = create_async_context_callback(
     m_threads->work_queue, create_context_callback<
       Replayer<I>, &Replayer<I>::handle_stop_remote_journaler_replay>(this));
-  m_remote_journaler->stop_replay(ctx);
+  m_state_builder->remote_journaler->stop_replay(ctx);
 }
 
 template <typename I>
@@ -544,45 +549,18 @@ void Replayer<I>::handle_stop_remote_journaler_replay(int r) {
   delete m_remote_replay_handler;
   m_remote_replay_handler = nullptr;
 
-  shut_down_remote_journaler();
+  wait_for_in_flight_ops();
 }
 
 template <typename I>
-void Replayer<I>::shut_down_remote_journaler() {
-  ceph_assert(ceph_mutex_is_locked_by_me(m_lock));
-
+void Replayer<I>::wait_for_in_flight_ops() {
   dout(10) << dendl;
   if (m_remote_listener != nullptr) {
-    m_remote_journaler->remove_listener(m_remote_listener);
+    m_state_builder->remote_journaler->remove_listener(m_remote_listener);
     delete m_remote_listener;
     m_remote_listener = nullptr;
   }
 
-  auto ctx = create_context_callback<
-    Replayer, &Replayer<I>::handle_shut_down_remote_journaler>(this);
-  m_remote_journaler->shut_down(ctx);
-}
-
-template <typename I>
-void Replayer<I>::handle_shut_down_remote_journaler(int r) {
-  dout(10) << "r=" << r << dendl;
-  if (r < 0) {
-    derr << "failed to shut down remote journaler: " << cpp_strerror(r)
-         << dendl;
-
-    std::unique_lock locker{m_lock};
-    handle_replay_error(r, "failed to shut down remote journaler");
-  }
-
-  m_remote_journaler = nullptr;
-
-  wait_for_in_flight_ops();
-}
-
-template <typename I>
-void Replayer<I>::wait_for_in_flight_ops() {
-  dout(10) << dendl;
-
   auto ctx = create_async_context_callback(
     m_threads->work_queue, create_context_callback<
       Replayer<I>, &Replayer<I>::handle_wait_for_in_flight_ops>(this));
@@ -616,8 +594,8 @@ void Replayer<I>::handle_remote_journal_metadata_updated() {
   }
 
   cls::journal::Client remote_client;
-  int r = m_remote_journaler->get_cached_client(m_local_mirror_uuid,
-                                                &remote_client);
+  int r = m_state_builder->remote_journaler->get_cached_client(
+    m_local_mirror_uuid, &remote_client);
   if (r < 0) {
     derr << "failed to retrieve client: " << cpp_strerror(r) << dendl;
     return;
@@ -729,7 +707,7 @@ void Replayer<I>::flush_commit_position(Context* on_flush) {
     [this, on_flush](int r) {
       handle_flush_commit_position(on_flush, r);
     });
-  m_remote_journaler->flush_commit_position(ctx);
+  m_state_builder->remote_journaler->flush_commit_position(ctx);
 }
 
 template <typename I>
@@ -807,7 +785,8 @@ void Replayer<I>::handle_replay_ready(
     return;
   }
 
-  if (!m_remote_journaler->try_pop_front(&m_replay_entry, &m_replay_tag_tid)) {
+  if (!m_state_builder->remote_journaler->try_pop_front(&m_replay_entry,
+                                                        &m_replay_tag_tid)) {
     dout(20) << "no entries ready for replay" << dendl;
     return;
   }
@@ -881,7 +860,8 @@ void Replayer<I>::get_remote_tag() {
 
   Context *ctx = create_context_callback<
     Replayer, &Replayer<I>::handle_get_remote_tag>(this);
-  m_remote_journaler->get_tag(m_replay_tag_tid, &m_replay_tag, ctx);
+  m_state_builder->remote_journaler->get_tag(m_replay_tag_tid, &m_replay_tag,
+                                             ctx);
 }
 
 template <typename I>
@@ -918,7 +898,7 @@ void Replayer<I>::allocate_local_tag() {
 
   std::string mirror_uuid = m_replay_tag_data.mirror_uuid;
   if (mirror_uuid == librbd::Journal<>::LOCAL_MIRROR_UUID) {
-    mirror_uuid = m_remote_mirror_uuid;
+    mirror_uuid = m_state_builder->remote_mirror_uuid;
   } else if (mirror_uuid == m_local_mirror_uuid) {
     mirror_uuid = librbd::Journal<>::LOCAL_MIRROR_UUID;
   } else if (mirror_uuid == librbd::Journal<>::ORPHAN_MIRROR_UUID) {
@@ -942,7 +922,7 @@ void Replayer<I>::allocate_local_tag() {
 
   librbd::journal::TagPredecessor predecessor(m_replay_tag_data.predecessor);
   if (predecessor.mirror_uuid == librbd::Journal<>::LOCAL_MIRROR_UUID) {
-    predecessor.mirror_uuid = m_remote_mirror_uuid;
+    predecessor.mirror_uuid = m_state_builder->remote_mirror_uuid;
   } else if (predecessor.mirror_uuid == m_local_mirror_uuid) {
     predecessor.mirror_uuid = librbd::Journal<>::LOCAL_MIRROR_UUID;
   }
@@ -986,7 +966,8 @@ void Replayer<I>::preprocess_entry() {
 
   m_replay_bytes = data.length();
   uint32_t delay = calculate_replay_delay(
-    m_event_entry.timestamp, (*m_local_image_ctx)->mirroring_replay_delay);
+    m_event_entry.timestamp,
+    m_state_builder->local_image_ctx->mirroring_replay_delay);
   if (delay == 0) {
     handle_preprocess_entry_ready(0);
     return;
@@ -1076,7 +1057,7 @@ void Replayer<I>::handle_process_entry_ready(int r) {
 
   bool update_status = false;
   {
-    auto local_image_ctx = *m_local_image_ctx;
+    auto local_image_ctx = m_state_builder->local_image_ctx;
     std::shared_lock image_locker{local_image_ctx->image_lock};
     auto image_spec = util::compute_image_spec(local_image_ctx->md_ctx,
                                                local_image_ctx->name);
@@ -1107,8 +1088,8 @@ void Replayer<I>::handle_process_entry_safe(
     derr << "failed to commit journal event: " << cpp_strerror(r) << dendl;
     handle_replay_complete(r, "failed to commit journal event");
   } else {
-    ceph_assert(m_remote_journaler != nullptr);
-    m_remote_journaler->committed(replay_entry);
+    ceph_assert(m_state_builder->remote_journaler != nullptr);
+    m_state_builder->remote_journaler->committed(replay_entry);
   }
 
   auto latency = ceph_clock_now() - replay_start_time;
@@ -1191,7 +1172,7 @@ int Replayer<I>::validate_remote_client_state(
     return -EBADMSG;
   }
 
-  auto local_image_ctx = *m_local_image_ctx;
+  auto local_image_ctx = m_state_builder->local_image_ctx;
   dout(5) << "image_id=" << local_image_ctx->id << ", "
           << "remote_client_meta.image_id="
           << remote_client_meta->image_id << ", "
@@ -1222,7 +1203,7 @@ void Replayer<I>::register_perf_counters() {
   ceph_assert(ceph_mutex_is_locked_by_me(m_lock));
   ceph_assert(m_perf_counters == nullptr);
 
-  auto cct = static_cast<CephContext *>((*m_local_image_ctx)->cct);
+  auto cct = static_cast<CephContext *>(m_state_builder->local_image_ctx->cct);
   auto prio = cct->_conf.get_val<int64_t>("rbd_mirror_image_perf_stats_prio");
   PerfCountersBuilder plb(g_ceph_context, "rbd_mirror_image_" + m_image_spec,
                           l_rbd_mirror_first, l_rbd_mirror_last);
index af22b145c41def47a534bddc8a8522bdff7e4737..90ef61022331ed54206a26d3874e911fc19eab05 100644 (file)
@@ -36,29 +36,29 @@ struct ReplayerListener;
 
 namespace journal {
 
-template <typename I> class EventPreprocessor;
-template <typename I> class ReplayStatusFormatter;
+template <typename> class EventPreprocessor;
+template <typename> class ReplayStatusFormatter;
+template <typename> class StateBuilder;
 
 template <typename ImageCtxT>
 class Replayer : public image_replayer::Replayer {
 public:
   typedef typename librbd::journal::TypeTraits<ImageCtxT>::Journaler Journaler;
 
-  static Replayer* create(ImageCtxT** local_image_ctx,
-                          Journaler* remote_journaler,
-                          const std::string& local_mirror_uuid,
-                          const std::string& remote_mirror_uuid,
-                          ReplayerListener* replayer_listener,
-                          Threads<ImageCtxT>* threads) {
-    return new Replayer(local_image_ctx, remote_journaler, local_mirror_uuid,
-                        remote_mirror_uuid, replayer_listener, threads);
+  static Replayer* create(
+      Threads<ImageCtxT>* threads,
+      const std::string& local_mirror_uuid,
+      StateBuilder<ImageCtxT>* state_builder,
+      ReplayerListener* replayer_listener) {
+    return new Replayer(threads, local_mirror_uuid, state_builder,
+                        replayer_listener);
   }
 
   Replayer(
-      ImageCtxT** local_image_ctx, Journaler* remote_journaler,
+      Threads<ImageCtxT>* threads,
       const std::string& local_mirror_uuid,
-      const std::string& remote_mirror_uuid,
-      ReplayerListener* replayer_listener, Threads<ImageCtxT>* threads);
+      StateBuilder<ImageCtxT>* state_builder,
+      ReplayerListener* replayer_listener);
   ~Replayer();
 
   void destroy() override {
@@ -156,9 +156,6 @@ private:
    *    v (skip if not started)
    * STOP_REMOTE_JOURNALER_REPLAY
    *    |
-   *    v (skip if not initialized)
-   * SHUT_DOWN_REMOTE_JOURNALER
-   *    |
    *    v
    * WAIT_FOR_IN_FLIGHT_OPS
    *    |
@@ -182,12 +179,10 @@ private:
   struct RemoteReplayHandler;
   struct LocalJournalListener;
 
-  ImageCtxT** m_local_image_ctx;
-  Journaler* m_remote_journaler;
+  Threads<ImageCtxT>* m_threads;
   std::string m_local_mirror_uuid;
-  std::string m_remote_mirror_uuid;
+  StateBuilder<ImageCtxT>* m_state_builder;
   ReplayerListener* m_replayer_listener;
-  Threads<ImageCtxT>* m_threads;
 
   mutable ceph::mutex m_lock;
 
@@ -202,7 +197,6 @@ private:
   ceph::ref_t<typename std::remove_pointer<decltype(ImageCtxT::journal)>::type>
     m_local_journal;
   RemoteJournalerListener* m_remote_listener = nullptr;
-  librbd::journal::MirrorPeerClientMeta m_remote_client_meta;
 
   librbd::journal::Replay<ImageCtxT>* m_local_journal_replay = nullptr;
   EventPreprocessor<ImageCtxT>* m_event_preprocessor = nullptr;
@@ -259,9 +253,6 @@ private:
   void stop_remote_journaler_replay();
   void handle_stop_remote_journaler_replay(int r);
 
-  void shut_down_remote_journaler();
-  void handle_shut_down_remote_journaler(int r);
-
   void wait_for_in_flight_ops();
   void handle_wait_for_in_flight_ops(int r);
 
index a0f85f0a1167871efad1c58b70f3bc06f33f4d6b..ed1cf6911ed2772ca509243dcb42f5b41bf8cab7 100644 (file)
@@ -87,9 +87,8 @@ BaseRequest* StateBuilder<I>::create_local_image_request(
     ProgressContext* progress_ctx,
     Context* on_finish) {
   return CreateLocalImageRequest<I>::create(
-    threads, local_io_ctx, remote_image_ctx, remote_journaler,
-    this->global_image_id, this->remote_mirror_uuid, &remote_client_meta,
-    progress_ctx, &this->local_image_id, on_finish);
+    threads, local_io_ctx, remote_image_ctx, this->global_image_id,
+    progress_ctx, this, on_finish);
 }
 
 template <typename I>
@@ -101,16 +100,8 @@ BaseRequest* StateBuilder<I>::create_prepare_replay_request(
     bool* syncing,
     Context* on_finish) {
   return PrepareReplayRequest<I>::create(
-    this->local_image_ctx,
-    remote_journaler,
-    remote_promotion_state,
-    local_mirror_uuid,
-    this->remote_mirror_uuid,
-    &remote_client_meta,
-    progress_ctx,
-    resync_requested,
-    syncing,
-    on_finish);
+    local_mirror_uuid, remote_promotion_state, progress_ctx, this,
+    resync_requested, syncing, on_finish);
 }
 
 template <typename I>
@@ -119,12 +110,7 @@ image_replayer::Replayer* StateBuilder<I>::create_replayer(
     const std::string& local_mirror_uuid,
     ReplayerListener* replayer_listener) {
   return Replayer<I>::create(
-    &this->local_image_ctx,
-    remote_journaler,
-    local_mirror_uuid,
-    this->remote_mirror_uuid,
-    replayer_listener,
-    threads);
+    threads, local_mirror_uuid, this, replayer_listener);
 }
 
 template <typename I>
index 274c2acbcb8fae4a38193ae94e9aaf0b308afb35..c760a66ce26c2b79ff145f70ad6391fe3f362e88 100644 (file)
@@ -61,7 +61,7 @@ public:
       bool* syncing,
       Context* on_finish) override;
 
-  Replayer* create_replayer(
+  image_replayer::Replayer* create_replayer(
       Threads<ImageCtxT>* threads,
       const std::string& local_mirror_uuid,
       ReplayerListener* replayer_listener) override;