mirror of
https://github.com/ceph/ceph
synced 2025-02-23 19:17:37 +00:00
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 <dillaman@redhat.com>
This commit is contained in:
parent
fc073c54a1
commit
86d39fb9ee
@ -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;
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user