From: Jason Dillaman Date: Thu, 6 Feb 2020 15:52:29 +0000 (-0500) Subject: rbd-mirror: keep remote image open after bootstrap for snapshot mirroring X-Git-Tag: v15.1.1~350^2~5 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=a767d267dabee5896e12dccb6d555087886139dd;p=ceph-ci.git rbd-mirror: keep remote image open after bootstrap for snapshot mirroring 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 --- diff --git a/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc b/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc index a6114e7d4cc..049187fcf78 100644 --- a/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc +++ b/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc @@ -234,6 +234,7 @@ struct StateBuilder { 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 diff --git a/src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc b/src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc index b41f71f6446..41a3af62367 100644 --- a/src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc +++ b/src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc @@ -418,6 +418,11 @@ void BootstrapRequest::handle_image_sync(int r) { template void BootstrapRequest::close_remote_image() { + if ((*m_state_builder)->replay_requires_remote_image()) { + finish(m_ret_val); + return; + } + dout(15) << dendl; update_progress("CLOSE_REMOTE_IMAGE"); diff --git a/src/tools/rbd_mirror/image_replayer/StateBuilder.h b/src/tools/rbd_mirror/image_replayer/StateBuilder.h index 9386b01c99e..b51a0dea8f2 100644 --- a/src/tools/rbd_mirror/image_replayer/StateBuilder.h +++ b/src/tools/rbd_mirror/image_replayer/StateBuilder.h @@ -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( diff --git a/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.cc b/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.cc index 78fe861b4a1..5475cf408e4 100644 --- a/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.cc +++ b/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.cc @@ -36,6 +36,12 @@ template void StateBuilder::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); } diff --git a/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h b/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h index d0604e4dfd6..f815ebad1e9 100644 --- a/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h +++ b/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h @@ -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* threads, librados::IoCtx& local_io_ctx,