From d8e3a5570422ea332866aaa8d608cc7aa7b6b516 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Thu, 13 Feb 2020 21:40:21 -0500 Subject: [PATCH] rbd-mirror: snapshot-based image replayer now applies image state Additionally, the image state will be re-read from the local cluster if the sync was interrupted. Signed-off-by: Jason Dillaman --- .../snapshot/test_mock_Replayer.cc | 51 +++- src/test/rbd_mirror/test_ImageReplayer.cc | 261 ++++++++++++++++++ .../image_replayer/snapshot/Replayer.cc | 82 +++++- .../image_replayer/snapshot/Replayer.h | 18 +- 4 files changed, 398 insertions(+), 14 deletions(-) diff --git a/src/test/rbd_mirror/image_replayer/snapshot/test_mock_Replayer.cc b/src/test/rbd_mirror/image_replayer/snapshot/test_mock_Replayer.cc index fa6018087c4..36250bdf59c 100644 --- a/src/test/rbd_mirror/image_replayer/snapshot/test_mock_Replayer.cc +++ b/src/test/rbd_mirror/image_replayer/snapshot/test_mock_Replayer.cc @@ -11,6 +11,7 @@ #include "tools/rbd_mirror/image_replayer/CloseImageRequest.h" #include "tools/rbd_mirror/image_replayer/ReplayerListener.h" #include "tools/rbd_mirror/image_replayer/Utils.h" +#include "tools/rbd_mirror/image_replayer/snapshot/ApplyImageStateRequest.h" #include "tools/rbd_mirror/image_replayer/snapshot/Replayer.h" #include "tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h" #include "test/librados_test_stub/MockTestMemIoCtxImpl.h" @@ -268,6 +269,30 @@ CloseImageRequest* CloseImageRequest +struct ApplyImageStateRequest { + Context* on_finish = nullptr; + + static ApplyImageStateRequest* s_instance; + static ApplyImageStateRequest* create( + const std::string& local_mirror_uuid, + const std::string& remote_mirror_uuid, + librbd::MockTestImageCtx* local_image_ctx, + librbd::MockTestImageCtx* remote_image_ctx, + const librbd::mirror::snapshot::ImageState& image_state, + Context* on_finish) { + ceph_assert(s_instance != nullptr); + s_instance->on_finish = on_finish; + return s_instance; + } + + ApplyImageStateRequest() { + s_instance = this; + } + + MOCK_METHOD0(send, void()); +}; + template<> struct StateBuilder { StateBuilder(librbd::MockTestImageCtx& local_image_ctx, @@ -282,6 +307,8 @@ struct StateBuilder { std::string remote_mirror_uuid = "remote mirror uuid"; }; +ApplyImageStateRequest* ApplyImageStateRequest::s_instance = nullptr; + } // namespace snapshot } // namespace image_replayer } // namespace mirror @@ -306,6 +333,7 @@ using ::testing::WithArg; class TestMockImageReplayerSnapshotReplayer : public TestMockFixture { public: typedef Replayer MockReplayer; + typedef ApplyImageStateRequest MockApplyImageStateRequest; typedef StateBuilder MockStateBuilder; typedef Threads MockThreads; typedef CloseImageRequest MockCloseImageRequest; @@ -469,6 +497,14 @@ public: })); } + void expect_apply_image_state( + MockApplyImageStateRequest& mock_request, int r) { + EXPECT_CALL(mock_request, send()) + .WillOnce(Invoke([this, &req=mock_request, r]() { + m_threads->work_queue->queue(req.on_finish, r); + })); + } + void expect_mirror_image_snapshot_set_copy_progress( librbd::MockTestImageCtx& mock_test_image_ctx, uint64_t snap_id, bool completed, uint64_t last_copied_object, int r) { @@ -648,6 +684,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SyncSnapshot) { MockImageCopyRequest mock_image_copy_request; expect_image_copy(mock_image_copy_request, 0, 1, 0, {}, {{1, CEPH_NOSNAP}}, 0); + MockApplyImageStateRequest mock_apply_state_request; + expect_apply_image_state(mock_apply_state_request, 0); expect_mirror_image_snapshot_set_copy_progress( mock_local_image_ctx, 11, true, 0, 0); expect_notify_update(mock_local_image_ctx); @@ -670,10 +708,11 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SyncSnapshot) { {{1, 11}, {4, CEPH_NOSNAP}}, 14, 0); expect_image_copy(mock_image_copy_request, 1, 4, 11, {}, {{1, 11}, {4, CEPH_NOSNAP}}, 0); - MockUnlinkPeerRequest mock_unlink_peer_request; + expect_apply_image_state(mock_apply_state_request, 0); expect_mirror_image_snapshot_set_copy_progress( mock_local_image_ctx, 14, true, 0, 0); expect_notify_update(mock_local_image_ctx); + MockUnlinkPeerRequest mock_unlink_peer_request; expect_unlink_peer(mock_unlink_peer_request, 1, "remote mirror peer uuid", 0); @@ -748,10 +787,14 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSync) { // re-sync snap1 expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + MockGetImageStateRequest mock_get_image_state_request; + expect_get_image_state(mock_get_image_state_request, 11, 0); MockImageCopyRequest mock_image_copy_request; expect_image_copy(mock_image_copy_request, 0, 1, 0, librbd::deep_copy::ObjectNumber{123U}, {{1, CEPH_NOSNAP}}, 0); + MockApplyImageStateRequest mock_apply_state_request; + expect_apply_image_state(mock_apply_state_request, 0); expect_mirror_image_snapshot_set_copy_progress( mock_local_image_ctx, 11, true, 123, 0); expect_notify_update(mock_local_image_ctx); @@ -827,6 +870,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteImageDemoted) { MockImageCopyRequest mock_image_copy_request; expect_image_copy(mock_image_copy_request, 0, 1, 0, {}, {{1, CEPH_NOSNAP}}, 0); + MockApplyImageStateRequest mock_apply_state_request; + expect_apply_image_state(mock_apply_state_request, 0); expect_mirror_image_snapshot_set_copy_progress( mock_local_image_ctx, 11, true, 0, 0); expect_notify_update(mock_local_image_ctx); @@ -1342,6 +1387,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UpdateNonPrimarySnapshotError) { MockImageCopyRequest mock_image_copy_request; expect_image_copy(mock_image_copy_request, 0, 1, 0, {}, {{1, CEPH_NOSNAP}}, 0); + MockApplyImageStateRequest mock_apply_state_request; + expect_apply_image_state(mock_apply_state_request, 0); expect_mirror_image_snapshot_set_copy_progress( mock_local_image_ctx, 11, true, 0, -EINVAL); @@ -1416,6 +1463,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnlinkPeerError) { MockImageCopyRequest mock_image_copy_request; expect_image_copy(mock_image_copy_request, 1, 2, 11, {}, {{2, CEPH_NOSNAP}}, 0); + MockApplyImageStateRequest mock_apply_state_request; + expect_apply_image_state(mock_apply_state_request, 0); expect_mirror_image_snapshot_set_copy_progress( mock_local_image_ctx, 12, true, 0, 0); expect_notify_update(mock_local_image_ctx); diff --git a/src/test/rbd_mirror/test_ImageReplayer.cc b/src/test/rbd_mirror/test_ImageReplayer.cc index caa2daa4f9c..fcd8db6da4e 100644 --- a/src/test/rbd_mirror/test_ImageReplayer.cc +++ b/src/test/rbd_mirror/test_ImageReplayer.cc @@ -31,6 +31,7 @@ #include "librbd/Utils.h" #include "librbd/internal.h" #include "librbd/api/Mirror.h" +#include "librbd/api/Snapshot.h" #include "librbd/io/AioCompletion.h" #include "librbd/io/ImageRequestWQ.h" #include "librbd/io/ReadResult.h" @@ -112,6 +113,9 @@ public: m_remote_ioctx)); m_remote_ioctx.application_enable("rbd", true); + // make snap id debugging easier when local/remote have different mappings + uint64_t snap_id; + EXPECT_EQ(0, m_remote_ioctx.selfmanaged_snap_create(&snap_id)); uint64_t features = librbd::util::get_rbd_default_features(g_ceph_context); if (MIRROR_IMAGE_MODE == cls::rbd::MIRROR_IMAGE_MODE_JOURNAL) { @@ -1376,5 +1380,262 @@ TEST_F(TestImageReplayerJournal, MirroringDelay) this->stop(); } +TYPED_TEST(TestImageReplayer, ImageRename) { + this->create_replayer(); + this->start(); + + librbd::ImageCtx* remote_image_ctx = nullptr; + this->open_remote_image(&remote_image_ctx); + auto image_name = this->get_temp_image_name(); + ASSERT_EQ(0, remote_image_ctx->operations->rename(image_name.c_str())); + this->flush(remote_image_ctx); + + this->wait_for_replay_complete(); + + librbd::ImageCtx* local_image_ctx = nullptr; + this->open_image(this->m_local_ioctx, image_name, true, &local_image_ctx); + ASSERT_EQ(image_name, local_image_ctx->name); + + this->close_image(local_image_ctx); + this->close_image(remote_image_ctx); + this->stop(); +} + +TYPED_TEST(TestImageReplayer, UpdateFeatures) { + librbd::ImageCtx* remote_image_ctx = nullptr; + this->open_remote_image(&remote_image_ctx); + + ASSERT_EQ(0, remote_image_ctx->operations->update_features( + (RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF), false)); + this->flush(remote_image_ctx); + + this->create_replayer(); + this->start(); + this->wait_for_replay_complete(); + + librbd::ImageCtx* local_image_ctx = nullptr; + this->open_local_image(&local_image_ctx); + ASSERT_EQ(0U, local_image_ctx->features & ( + RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF)); + + // enable object-map/fast-diff + ASSERT_EQ(0, remote_image_ctx->operations->update_features( + (RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF), true)); + this->flush(remote_image_ctx); + this->wait_for_replay_complete(); + + ASSERT_EQ(0, local_image_ctx->state->refresh()); + ASSERT_EQ(RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF, + local_image_ctx->features & ( + RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF)); + + // disable deep-flatten + ASSERT_EQ(0, remote_image_ctx->operations->update_features( + RBD_FEATURE_DEEP_FLATTEN, false)); + this->flush(remote_image_ctx); + this->wait_for_replay_complete(); + + ASSERT_EQ(0, local_image_ctx->state->refresh()); + ASSERT_EQ(0, local_image_ctx->features & RBD_FEATURE_DEEP_FLATTEN); + + this->close_image(local_image_ctx); + this->close_image(remote_image_ctx); + this->stop(); +} + +TYPED_TEST(TestImageReplayer, SnapshotUnprotect) { + librbd::ImageCtx* remote_image_ctx = nullptr; + this->open_remote_image(&remote_image_ctx); + + // create a protected snapshot + ASSERT_EQ(0, remote_image_ctx->operations->snap_create( + cls::rbd::UserSnapshotNamespace{}, "snap1")); + ASSERT_EQ(0, remote_image_ctx->operations->snap_protect( + cls::rbd::UserSnapshotNamespace{}, "snap1")); + this->flush(remote_image_ctx); + + this->create_replayer(); + this->start(); + this->wait_for_replay_complete(); + + librbd::ImageCtx* local_image_ctx = nullptr; + this->open_local_image(&local_image_ctx); + auto local_snap_id_it = local_image_ctx->snap_ids.find({ + {cls::rbd::UserSnapshotNamespace{}}, "snap1"}); + ASSERT_NE(local_image_ctx->snap_ids.end(), local_snap_id_it); + auto local_snap_id = local_snap_id_it->second; + auto local_snap_info_it = local_image_ctx->snap_info.find(local_snap_id); + ASSERT_NE(local_image_ctx->snap_info.end(), local_snap_info_it); + ASSERT_EQ(RBD_PROTECTION_STATUS_PROTECTED, + local_snap_info_it->second.protection_status); + + // unprotect the snapshot + ASSERT_EQ(0, remote_image_ctx->operations->snap_unprotect( + cls::rbd::UserSnapshotNamespace{}, "snap1")); + this->flush(remote_image_ctx); + this->wait_for_replay_complete(); + + ASSERT_EQ(0, local_image_ctx->state->refresh()); + local_snap_info_it = local_image_ctx->snap_info.find(local_snap_id); + ASSERT_NE(local_image_ctx->snap_info.end(), local_snap_info_it); + ASSERT_EQ(RBD_PROTECTION_STATUS_UNPROTECTED, + local_snap_info_it->second.protection_status); + + this->close_image(local_image_ctx); + this->close_image(remote_image_ctx); + this->stop(); +} + +TYPED_TEST(TestImageReplayer, SnapshotProtect) { + librbd::ImageCtx* remote_image_ctx = nullptr; + this->open_remote_image(&remote_image_ctx); + + // create an unprotected snapshot + ASSERT_EQ(0, remote_image_ctx->operations->snap_create( + cls::rbd::UserSnapshotNamespace{}, "snap1")); + this->flush(remote_image_ctx); + + this->create_replayer(); + this->start(); + this->wait_for_replay_complete(); + + librbd::ImageCtx* local_image_ctx = nullptr; + this->open_local_image(&local_image_ctx); + auto local_snap_id_it = local_image_ctx->snap_ids.find({ + {cls::rbd::UserSnapshotNamespace{}}, "snap1"}); + ASSERT_NE(local_image_ctx->snap_ids.end(), local_snap_id_it); + auto local_snap_id = local_snap_id_it->second; + auto local_snap_info_it = local_image_ctx->snap_info.find(local_snap_id); + ASSERT_NE(local_image_ctx->snap_info.end(), local_snap_info_it); + ASSERT_EQ(RBD_PROTECTION_STATUS_UNPROTECTED, + local_snap_info_it->second.protection_status); + + // protect the snapshot + ASSERT_EQ(0, remote_image_ctx->operations->snap_protect( + cls::rbd::UserSnapshotNamespace{}, "snap1")); + this->flush(remote_image_ctx); + this->wait_for_replay_complete(); + + ASSERT_EQ(0, local_image_ctx->state->refresh()); + local_snap_info_it = local_image_ctx->snap_info.find(local_snap_id); + ASSERT_NE(local_image_ctx->snap_info.end(), local_snap_info_it); + ASSERT_EQ(RBD_PROTECTION_STATUS_PROTECTED, + local_snap_info_it->second.protection_status); + + this->close_image(local_image_ctx); + this->close_image(remote_image_ctx); + this->stop(); +} + +TYPED_TEST(TestImageReplayer, SnapshotRemove) { + librbd::ImageCtx* remote_image_ctx = nullptr; + this->open_remote_image(&remote_image_ctx); + + // create a user snapshot + ASSERT_EQ(0, remote_image_ctx->operations->snap_create( + cls::rbd::UserSnapshotNamespace{}, "snap1")); + this->flush(remote_image_ctx); + + this->create_replayer(); + this->start(); + this->wait_for_replay_complete(); + + librbd::ImageCtx* local_image_ctx = nullptr; + this->open_local_image(&local_image_ctx); + auto local_snap_id_it = local_image_ctx->snap_ids.find({ + {cls::rbd::UserSnapshotNamespace{}}, "snap1"}); + ASSERT_NE(local_image_ctx->snap_ids.end(), local_snap_id_it); + + // remove the snapshot + ASSERT_EQ(0, remote_image_ctx->operations->snap_remove( + cls::rbd::UserSnapshotNamespace{}, "snap1")); + this->flush(remote_image_ctx); + this->wait_for_replay_complete(); + + ASSERT_EQ(0, local_image_ctx->state->refresh()); + local_snap_id_it = local_image_ctx->snap_ids.find({ + {cls::rbd::UserSnapshotNamespace{}}, "snap1"}); + ASSERT_EQ(local_image_ctx->snap_ids.end(), local_snap_id_it); + + this->close_image(local_image_ctx); + this->close_image(remote_image_ctx); + this->stop(); +} + +TYPED_TEST(TestImageReplayer, SnapshotRename) { + librbd::ImageCtx* remote_image_ctx = nullptr; + this->open_remote_image(&remote_image_ctx); + + // create a user snapshot + ASSERT_EQ(0, remote_image_ctx->operations->snap_create( + cls::rbd::UserSnapshotNamespace{}, "snap1")); + this->flush(remote_image_ctx); + + this->create_replayer(); + this->start(); + this->wait_for_replay_complete(); + + librbd::ImageCtx* local_image_ctx = nullptr; + this->open_local_image(&local_image_ctx); + auto local_snap_id_it = local_image_ctx->snap_ids.find({ + {cls::rbd::UserSnapshotNamespace{}}, "snap1"}); + ASSERT_NE(local_image_ctx->snap_ids.end(), local_snap_id_it); + auto local_snap_id = local_snap_id_it->second; + auto local_snap_info_it = local_image_ctx->snap_info.find(local_snap_id); + ASSERT_NE(local_image_ctx->snap_info.end(), local_snap_info_it); + ASSERT_EQ(RBD_PROTECTION_STATUS_UNPROTECTED, + local_snap_info_it->second.protection_status); + + // rename the snapshot + ASSERT_EQ(0, remote_image_ctx->operations->snap_rename( + "snap1", "snap1-renamed")); + this->flush(remote_image_ctx); + this->wait_for_replay_complete(); + + ASSERT_EQ(0, local_image_ctx->state->refresh()); + local_snap_info_it = local_image_ctx->snap_info.find(local_snap_id); + ASSERT_NE(local_image_ctx->snap_info.end(), local_snap_info_it); + ASSERT_EQ("snap1-renamed", local_snap_info_it->second.name); + + this->close_image(local_image_ctx); + this->close_image(remote_image_ctx); + this->stop(); +} + +TYPED_TEST(TestImageReplayer, SnapshotLimit) { + librbd::ImageCtx* remote_image_ctx = nullptr; + this->open_remote_image(&remote_image_ctx); + + this->create_replayer(); + this->start(); + this->wait_for_replay_complete(); + + // update the snap limit + ASSERT_EQ(0, librbd::api::Snapshot<>::set_limit(remote_image_ctx, 123U)); + this->flush(remote_image_ctx); + this->wait_for_replay_complete(); + + librbd::ImageCtx* local_image_ctx = nullptr; + this->open_local_image(&local_image_ctx); + uint64_t local_snap_limit; + ASSERT_EQ(0, librbd::api::Snapshot<>::get_limit(local_image_ctx, + &local_snap_limit)); + ASSERT_EQ(123U, local_snap_limit); + + // update the limit again + ASSERT_EQ(0, librbd::api::Snapshot<>::set_limit( + remote_image_ctx, std::numeric_limits::max())); + this->flush(remote_image_ctx); + this->wait_for_replay_complete(); + + ASSERT_EQ(0, librbd::api::Snapshot<>::get_limit(local_image_ctx, + &local_snap_limit)); + ASSERT_EQ(std::numeric_limits::max(), local_snap_limit); + + this->close_image(local_image_ctx); + this->close_image(remote_image_ctx); + this->stop(); +} + } // namespace mirror } // namespace rbd diff --git a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc index 2af646ca1af..095e2ca2e93 100644 --- a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc +++ b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc @@ -21,6 +21,7 @@ #include "tools/rbd_mirror/image_replayer/CloseImageRequest.h" #include "tools/rbd_mirror/image_replayer/ReplayerListener.h" #include "tools/rbd_mirror/image_replayer/Utils.h" +#include "tools/rbd_mirror/image_replayer/snapshot/ApplyImageStateRequest.h" #include "tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h" #define dout_context g_ceph_context @@ -424,7 +425,7 @@ void Replayer::scan_remote_mirror_snapshots() { // attempt to resume image-sync dout(10) << "local image contains in-progress mirror snapshot" << dendl; - copy_image(); + get_local_image_state(); } else { copy_snapshots(); } @@ -468,7 +469,9 @@ void Replayer::scan_remote_mirror_snapshots() { template void Replayer::copy_snapshots() { - dout(10) << dendl; + dout(10) << "remote_snap_id_start=" << m_remote_snap_id_start << ", " + << "remote_snap_id_end=" << m_remote_snap_id_end << ", " + << "local_snap_id_start=" << m_local_snap_id_start << dendl; ceph_assert(m_remote_snap_id_start != CEPH_NOSNAP); ceph_assert(m_remote_snap_id_end > 0 && @@ -502,15 +505,15 @@ void Replayer::handle_copy_snapshots(int r) { << "remote_snap_id_end=" << m_remote_snap_id_end << ", " << "local_snap_id_start=" << m_local_snap_id_start << ", " << "snap_seqs=" << m_local_mirror_snap_ns.snap_seqs << dendl; - get_image_state(); + get_remote_image_state(); } template -void Replayer::get_image_state() { +void Replayer::get_remote_image_state() { dout(10) << dendl; auto ctx = create_context_callback< - Replayer, &Replayer::handle_get_image_state>(this); + Replayer, &Replayer::handle_get_remote_image_state>(this); auto req = librbd::mirror::snapshot::GetImageStateRequest::create( m_state_builder->remote_image_ctx, m_remote_snap_id_end, &m_image_state, ctx); @@ -518,7 +521,7 @@ void Replayer::get_image_state() { } template -void Replayer::handle_get_image_state(int r) { +void Replayer::handle_get_remote_image_state(int r) { dout(10) << "r=" << r << dendl; if (r < 0) { @@ -531,6 +534,33 @@ void Replayer::handle_get_image_state(int r) { create_non_primary_snapshot(); } +template +void Replayer::get_local_image_state() { + dout(10) << dendl; + + ceph_assert(m_local_snap_id_end != CEPH_NOSNAP); + auto ctx = create_context_callback< + Replayer, &Replayer::handle_get_local_image_state>(this); + auto req = librbd::mirror::snapshot::GetImageStateRequest::create( + m_state_builder->local_image_ctx, m_local_snap_id_end, + &m_image_state, ctx); + req->send(); +} + +template +void Replayer::handle_get_local_image_state(int r) { + dout(10) << "r=" << r << dendl; + + if (r < 0) { + derr << "failed to retrieve local snapshot image state: " + << cpp_strerror(r) << dendl; + handle_replay_complete(r, "failed to retrieve local snapshot image state"); + return; + } + + copy_image(); +} + template void Replayer::create_non_primary_snapshot() { dout(10) << dendl; @@ -555,12 +585,19 @@ void Replayer::handle_create_non_primary_snapshot(int r) { return; } + dout(15) << "local_snap_id_end=" << m_local_snap_id_end << dendl; + copy_image(); } template void Replayer::copy_image() { - dout(10) << dendl; + dout(10) << "remote_snap_id_start=" << m_remote_snap_id_start << ", " + << "remote_snap_id_end=" << m_remote_snap_id_end << ", " + << "local_snap_id_start=" << m_local_snap_id_start << ", " + << "last_copied_object_number=" + << m_local_mirror_snap_ns.last_copied_object_number << ", " + << "snap_seqs=" << m_local_mirror_snap_ns.snap_seqs << dendl; m_progress_ctx = new ProgressContext(this); auto ctx = create_context_callback< @@ -590,7 +627,7 @@ void Replayer::handle_copy_image(int r) { return; } - update_non_primary_snapshot(true); + apply_image_state(); } template @@ -600,6 +637,35 @@ void Replayer::handle_copy_image_progress(uint64_t offset, uint64_t total) { // TODO } +template +void Replayer::apply_image_state() { + dout(10) << dendl; + + auto ctx = create_context_callback< + Replayer, &Replayer::handle_apply_image_state>(this); + auto req = ApplyImageStateRequest::create( + m_local_mirror_uuid, + m_state_builder->remote_mirror_uuid, + m_state_builder->local_image_ctx, + m_state_builder->remote_image_ctx, + m_image_state, ctx); + req->send(); +} + +template +void Replayer::handle_apply_image_state(int r) { + dout(10) << "r=" << r << dendl; + + if (r < 0 && r != -ENOENT) { + derr << "failed to apply remote image state to local image: " + << cpp_strerror(r) << dendl; + handle_replay_complete(r, "failed to apply remote image state"); + return; + } + + update_non_primary_snapshot(true); +} + template void Replayer::update_non_primary_snapshot(bool complete) { dout(10) << dendl; diff --git a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h index b28b69c073b..f8faf657ee8 100644 --- a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h +++ b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h @@ -103,15 +103,14 @@ private: * v (skip if not needed) | * REFRESH_REMOTE_IMAGE | * | | - * | | * | (interrupted sync) | - * |\--------------------------------------------\ | + * |\--------------> GET_LOCAL_IMAGE_STATE ------\ | * | | | * | (new snapshot) | | * |\--------------> COPY_SNAPSHOTS | | * | | | | * | v | | - * | GET_IMAGE_STATE | | + * | GET_REMOTE_IMAGE_STATE | | * | | | | * | v | | * | CREATE_NON_PRIMARY_SNAPSHOT | | @@ -122,6 +121,9 @@ private: * | COPY_IMAGE | * | | | * | v | + * | APPLY_IMAGE_STATE | + * | | | + * | v | * | UPDATE_NON_PRIMARY_SNAPSHOT | * | | | * | v | @@ -215,8 +217,11 @@ private: void copy_snapshots(); void handle_copy_snapshots(int r); - void get_image_state(); - void handle_get_image_state(int r); + void get_remote_image_state(); + void handle_get_remote_image_state(int r); + + void get_local_image_state(); + void handle_get_local_image_state(int r); void create_non_primary_snapshot(); void handle_create_non_primary_snapshot(int r); @@ -225,6 +230,9 @@ private: void handle_copy_image(int r); void handle_copy_image_progress(uint64_t offset, uint64_t total); + void apply_image_state(); + void handle_apply_image_state(int r); + void update_non_primary_snapshot(bool complete); void handle_update_non_primary_snapshot(bool complete, int r); -- 2.39.5