]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
rbd-mirror: support resync request for snapshot-based mirroring
authorJason Dillaman <dillaman@redhat.com>
Sat, 22 Feb 2020 20:23:10 +0000 (15:23 -0500)
committerJason Dillaman <dillaman@redhat.com>
Thu, 27 Feb 2020 13:22:58 +0000 (08:22 -0500)
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 <dillaman@redhat.com>
src/test/rbd_mirror/image_replayer/snapshot/test_mock_Replayer.cc
src/test/rbd_mirror/test_ImageReplayer.cc
src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc
src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h

index 822d3a421358019e48f0ad7eedf0a2caa65a9536..49d4b3884ce4e31718dbaef78acec5295b9a49dd 100644 (file)
@@ -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<MockTestImageCtx> {
   MOCK_METHOD0(send, void());
 };
 
+template <>
+struct ImageMeta<MockTestImageCtx> {
+  MOCK_METHOD1(load, void(Context*));
+
+  bool resync_requested = false;
+};
+
 template <>
 struct UnlinkPeerRequest<MockTestImageCtx> {
   uint64_t snap_id;
@@ -296,15 +304,21 @@ struct ApplyImageStateRequest<librbd::MockTestImageCtx> {
 template<>
 struct StateBuilder<librbd::MockTestImageCtx> {
   StateBuilder(librbd::MockTestImageCtx& local_image_ctx,
-               librbd::MockTestImageCtx& remote_image_ctx)
+               librbd::MockTestImageCtx& remote_image_ctx,
+               librbd::mirror::snapshot::ImageMeta<librbd::MockTestImageCtx>&
+                 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<librbd::MockTestImageCtx>*
+    local_image_meta = nullptr;
 };
 
 ApplyImageStateRequest<librbd::MockTestImageCtx>* ApplyImageStateRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
@@ -341,6 +355,7 @@ public:
   typedef librbd::deep_copy::SnapshotCopyRequest<librbd::MockTestImageCtx> MockSnapshotCopyRequest;
   typedef librbd::mirror::snapshot::CreateNonPrimaryRequest<librbd::MockTestImageCtx> MockCreateNonPrimaryRequest;
   typedef librbd::mirror::snapshot::GetImageStateRequest<librbd::MockTestImageCtx> MockGetImageStateRequest;
+  typedef librbd::mirror::snapshot::ImageMeta<librbd::MockTestImageCtx> MockImageMeta;
   typedef librbd::mirror::snapshot::UnlinkPeerRequest<librbd::MockTestImageCtx> 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;
index 83fd20f96ae9f0fe19f7fa0820605340e6760b03..d5962984369b4ddd2cea819393a4224f679b78e2 100644 (file)
@@ -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());
 
index 1140813166b03c8f6b21cc3fe7cf7ccecb66d8d3..a2f8950f0de5c4f5ea1d2cbd150f66014463c802 100644 (file)
@@ -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<I>::get_replay_status(std::string* description,
   return true;
 }
 
+template <typename I>
+void Replayer<I>::load_local_image_meta() {
+  dout(10) << dendl;
+
+  ceph_assert(m_state_builder->local_image_meta != nullptr);
+  auto ctx = create_context_callback<
+    Replayer<I>, &Replayer<I>::handle_load_local_image_meta>(this);
+  m_state_builder->local_image_meta->load(ctx);
+}
+
+template <typename I>
+void Replayer<I>::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 <typename I>
 void Replayer<I>::refresh_local_image() {
   if (!m_state_builder->local_image_ctx->state->is_refresh_required()) {
@@ -551,7 +583,7 @@ void Replayer<I>::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<I>::unlink_peer() {
       notify_status_updated();
     }
 
-    refresh_local_image();
+    load_local_image_meta();
     return;
   }
 
@@ -898,7 +930,7 @@ void Replayer<I>::handle_unlink_peer(int r) {
     notify_status_updated();
   }
 
-  refresh_local_image();
+  load_local_image_meta();
 }
 
 template <typename I>
@@ -975,7 +1007,7 @@ void Replayer<I>::handle_register_remote_update_watcher(int r) {
     notify_status_updated();
   }
 
-  refresh_local_image();
+  load_local_image_meta();
 }
 
 template <typename I>
@@ -1067,7 +1099,7 @@ void Replayer<I>::handle_image_update_notify() {
     locker.unlock();
 
     dout(15) << "restarting idle replayer" << dendl;
-    refresh_local_image();
+    load_local_image_meta();
   }
 }
 
index e0d0b01f6ea1689385af0916234b411a80779352..e5ae54c6272648588dad8f18890b70cbe8a9cfab 100644 (file)
@@ -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);