]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
rbd-mirror: keep remote image open after bootstrap for snapshot mirroring
authorJason Dillaman <dillaman@redhat.com>
Thu, 6 Feb 2020 15:52:29 +0000 (10:52 -0500)
committerJason Dillaman <dillaman@redhat.com>
Wed, 19 Feb 2020 15:36:40 +0000 (10:36 -0500)
The snapshot-based mirroring requires an open remote image to watch for
snapshot creation and to handle the deep-copy from remote to local image.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc
src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc
src/tools/rbd_mirror/image_replayer/StateBuilder.h
src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.cc
src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h

index a6114e7d4cc5f49f7c4c731f60a0bb0669e938db..049187fcf78b57f90f13043682221d1feeeedb37 100644 (file)
@@ -234,6 +234,7 @@ struct StateBuilder<librbd::MockTestImageCtx> {
   MOCK_CONST_METHOD0(is_local_primary, bool());
   MOCK_CONST_METHOD0(is_linked, bool());
 
+  MOCK_CONST_METHOD0(replay_requires_remote_image, bool());
   MOCK_METHOD1(close_remote_image, void(Context*));
 
   MOCK_METHOD6(create_local_image_request,
@@ -360,6 +361,12 @@ public:
       .WillOnce(Return(is_disconnected));
   }
 
+  void expect_replay_requires_remote_image(MockStateBuilder& mock_state_builder,
+                                           bool requires_image) {
+    EXPECT_CALL(mock_state_builder, replay_requires_remote_image())
+      .WillOnce(Return(requires_image));
+  }
+
   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) {
@@ -503,6 +510,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, Success) {
   expect_is_disconnected(mock_state_builder, false);
 
   // close remote image
+  expect_replay_requires_remote_image(mock_state_builder, false);
   expect_close_remote_image(mock_state_builder, 0);
 
   C_SaferCond ctx;
@@ -544,6 +552,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, OpenLocalImageError) {
                           -EINVAL);
 
   // close remote image
+  expect_replay_requires_remote_image(mock_state_builder, false);
   expect_close_remote_image(mock_state_builder, 0);
 
   C_SaferCond ctx;
@@ -596,6 +605,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, OpenLocalImageDNE) {
   expect_is_disconnected(mock_state_builder, false);
 
   // close remote image
+  expect_replay_requires_remote_image(mock_state_builder, false);
   expect_close_remote_image(mock_state_builder, 0);
 
   C_SaferCond ctx;
@@ -637,6 +647,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, OpenLocalImagePrimary) {
                           -EREMOTEIO);
 
   // close remote image
+  expect_replay_requires_remote_image(mock_state_builder, false);
   expect_close_remote_image(mock_state_builder, 0);
 
   C_SaferCond ctx;
