From 86d39fb9eeaafec2523d3652083a407947434844 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Sat, 22 Feb 2020 15:23:10 -0500 Subject: [PATCH] rbd-mirror: support resync request for snapshot-based mirroring When a local image has the resync requested image-meta property, the snapshot replayer will stop and initiate the resync request. Signed-off-by: Jason Dillaman --- .../snapshot/test_mock_Replayer.cc | 221 ++++++++++++++++-- src/test/rbd_mirror/test_ImageReplayer.cc | 44 ++-- .../image_replayer/snapshot/Replayer.cc | 42 +++- .../image_replayer/snapshot/Replayer.h | 16 +- 4 files changed, 273 insertions(+), 50 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 822d3a42135..49d4b3884ce 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 @@ -6,6 +6,7 @@ #include "librbd/deep_copy/SnapshotCopyRequest.h" #include "librbd/mirror/snapshot/CreateNonPrimaryRequest.h" #include "librbd/mirror/snapshot/GetImageStateRequest.h" +#include "librbd/mirror/snapshot/ImageMeta.h" #include "librbd/mirror/snapshot/UnlinkPeerRequest.h" #include "tools/rbd_mirror/Threads.h" #include "tools/rbd_mirror/image_replayer/CloseImageRequest.h" @@ -173,6 +174,13 @@ struct GetImageStateRequest { MOCK_METHOD0(send, void()); }; +template <> +struct ImageMeta { + MOCK_METHOD1(load, void(Context*)); + + bool resync_requested = false; +}; + template <> struct UnlinkPeerRequest { uint64_t snap_id; @@ -296,15 +304,21 @@ struct ApplyImageStateRequest { template<> struct StateBuilder { StateBuilder(librbd::MockTestImageCtx& local_image_ctx, - librbd::MockTestImageCtx& remote_image_ctx) + librbd::MockTestImageCtx& remote_image_ctx, + librbd::mirror::snapshot::ImageMeta& + local_image_meta) : local_image_ctx(&local_image_ctx), - remote_image_ctx(&remote_image_ctx) { + remote_image_ctx(&remote_image_ctx), + local_image_meta(&local_image_meta) { } librbd::MockTestImageCtx* local_image_ctx; librbd::MockTestImageCtx* remote_image_ctx; std::string remote_mirror_uuid = "remote mirror uuid"; + + librbd::mirror::snapshot::ImageMeta* + local_image_meta = nullptr; }; ApplyImageStateRequest* ApplyImageStateRequest::s_instance = nullptr; @@ -341,6 +355,7 @@ public: typedef librbd::deep_copy::SnapshotCopyRequest MockSnapshotCopyRequest; typedef librbd::mirror::snapshot::CreateNonPrimaryRequest MockCreateNonPrimaryRequest; typedef librbd::mirror::snapshot::GetImageStateRequest MockGetImageStateRequest; + typedef librbd::mirror::snapshot::ImageMeta MockImageMeta; typedef librbd::mirror::snapshot::UnlinkPeerRequest MockUnlinkPeerRequest; void SetUp() override { @@ -399,6 +414,15 @@ public: }))); } + void expect_load_image_meta(MockImageMeta& mock_image_meta, + bool resync_requested, int r) { + EXPECT_CALL(mock_image_meta, load(_)) + .WillOnce(Invoke([this, &mock_image_meta, resync_requested, r](Context* ctx) { + mock_image_meta.resync_requested = resync_requested; + m_threads->work_queue->queue(ctx, r); + })); + } + void expect_is_refresh_required(librbd::MockTestImageCtx& mock_image_ctx, bool is_required) { EXPECT_CALL(*mock_image_ctx.state, is_refresh_required()) @@ -556,11 +580,13 @@ public: librbd::MockTestImageCtx& mock_local_image_ctx, librbd::MockTestImageCtx& mock_remote_image_ctx, MockReplayerListener& mock_replayer_listener, + MockImageMeta& mock_image_meta, librbd::UpdateWatchCtx** update_watch_ctx) { expect_register_update_watcher(mock_local_image_ctx, update_watch_ctx, 123, 0); expect_register_update_watcher(mock_remote_image_ctx, update_watch_ctx, 234, 0); + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); @@ -609,8 +635,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InitShutDown) { InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, &mock_replayer_listener}; @@ -623,6 +651,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InitShutDown) { mock_local_image_ctx, mock_remote_image_ctx, mock_replayer_listener, + mock_image_meta, &update_watch_ctx)); ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, mock_local_image_ctx, @@ -659,8 +688,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SyncSnapshot) { InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, &mock_replayer_listener}; @@ -677,6 +708,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SyncSnapshot) { 0); // sync snap1 + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; @@ -698,6 +730,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SyncSnapshot) { expect_notify_update(mock_local_image_ctx); // sync snap4 + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -724,6 +757,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SyncSnapshot) { 0); // idle + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -764,8 +798,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSync) { InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, &mock_replayer_listener}; @@ -778,6 +814,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSync) { mock_local_image_ctx, mock_remote_image_ctx, mock_replayer_listener, + mock_image_meta, &update_watch_ctx)); // inject a incomplete sync snapshot @@ -793,6 +830,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSync) { 0, {}, 0, 0, {}}}}; // re-sync snap1 + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); MockGetImageStateRequest mock_get_image_state_request; @@ -808,6 +846,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSync) { expect_notify_update(mock_local_image_ctx); // idle + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -841,8 +880,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteImageDemoted) { InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, &mock_replayer_listener}; @@ -855,6 +896,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteImageDemoted) { mock_local_image_ctx, mock_remote_image_ctx, mock_replayer_listener, + mock_image_meta, &update_watch_ctx)); // inject a demotion snapshot @@ -865,6 +907,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteImageDemoted) { 0, {}, 0, 0, {}}}}; // sync snap1 + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; @@ -886,6 +929,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteImageDemoted) { expect_notify_update(mock_local_image_ctx); // idle + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -920,8 +964,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, LocalImagePromoted) { InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, &mock_replayer_listener}; @@ -934,6 +980,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, LocalImagePromoted) { mock_local_image_ctx, mock_remote_image_ctx, mock_replayer_listener, + mock_image_meta, &update_watch_ctx)); // inject a promotion snapshot @@ -944,6 +991,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, LocalImagePromoted) { 0, {}, 0, 0, {}}}}; // idle + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); @@ -959,6 +1007,52 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, LocalImagePromoted) { mock_remote_image_ctx)); } +TEST_F(TestMockImageReplayerSnapshotReplayer, ResyncRequested) { + librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; + librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; + + MockThreads mock_threads(m_threads); + expect_work_queue_repeatedly(mock_threads); + + MockReplayerListener mock_replayer_listener; + expect_notification(mock_threads, mock_replayer_listener); + + InSequence seq; + + MockImageMeta mock_image_meta; + MockStateBuilder mock_state_builder(mock_local_image_ctx, + mock_remote_image_ctx, + mock_image_meta); + MockReplayer mock_replayer{&mock_threads, "local mirror uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; + m_pool_meta_cache.set_remote_pool_meta( + m_remote_io_ctx.get_id(), + {"remote mirror uuid", "remote mirror peer uuid"}); + + librbd::UpdateWatchCtx* update_watch_ctx = nullptr; + ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, + mock_local_image_ctx, + mock_remote_image_ctx, + mock_replayer_listener, + mock_image_meta, + &update_watch_ctx)); + + // idle + expect_load_image_meta(mock_image_meta, true, 0); + + // wake-up replayer + update_watch_ctx->handle_notify(); + + // wait for sync to complete and expect replay complete + ASSERT_EQ(0, wait_for_notification(1)); + ASSERT_FALSE(mock_replayer.is_replaying()); + + ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, + mock_local_image_ctx, + mock_remote_image_ctx)); +} + TEST_F(TestMockImageReplayerSnapshotReplayer, RegisterLocalUpdateWatcherError) { librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; @@ -968,8 +1062,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RegisterLocalUpdateWatcherError) { InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayerListener mock_replayer_listener; MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, @@ -998,8 +1094,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RegisterRemoteUpdateWatcherError) InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayerListener mock_replayer_listener; MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, @@ -1035,8 +1133,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnregisterRemoteUpdateWatcherError InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, &mock_replayer_listener}; @@ -1049,6 +1149,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnregisterRemoteUpdateWatcherError mock_local_image_ctx, mock_remote_image_ctx, mock_replayer_listener, + mock_image_meta, &update_watch_ctx)); @@ -1073,8 +1174,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnregisterLocalUpdateWatcherError) InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, &mock_replayer_listener}; @@ -1087,6 +1190,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnregisterLocalUpdateWatcherError) mock_local_image_ctx, mock_remote_image_ctx, mock_replayer_listener, + mock_image_meta, &update_watch_ctx)); @@ -1099,6 +1203,53 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnregisterLocalUpdateWatcherError) ASSERT_EQ(-EINVAL, shutdown_ctx.wait()); } +TEST_F(TestMockImageReplayerSnapshotReplayer, LoadImageMetaError) { + librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; + librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; + + MockThreads mock_threads(m_threads); + expect_work_queue_repeatedly(mock_threads); + + MockReplayerListener mock_replayer_listener; + expect_notification(mock_threads, mock_replayer_listener); + + InSequence seq; + + MockImageMeta mock_image_meta; + MockStateBuilder mock_state_builder(mock_local_image_ctx, + mock_remote_image_ctx, + mock_image_meta); + MockReplayer mock_replayer{&mock_threads, "local mirror uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; + m_pool_meta_cache.set_remote_pool_meta( + m_remote_io_ctx.get_id(), + {"remote mirror uuid", "remote mirror peer uuid"}); + + librbd::UpdateWatchCtx* update_watch_ctx = nullptr; + ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, + mock_local_image_ctx, + mock_remote_image_ctx, + mock_replayer_listener, + mock_image_meta, + &update_watch_ctx)); + + // sync + expect_load_image_meta(mock_image_meta, false, -EINVAL); + + // wake-up replayer + update_watch_ctx->handle_notify(); + + // wait for sync to complete and expect replay complete + ASSERT_EQ(0, wait_for_notification(1)); + ASSERT_FALSE(mock_replayer.is_replaying()); + ASSERT_EQ(-EINVAL, mock_replayer.get_error_code()); + + ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, + mock_local_image_ctx, + mock_remote_image_ctx)); +} + TEST_F(TestMockImageReplayerSnapshotReplayer, RefreshLocalImageError) { librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; @@ -1111,8 +1262,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RefreshLocalImageError) { InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, &mock_replayer_listener}; @@ -1125,9 +1278,11 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RefreshLocalImageError) { mock_local_image_ctx, mock_remote_image_ctx, mock_replayer_listener, + mock_image_meta, &update_watch_ctx)); // sync + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh(mock_local_image_ctx, {}, -EINVAL); @@ -1156,8 +1311,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RefreshRemoteImageError) { InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, &mock_replayer_listener}; @@ -1170,9 +1327,11 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RefreshRemoteImageError) { mock_local_image_ctx, mock_remote_image_ctx, mock_replayer_listener, + mock_image_meta, &update_watch_ctx)); // sync + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, true); expect_refresh(mock_remote_image_ctx, {}, -EINVAL); @@ -1202,8 +1361,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, CopySnapshotsError) { InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, &mock_replayer_listener}; @@ -1216,6 +1377,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, CopySnapshotsError) { mock_local_image_ctx, mock_remote_image_ctx, mock_replayer_listener, + mock_image_meta, &update_watch_ctx)); // inject snapshot @@ -1226,6 +1388,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, CopySnapshotsError) { 0, {}, 0, 0, {}}}}; // sync snap1 + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; @@ -1257,8 +1420,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, GetImageStateError) { InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, &mock_replayer_listener}; @@ -1271,6 +1436,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, GetImageStateError) { mock_local_image_ctx, mock_remote_image_ctx, mock_replayer_listener, + mock_image_meta, &update_watch_ctx)); // inject snapshot @@ -1281,6 +1447,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, GetImageStateError) { 0, {}, 0, 0, {}}}}; // sync snap1 + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; @@ -1314,8 +1481,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, CreateNonPrimarySnapshotError) { InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, &mock_replayer_listener}; @@ -1328,6 +1497,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, CreateNonPrimarySnapshotError) { mock_local_image_ctx, mock_remote_image_ctx, mock_replayer_listener, + mock_image_meta, &update_watch_ctx)); // inject snapshot @@ -1338,6 +1508,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, CreateNonPrimarySnapshotError) { 0, {}, 0, 0, {}}}}; // sync snap1 + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; @@ -1375,8 +1546,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, CopyImageError) { InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, &mock_replayer_listener}; @@ -1389,6 +1562,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, CopyImageError) { mock_local_image_ctx, mock_remote_image_ctx, mock_replayer_listener, + mock_image_meta, &update_watch_ctx)); // inject snapshot @@ -1399,6 +1573,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, CopyImageError) { 0, {}, 0, 0, {}}}}; // sync snap1 + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; @@ -1439,8 +1614,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UpdateNonPrimarySnapshotError) { InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, &mock_replayer_listener}; @@ -1453,6 +1630,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UpdateNonPrimarySnapshotError) { mock_local_image_ctx, mock_remote_image_ctx, mock_replayer_listener, + mock_image_meta, &update_watch_ctx)); // inject snapshot @@ -1463,6 +1641,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UpdateNonPrimarySnapshotError) { 0, {}, 0, 0, {}}}}; // sync snap1 + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; @@ -1507,8 +1686,10 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnlinkPeerError) { InSequence seq; + MockImageMeta mock_image_meta; MockStateBuilder mock_state_builder(mock_local_image_ctx, - mock_remote_image_ctx); + mock_remote_image_ctx, + mock_image_meta); MockReplayer mock_replayer{&mock_threads, "local mirror uuid", &m_pool_meta_cache, &mock_state_builder, &mock_replayer_listener}; @@ -1521,6 +1702,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnlinkPeerError) { mock_local_image_ctx, mock_remote_image_ctx, mock_replayer_listener, + mock_image_meta, &update_watch_ctx)); // inject snapshot @@ -1540,6 +1722,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnlinkPeerError) { 0, {}, 0, 0, {}}}}; // sync snap2 + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; diff --git a/src/test/rbd_mirror/test_ImageReplayer.cc b/src/test/rbd_mirror/test_ImageReplayer.cc index 83fd20f96ae..d5962984369 100644 --- a/src/test/rbd_mirror/test_ImageReplayer.cc +++ b/src/test/rbd_mirror/test_ImageReplayer.cc @@ -122,9 +122,14 @@ public: features |= RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_JOURNALING; EXPECT_EQ(0, librbd::api::Mirror<>::mode_set(m_remote_ioctx, RBD_MIRROR_MODE_POOL)); + EXPECT_EQ(0, librbd::api::Mirror<>::mode_set(m_local_ioctx, + RBD_MIRROR_MODE_POOL)); } else { EXPECT_EQ(0, librbd::api::Mirror<>::mode_set(m_remote_ioctx, RBD_MIRROR_MODE_IMAGE)); + EXPECT_EQ(0, librbd::api::Mirror<>::mode_set(m_local_ioctx, + RBD_MIRROR_MODE_IMAGE)); + uuid_d uuid_gen; uuid_gen.generate_random(); @@ -139,6 +144,11 @@ public: m_remote_ioctx.get_id(), {m_remote_mirror_uuid, remote_peer_uuid}); } + EXPECT_EQ(0, librbd::api::Mirror<>::uuid_get(m_remote_ioctx, + &m_remote_mirror_uuid)); + EXPECT_EQ(0, librbd::api::Mirror<>::uuid_get(m_local_ioctx, + &m_local_mirror_uuid)); + m_image_name = get_temp_image_name(); int order = 0; EXPECT_EQ(0, librbd::create(m_remote_ioctx, m_image_name.c_str(), 1 << 22, @@ -212,6 +222,10 @@ public: m_replayer->start(&cond); ASSERT_EQ(0, cond.wait()); + create_watch_ctx(); + } + + void create_watch_ctx() { std::string oid; if (MIRROR_IMAGE_MODE == cls::rbd::MIRROR_IMAGE_MODE_JOURNAL) { oid = ::journal::Journaler::header_oid(m_remote_image_id); @@ -220,12 +234,9 @@ public: } ASSERT_EQ(0U, m_watch_handle); - create_watch_ctx(oid); - ASSERT_EQ(0, m_remote_ioctx.watch2(oid, &m_watch_handle, m_watch_ctx)); - } - - void create_watch_ctx(const std::string& oid) { + ASSERT_TRUE(m_watch_ctx == nullptr); m_watch_ctx = new C_WatchCtx(this, oid); + ASSERT_EQ(0, m_remote_ioctx.watch2(oid, &m_watch_handle, m_watch_ctx)); } void unwatch() { @@ -824,9 +835,8 @@ TEST_F(TestImageReplayerJournal, NextTag) this->stop(); } -TEST_F(TestImageReplayerJournal, Resync) +TYPED_TEST(TestImageReplayer, Resync) { - // TODO add support to snapshot-based mirroring this->bootstrap(); librbd::ImageCtx *ictx; @@ -852,7 +862,7 @@ TEST_F(TestImageReplayerJournal, Resync) this->close_image(ictx); this->open_local_image(&ictx); - librbd::Journal<>::request_resync(ictx); + EXPECT_EQ(0, librbd::api::Mirror<>::image_resync(ictx)); this->close_image(ictx); this->wait_for_stopped(); @@ -874,10 +884,8 @@ TEST_F(TestImageReplayerJournal, Resync) this->stop(); } -TEST_F(TestImageReplayerJournal, Resync_While_Stop) +TYPED_TEST(TestImageReplayer, Resync_While_Stop) { - // TODO add support to snapshot-based mirroring - this->bootstrap(); this->start(); @@ -908,7 +916,7 @@ TEST_F(TestImageReplayerJournal, Resync_While_Stop) ASSERT_EQ(0, cond.wait()); this->open_local_image(&ictx); - librbd::Journal<>::request_resync(ictx); + EXPECT_EQ(0, librbd::api::Mirror<>::image_resync(ictx)); this->close_image(ictx); C_SaferCond cond2; @@ -935,15 +943,13 @@ TEST_F(TestImageReplayerJournal, Resync_While_Stop) this->stop(); } -TEST_F(TestImageReplayerJournal, Resync_StartInterrupted) +TYPED_TEST(TestImageReplayer, Resync_StartInterrupted) { - // TODO add support to snapshot-based mirroring - this->bootstrap(); librbd::ImageCtx *ictx; this->open_local_image(&ictx); - librbd::Journal<>::request_resync(ictx); + EXPECT_EQ(0, librbd::api::Mirror<>::image_resync(ictx)); this->close_image(ictx); C_SaferCond cond; @@ -956,11 +962,7 @@ TEST_F(TestImageReplayerJournal, Resync_StartInterrupted) this->m_replayer->start(&cond2); ASSERT_EQ(0, cond2.wait()); - ASSERT_EQ(0U, this->m_watch_handle); - std::string oid = ::journal::Journaler::header_oid(this->m_remote_image_id); - this->create_watch_ctx(oid); - ASSERT_EQ(0, this->m_remote_ioctx.watch2(oid, &this->m_watch_handle, - this->m_watch_ctx)); + this->create_watch_ctx(); ASSERT_TRUE(this->m_replayer->is_replaying()); diff --git a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc index 1140813166b..a2f8950f0de 100644 --- a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc +++ b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc @@ -15,6 +15,7 @@ #include "librbd/deep_copy/SnapshotCopyRequest.h" #include "librbd/mirror/snapshot/CreateNonPrimaryRequest.h" #include "librbd/mirror/snapshot/GetImageStateRequest.h" +#include "librbd/mirror/snapshot/ImageMeta.h" #include "librbd/mirror/snapshot/UnlinkPeerRequest.h" #include "tools/rbd_mirror/PoolMetaCache.h" #include "tools/rbd_mirror/Threads.h" @@ -274,6 +275,37 @@ bool Replayer::get_replay_status(std::string* description, return true; } +template +void Replayer::load_local_image_meta() { + dout(10) << dendl; + + ceph_assert(m_state_builder->local_image_meta != nullptr); + auto ctx = create_context_callback< + Replayer, &Replayer::handle_load_local_image_meta>(this); + m_state_builder->local_image_meta->load(ctx); +} + +template +void Replayer::handle_load_local_image_meta(int r) { + dout(10) << "r=" << r << dendl; + + if (r < 0 && r != -ENOENT) { + derr << "failed to load local image-meta: " << cpp_strerror(r) << dendl; + handle_replay_complete(r, "failed to load local image-meta"); + return; + } + + if (r >= 0 && m_state_builder->local_image_meta->resync_requested) { + m_resync_requested = true; + + dout(10) << "local image resync requested" << dendl; + handle_replay_complete(0, "resync requested"); + return; + } + + refresh_local_image(); +} + template void Replayer::refresh_local_image() { if (!m_state_builder->local_image_ctx->state->is_refresh_required()) { @@ -551,7 +583,7 @@ void Replayer::scan_remote_mirror_snapshots( dout(10) << "restarting snapshot scan due to remote update notification" << dendl; - refresh_local_image(); + load_local_image_meta(); return; } @@ -866,7 +898,7 @@ void Replayer::unlink_peer() { notify_status_updated(); } - refresh_local_image(); + load_local_image_meta(); return; } @@ -898,7 +930,7 @@ void Replayer::handle_unlink_peer(int r) { notify_status_updated(); } - refresh_local_image(); + load_local_image_meta(); } template @@ -975,7 +1007,7 @@ void Replayer::handle_register_remote_update_watcher(int r) { notify_status_updated(); } - refresh_local_image(); + load_local_image_meta(); } template @@ -1067,7 +1099,7 @@ void Replayer::handle_image_update_notify() { locker.unlock(); dout(15) << "restarting idle replayer" << dendl; - refresh_local_image(); + load_local_image_meta(); } } diff --git a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h index e0d0b01f6ea..e5ae54c6272 100644 --- a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h +++ b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h @@ -73,9 +73,8 @@ public: } bool is_resync_requested() const override { - std::unique_lock locker(m_lock); - // TODO - return false; + std::unique_lock locker{m_lock}; + return m_resync_requested; } int get_error_code() const override { @@ -100,8 +99,11 @@ private: * v * REGISTER_REMOTE_UPDATE_WATCHER * | - * v (skip if not needed) - * REFRESH_LOCAL_IMAGE <------------------------------\ + * v + * LOAD_LOCAL_IMAGE_META <----------------------------\ + * | | + * v (skip if not needed) | + * REFRESH_LOCAL_IMAGE | * | | * v (skip if not needed) | * REFRESH_REMOTE_IMAGE | @@ -189,6 +191,7 @@ private: Context* m_on_init_shutdown = nullptr; + bool m_resync_requested = false; int m_error_code = 0; std::string m_error_description; @@ -215,6 +218,9 @@ private: bool m_remote_image_updated = false; bool m_updating_sync_point = false; + void load_local_image_meta(); + void handle_load_local_image_meta(int r); + void refresh_local_image(); void handle_refresh_local_image(int r); -- 2.39.5