@@ -674,6 +685,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, CreateLocalImageError) {
   expect_create_local_image(mock_state_builder, "local image id", -EINVAL);
 
   // close remote image
+  expect_replay_requires_remote_image(mock_state_builder, false);
   expect_close_remote_image(mock_state_builder, 0);
 
   C_SaferCond ctx;
@@ -717,6 +729,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplayError) {
   expect_prepare_replay(mock_state_builder, false, false, -EINVAL);
 
   // close remote image
+  expect_replay_requires_remote_image(mock_state_builder, false);
   expect_close_remote_image(mock_state_builder, 0);
 
   C_SaferCond ctx;
@@ -760,6 +773,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplayResyncRequested) {
   expect_prepare_replay(mock_state_builder, true, false, 0);
 
   // close remote image
+  expect_replay_requires_remote_image(mock_state_builder, false);
   expect_close_remote_image(mock_state_builder, 0);
 
   C_SaferCond ctx;
@@ -809,6 +823,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplaySyncing) {
   expect_image_sync(mock_image_sync, 0);
 
   // close remote image
+  expect_replay_requires_remote_image(mock_state_builder, false);
   expect_close_remote_image(mock_state_builder, 0);
 
   C_SaferCond ctx;
@@ -853,6 +868,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplayDisconnected) {
   expect_is_disconnected(mock_state_builder, false);
 
   // close remote image
+  expect_replay_requires_remote_image(mock_state_builder, false);
   expect_close_remote_image(mock_state_builder, 0);
 
   C_SaferCond ctx;
@@ -901,6 +917,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, ImageSyncError) {
   expect_image_sync(mock_image_sync, -EINVAL);
 
   // close remote image
+  expect_replay_requires_remote_image(mock_state_builder, false);
   expect_close_remote_image(mock_state_builder, 0);
 
   C_SaferCond ctx;
@@ -945,6 +962,7 @@ TEST_F(TestMockImageReplayerBootstrapRequest, ImageSyncCanceled) {
   expect_is_disconnected(mock_state_builder, false);
 
   // close remote image
+  expect_replay_requires_remote_image(mock_state_builder, false);
   expect_close_remote_image(mock_state_builder, 0);
 
   C_SaferCond ctx;
@@ -989,6 +1007,8 @@ TEST_F(TestMockImageReplayerBootstrapRequest, CloseRemoteImageError) {
   expect_prepare_replay(mock_state_builder, false, false, 0);
   expect_is_disconnected(mock_state_builder, false);
 
+  // attempt to close remote image
+  expect_replay_requires_remote_image(mock_state_builder, false);
   expect_close_remote_image(mock_state_builder, -EINVAL);
 
   C_SaferCond ctx;
@@ -1001,6 +1021,50 @@ TEST_F(TestMockImageReplayerBootstrapRequest, CloseRemoteImageError) {
   ASSERT_EQ(0, ctx.wait());
 }
 
+TEST_F(TestMockImageReplayerBootstrapRequest, ReplayRequiresRemoteImage) {
+  InSequence seq;
+
+  // prepare local image
+  MockPrepareLocalImageRequest mock_prepare_local_image_request;
+  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;
+  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::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);
+
+  // open the local image
+  librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+  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
+  expect_prepare_replay(mock_state_builder, false, false, 0);
+  expect_is_disconnected(mock_state_builder, false);
+
+  // remote image is left open
+  expect_replay_requires_remote_image(mock_state_builder, true);
+
+  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(0, ctx.wait());
+}
+
 } // namespace image_replayer
 } // namespace mirror
 } // namespace rbd
index b41f71f64469dec5bed54906fcae046af557b395..41a3af62367d1042d4a51624d1537b9c2f1eafd3 100644 (file)
@@ -418,6 +418,11 @@ void BootstrapRequest<I>::handle_image_sync(int r) {
 
 template <typename I>
 void BootstrapRequest<I>::close_remote_image() {
+  if ((*m_state_builder)->replay_requires_remote_image()) {
+    finish(m_ret_val);
+    return;
+  }
+
   dout(15) << dendl;
 
   update_progress("CLOSE_REMOTE_IMAGE");
index 9386b01c99e547ca126267ae876d623cff539a9f..b51a0dea8f2064dda08745f172a06e2e876e4274 100644 (file)
@@ -50,6 +50,10 @@ public:
   virtual image_sync::SyncPointHandler* create_sync_point_handler() = 0;
   void destroy_sync_point_handler();
 
+  virtual bool replay_requires_remote_image() const {
+    return false;
+  }
+
   void close_remote_image(Context* on_finish);
 
   virtual BaseRequest* create_local_image_request(
index 78fe861b4a13f1bda2afc4ebeb9580c42248cb0c..5475cf408e4ff8245adaa4bc8e682cf6f163f495 100644 (file)
@@ -36,6 +36,12 @@ template <typename I>
 void StateBuilder<I>::close(Context* on_finish) {
   dout(10) << dendl;
 
+  // close the remote image after closing the local
+  // image in case the remote cluster is unreachable and
+  // we cannot close it.
+  on_finish = new LambdaContext([this, on_finish](int) {
+      this->close_remote_image(on_finish);
+    });
   this->close_local_image(on_finish);
 }
 
index d0604e4dfd6dfd539a979c73fe25265cb6a9ad6c..f815ebad1e9970aab814c8c5529885711c6dce16 100644 (file)
@@ -37,6 +37,10 @@ public:
 
   image_sync::SyncPointHandler* create_sync_point_handler() override;
 
+  bool replay_requires_remote_image() const override {
+    return true;
+  }
+
   BaseRequest* create_local_image_request(
       Threads<ImageCtxT>* threads,
       librados::IoCtx& local_io_ctx,