From a10f58df8cb95deae899f35562bd024ad0c2bae9 Mon Sep 17 00:00:00 2001 From: Miki Patel Date: Sun, 19 Apr 2026 11:59:40 +0530 Subject: [PATCH] rbd-mirror: prune obsolete primary mirror snapshots after relocation Previously, obsolete primary and demoted primary snapshots on the secondary cluster were not cleaned up immediately after relocation. Instead, old primary snapshots remained until a subsequent promote operation triggered their cleanup, while old demoted primary snapshots persisted until a later demote operation removed them. Adding changes for proactive cleanup of obsolete primary and demoted primary snapshots that are no longer required after relocation. Also adding test coverage to validate the cleanup behavior. Fixes: https://tracker.ceph.com/issues/76154 Signed-off-by: Miki Patel --- qa/workunits/rbd/rbd_mirror.sh | 54 ++++ qa/workunits/rbd/rbd_mirror_helpers.sh | 37 +++ .../snapshot/test_mock_Replayer.cc | 272 +++++++++++------- .../rbd_mirror/test_mock_ImageReplayer.cc | 10 +- src/tools/rbd_mirror/ImageReplayer.cc | 1 + src/tools/rbd_mirror/Types.h | 2 +- .../rbd_mirror/image_replayer/StateBuilder.h | 1 + .../image_replayer/journal/StateBuilder.cc | 1 + .../image_replayer/journal/StateBuilder.h | 1 + .../image_replayer/snapshot/Replayer.cc | 32 ++- .../image_replayer/snapshot/Replayer.h | 10 +- .../image_replayer/snapshot/StateBuilder.cc | 5 +- .../image_replayer/snapshot/StateBuilder.h | 1 + 13 files changed, 312 insertions(+), 115 deletions(-) diff --git a/qa/workunits/rbd/rbd_mirror.sh b/qa/workunits/rbd/rbd_mirror.sh index 7f8afddc613..99166f169ba 100755 --- a/qa/workunits/rbd/rbd_mirror.sh +++ b/qa/workunits/rbd/rbd_mirror.sh @@ -274,6 +274,60 @@ wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+stopped' compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image} +if [ "${RBD_MIRROR_MODE}" = "snapshot" ]; then + testlog "TEST: failover / failback loop with snapshot presence checks" + snap_id_1="" + demote_snap_id_1="" + snap_id_2="" + demote_snap_id_2="" + get_newest_complete_mirror_snapshot_id ${CLUSTER2} ${POOL} ${image} snap_id_2 + for i in `seq 1 5`; do + demote_image ${CLUSTER2} ${POOL} ${image} + wait_for_image_replay_stopped ${CLUSTER1} ${POOL} ${image} + wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} 'up+unknown' + wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+unknown' + get_newest_complete_mirror_snapshot_id ${CLUSTER2} ${POOL} ${image} demote_snap_id_2 + wait_for_non_primary_snap_present ${CLUSTER1} ${POOL} ${image} ${demote_snap_id_2} + wait_for_non_primary_snap_not_present ${CLUSTER1} ${POOL} ${image} ${snap_id_2} + + promote_image ${CLUSTER1} ${POOL} ${image} + wait_for_image_replay_started ${CLUSTER2} ${POOL} ${image} + wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} 'up+stopped' + wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+replaying' + get_newest_complete_mirror_snapshot_id ${CLUSTER1} ${POOL} ${image} snap_id_1 + wait_for_non_primary_snap_present ${CLUSTER2} ${POOL} ${image} ${snap_id_1} + wait_for_snap_not_present ${CLUSTER2} ${POOL} ${image} ${snap_id_2} + wait_for_snap_not_present ${CLUSTER2} ${POOL} ${image} ${demote_snap_id_2} + + demote_image ${CLUSTER1} ${POOL} ${image} + wait_for_non_primary_snap_not_present ${CLUSTER1} ${POOL} ${image} ${demote_snap_id_2} + wait_for_image_replay_stopped ${CLUSTER2} ${POOL} ${image} + wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} 'up+unknown' + wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+unknown' + get_newest_complete_mirror_snapshot_id ${CLUSTER1} ${POOL} ${image} demote_snap_id_1 + wait_for_non_primary_snap_present ${CLUSTER2} ${POOL} ${image} ${demote_snap_id_1} + wait_for_non_primary_snap_not_present ${CLUSTER2} ${POOL} ${image} ${snap_id_1} + + promote_image ${CLUSTER2} ${POOL} ${image} + wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image} + wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+stopped' + wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} 'up+replaying' + get_newest_complete_mirror_snapshot_id ${CLUSTER2} ${POOL} ${image} snap_id_2 + wait_for_non_primary_snap_present ${CLUSTER1} ${POOL} ${image} ${snap_id_2} + wait_for_snap_not_present ${CLUSTER1} ${POOL} ${image} ${snap_id_1} + wait_for_snap_not_present ${CLUSTER1} ${POOL} ${image} ${demote_snap_id_1} + done + # expected snapshot in non-primary image: non-primary + SNAPS=$(get_snaps_json ${CLUSTER1} ${POOL} ${image}) + jq -e 'length == 1' <<< ${SNAPS} + jq -e '.[0].namespace["type"] == "mirror" and .[0].namespace["state"] == "non-primary"' <<< ${SNAPS} + # expected snapshots in primary image: non-primary demoted, primary + SNAPS=$(get_snaps_json ${CLUSTER2} ${POOL} ${image}) + jq -e 'length == 2' <<< ${SNAPS} + jq -e '.[0].namespace["type"] == "mirror" and .[0].namespace["state"] == "demoted" and (.[0]["name"] | startswith(".mirror.non_primary"))' <<< ${SNAPS} + jq -e '.[1].namespace["type"] == "mirror" and .[1].namespace["state"] == "primary"' <<< ${SNAPS} +fi + testlog "TEST: failover / failback loop" for i in `seq 1 20`; do demote_image ${CLUSTER2} ${POOL} ${image} diff --git a/qa/workunits/rbd/rbd_mirror_helpers.sh b/qa/workunits/rbd/rbd_mirror_helpers.sh index 324b0877655..50903971643 100755 --- a/qa/workunits/rbd/rbd_mirror_helpers.sh +++ b/qa/workunits/rbd/rbd_mirror_helpers.sh @@ -826,6 +826,43 @@ wait_for_non_primary_snap_present() return 1 } +wait_for_snap_not_present() +{ + local cluster=$1 + local pool=$2 + local image=$3 + local snap_id=$4 + local snap_count + local s + + for s in 0.1 1 2 4 8 8 8 8 8 8 8 8 16 16 32 32; do + sleep ${s} + snap_count=$(rbd --cluster ${cluster} snap list --all ${pool}/${image} --format xml | \ + xmlstarlet sel -t -v "count(//snapshots/snapshot[id='${snap_id}'])") + [ "${snap_count}" = "0" ] && return 0 + done + + return 1 +} + +wait_for_non_primary_snap_not_present() +{ + local cluster=$1 + local pool=$2 + local image=$3 + local primary_snap_id=$4 + local snap_count + local s + + for s in 0.1 1 2 4 8 8 8 8 8 8 8 8 16 16 32 32; do + sleep ${s} + snap_count=$(rbd --cluster ${cluster} snap list --all ${pool}/${image} --format xml | \ + xmlstarlet sel -t -v "count(//snapshots/snapshot/namespace[primary_snap_id='${primary_snap_id}'])") + [ "${snap_count}" = "0" ] && return 0 + done + return 1 +} + wait_for_snapshot_sync_complete() { local local_cluster=$1 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 db85304f06b..a2dabf2e0ae 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 @@ -495,8 +495,8 @@ public: })); } - void expect_prune_non_primary_snapshot(librbd::MockTestImageCtx& mock_image_ctx, - uint64_t snap_id, int r) { + void expect_prune_mirror_snapshot(librbd::MockTestImageCtx& mock_image_ctx, + uint64_t snap_id, int r) { EXPECT_CALL(mock_image_ctx, get_snap_info(snap_id)) .WillOnce(Invoke([&mock_image_ctx](uint64_t snap_id) -> librbd::SnapInfo* { auto it = mock_image_ctx.snap_info.find(snap_id); @@ -734,8 +734,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InitShutDown) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -788,8 +789,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SyncSnapshot) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -913,7 +915,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SyncSnapshot) { 4, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); - expect_prune_non_primary_snapshot(mock_local_image_ctx, 11, 0); + expect_prune_mirror_snapshot(mock_local_image_ctx, 11, 0); // idle expect_load_image_meta(mock_image_meta, false, 0); @@ -966,8 +968,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncInitial) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -1051,8 +1054,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncDelta) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -1129,7 +1133,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncDelta) { 2, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); - expect_prune_non_primary_snapshot(mock_local_image_ctx, 11, 0); + expect_prune_mirror_snapshot(mock_local_image_ctx, 11, 0); // idle expect_load_image_meta(mock_image_meta, false, 0); @@ -1172,8 +1176,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncDeltaDemote) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -1201,7 +1206,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncDeltaDemote) { mock_local_image_ctx.snap_info = { {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, - {"remote mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, + {"local mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, 0, {}, 0, 0, {}}}, {12U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", @@ -1229,7 +1234,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncDeltaDemote) { false, 0); expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id); - // idle + // prune primary demotion snap1 expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_remote_image_ctx, true); expect_refresh( @@ -1244,8 +1249,21 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncDeltaDemote) { mock_local_image_ctx, { {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, - {"remote mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, + {"local mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, + 0, {}, 0, 0, {}}}, + {12U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", + 2, true, 0, {}}, 0, {}, 0, 0, {}}}, + }, 0); + expect_prune_mirror_snapshot(mock_local_image_ctx, 11, 0); + + // idle + expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, true); + expect_refresh( + mock_local_image_ctx, { {12U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", 2, true, 0, {}}, @@ -1281,8 +1299,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncInitial) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -1365,8 +1384,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDelta) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -1404,7 +1424,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDelta) { expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_remote_image_ctx, false); expect_is_refresh_required(mock_local_image_ctx, false); - expect_prune_non_primary_snapshot(mock_local_image_ctx, 12, 0); + expect_prune_mirror_snapshot(mock_local_image_ctx, 12, 0); // sync snap2 expect_load_image_meta(mock_image_meta, false, 0); @@ -1462,7 +1482,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDelta) { 2, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); - expect_prune_non_primary_snapshot(mock_local_image_ctx, 11, 0); + expect_prune_mirror_snapshot(mock_local_image_ctx, 11, 0); // idle expect_load_image_meta(mock_image_meta, false, 0); @@ -1505,8 +1525,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDeltaDemote) mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -1534,7 +1555,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDeltaDemote) mock_local_image_ctx.snap_info = { {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, - {"remote mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, + {"local mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, 0, {}, 0, 0, {}}}, {12U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", @@ -1545,7 +1566,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDeltaDemote) expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_remote_image_ctx, false); expect_is_refresh_required(mock_local_image_ctx, false); - expect_prune_non_primary_snapshot(mock_local_image_ctx, 12, 0); + expect_prune_mirror_snapshot(mock_local_image_ctx, 12, 0); // sync snap2 expect_load_image_meta(mock_image_meta, false, 0); @@ -1555,7 +1576,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDeltaDemote) mock_local_image_ctx, { {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, - {"remote mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, + {"local mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); MockSnapshotCopyRequest mock_snapshot_copy_request; @@ -1581,7 +1602,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDeltaDemote) false, 0); expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id); - // idle + // prune primary demotion snap1 expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_remote_image_ctx, true); expect_refresh( @@ -1596,13 +1617,26 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDeltaDemote) mock_local_image_ctx, { {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, - {"remote mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, + {"local mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, 0, {}, 0, 0, {}}}, {13U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", 2, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); + expect_prune_mirror_snapshot(mock_local_image_ctx, 11, 0); + + // idle + expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, true); + expect_refresh( + mock_local_image_ctx, { + {13U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", + 2, true, 0, {}}, + 0, {}, 0, 0, {}}}, + }, 0); // wake-up replayer update_watch_ctx->handle_notify(); @@ -1633,8 +1667,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteImageDemoted) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -1687,8 +1722,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteImageDemoted) { expect_refresh( mock_local_image_ctx, { {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ - cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", - 1, true, 0, {}}, + cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY_DEMOTED, + {"local mirror peer uuid"}, "remote mirror uuid", 1, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); @@ -1722,8 +1757,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, LocalImagePromoted) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -1740,7 +1776,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, LocalImagePromoted) { mock_local_image_ctx.snap_info = { {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, - {"remote mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, + {"local mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, 0, {}, 0, 0, {}}}}; // idle @@ -1778,8 +1814,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, ResyncRequested) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -1834,8 +1871,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, ResyncRequestedRemoteNotPrimary) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -1890,8 +1928,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, ResyncRequestedRemoteNotPrimary) { expect_refresh( mock_local_image_ctx, { {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ - cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY_DEMOTED, {"uuid"}, - "remote mirror uuid", 1, true, 0, {{1, CEPH_NOSNAP}}}, + cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY_DEMOTED, + {"local mirror peer uuid"}, "remote mirror uuid", 1, true, 0, + {{1, CEPH_NOSNAP}}}, 0, {}, 0, 0, {}}}, }, 0); @@ -1923,8 +1962,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RegisterLocalUpdateWatcherError) { mock_image_meta); MockReplayerListener mock_replayer_listener; MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -1956,8 +1996,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RegisterRemoteUpdateWatcherError) mock_image_meta); MockReplayerListener mock_replayer_listener; MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -1995,8 +2036,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnregisterRemoteUpdateWatcherError mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2037,8 +2079,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnregisterLocalUpdateWatcherError) mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2079,8 +2122,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, LoadImageMetaError) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2127,8 +2171,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RefreshLocalImageError) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2178,8 +2223,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RefreshRemoteImageError) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2228,8 +2274,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, CopySnapshotsError) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2288,8 +2335,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, GetImageStateError) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2350,8 +2398,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, CreateNonPrimarySnapshotError) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2416,8 +2465,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UpdateMirrorImageStateError) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2484,8 +2534,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RequestSyncError) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2554,8 +2605,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, CopyImageError) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2627,8 +2679,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UpdateNonPrimarySnapshotError) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2704,8 +2757,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnlinkPeerError) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2792,8 +2846,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SplitBrain) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2855,8 +2910,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteSnapshotMissingSplitBrain) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2923,8 +2979,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteFailover) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -2956,8 +3013,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteFailover) { {11U, librbd::SnapInfo{"snap1", cls::rbd::UserSnapshotNamespace{}, 0, {}, 0, 0, {}}}, {12U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ - cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, {}, "", CEPH_NOSNAP, - true, 0, {}}, + cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, + {"local mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, 0, {}, 0, 0, {}}}}; // attach to promoted remote image @@ -2988,7 +3045,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteFailover) { false, 0); expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id); - // idle + // prune primary demotion snap2 expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_remote_image_ctx, true); expect_refresh( @@ -2997,11 +3054,11 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteFailover) { 0, {}, 0, 0, {}}}, {2U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY_DEMOTED, - {"remote mirror peer uuid"}, "local mirror uuid", 12U, true, 0, {}}, + {}, "local mirror uuid", 12U, true, 0, {}}, 0, {}, 0, 0, {}}}, {3U, librbd::SnapInfo{"snap3", cls::rbd::MirrorSnapshotNamespace{ - cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {}, "", CEPH_NOSNAP, true, 0, - {}}, + cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, + "", CEPH_NOSNAP, true, 0, {}}, 0, {}, 0, 0, {}}} }, 0); expect_is_refresh_required(mock_local_image_ctx, true); @@ -3010,8 +3067,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteFailover) { {11U, librbd::SnapInfo{"snap1", cls::rbd::UserSnapshotNamespace{}, 0, {}, 0, 0, {}}}, {12U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ - cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, {}, "", CEPH_NOSNAP, - true, 0, {}}, + cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, + {"local mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, 0, {}, 0, 0, {}}}, {13U, librbd::SnapInfo{"snap3", cls::rbd::MirrorSnapshotNamespace{ cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, @@ -3019,6 +3076,22 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteFailover) { {{1, 11}, {2, 12}, {3, CEPH_NOSNAP}}}, 0, {}, 0, 0, {}}}, }, 0); + expect_prune_mirror_snapshot(mock_local_image_ctx, 12, 0); + + // idle + expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, true); + expect_refresh( + mock_local_image_ctx, { + {11U, librbd::SnapInfo{"snap1", cls::rbd::UserSnapshotNamespace{}, + 0, {}, 0, 0, {}}}, + {13U, librbd::SnapInfo{"snap3", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, + "remote mirror uuid", 3, true, 0, + {{1, 11}, {2, 12}, {3, CEPH_NOSNAP}}}, + 0, {}, 0, 0, {}}}, + }, 0); // wake-up replayer update_watch_ctx->handle_notify(); @@ -3065,8 +3138,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnlinkRemoteSnapshot) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -3143,8 +3217,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SkipImageSync) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -3222,8 +3297,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, ImageNameUpdated) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), {"remote mirror uuid", "remote mirror peer uuid"}); @@ -3284,8 +3360,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, ApplyImageStatePendingShutdown) { mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; C_SaferCond shutdown_ctx; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), @@ -3371,8 +3448,9 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, ApplyImageStateErrorPendingShutdow mock_remote_image_ctx, mock_image_meta); MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, - "local mirror uuid", &m_pool_meta_cache, - &mock_state_builder, &mock_replayer_listener}; + "local mirror uuid", "local mirror peer uuid", + &m_pool_meta_cache, &mock_state_builder, + &mock_replayer_listener}; C_SaferCond shutdown_ctx; m_pool_meta_cache.set_remote_pool_meta( m_remote_fsid, m_remote_io_ctx.get_id(), diff --git a/src/test/rbd_mirror/test_mock_ImageReplayer.cc b/src/test/rbd_mirror/test_mock_ImageReplayer.cc index 0788ce51bfa..1bdd0c6b96f 100644 --- a/src/test/rbd_mirror/test_mock_ImageReplayer.cc +++ b/src/test/rbd_mirror/test_mock_ImageReplayer.cc @@ -178,9 +178,11 @@ struct StateBuilder { } MOCK_METHOD1(close, void(Context*)); - MOCK_METHOD5(create_replayer, Replayer*(Threads*, + MOCK_METHOD6(create_replayer, Replayer*(Threads*, InstanceWatcher*, - const std::string&, PoolMetaCache*, + const std::string&, + const std::string&, + PoolMetaCache*, ReplayerListener*)); StateBuilder() { @@ -312,8 +314,8 @@ public: void expect_create_replayer(MockStateBuilder& mock_state_builder, MockReplayer& mock_replayer) { - EXPECT_CALL(mock_state_builder, create_replayer(_, _, _, _, _)) - .WillOnce(WithArg<4>( + EXPECT_CALL(mock_state_builder, create_replayer(_, _, _, _, _, _)) + .WillOnce(WithArg<5>( Invoke([&mock_replayer] (image_replayer::ReplayerListener* replayer_listener) { mock_replayer.replayer_listener = replayer_listener; diff --git a/src/tools/rbd_mirror/ImageReplayer.cc b/src/tools/rbd_mirror/ImageReplayer.cc index de4ef76b7c7..9aee9a96b4d 100644 --- a/src/tools/rbd_mirror/ImageReplayer.cc +++ b/src/tools/rbd_mirror/ImageReplayer.cc @@ -431,6 +431,7 @@ void ImageReplayer::start_replay() { ceph_assert(m_replayer == nullptr); m_replayer = m_state_builder->create_replayer(m_threads, m_instance_watcher, m_local_mirror_uuid, + m_remote_image_peer.uuid, m_pool_meta_cache, m_replayer_listener); diff --git a/src/tools/rbd_mirror/Types.h b/src/tools/rbd_mirror/Types.h index f5e9c67fde8..ef13f20fa9c 100644 --- a/src/tools/rbd_mirror/Types.h +++ b/src/tools/rbd_mirror/Types.h @@ -116,7 +116,7 @@ struct Peer { template std::ostream& operator<<(std::ostream& os, const Peer& peer) { - return os << "uuid=" << peer.uuid << ", " + return os << "uuid=" << peer.uuid << ", remote_pool_meta=" << peer.remote_pool_meta; } diff --git a/src/tools/rbd_mirror/image_replayer/StateBuilder.h b/src/tools/rbd_mirror/image_replayer/StateBuilder.h index 0831f72f130..79c27cb19b9 100644 --- a/src/tools/rbd_mirror/image_replayer/StateBuilder.h +++ b/src/tools/rbd_mirror/image_replayer/StateBuilder.h @@ -75,6 +75,7 @@ public: Threads* threads, InstanceWatcher* instance_watcher, const std::string& local_mirror_uuid, + const std::string& local_mirror_peer_uuid, PoolMetaCache* pool_meta_cache, ReplayerListener* replayer_listener) = 0; diff --git a/src/tools/rbd_mirror/image_replayer/journal/StateBuilder.cc b/src/tools/rbd_mirror/image_replayer/journal/StateBuilder.cc index 358af64bea2..9e346e7adc6 100644 --- a/src/tools/rbd_mirror/image_replayer/journal/StateBuilder.cc +++ b/src/tools/rbd_mirror/image_replayer/journal/StateBuilder.cc @@ -106,6 +106,7 @@ image_replayer::Replayer* StateBuilder::create_replayer( Threads* threads, InstanceWatcher* instance_watcher, const std::string& local_mirror_uuid, + const std::string& local_mirror_peer_uuid, PoolMetaCache* pool_meta_cache, ReplayerListener* replayer_listener) { return Replayer::create( diff --git a/src/tools/rbd_mirror/image_replayer/journal/StateBuilder.h b/src/tools/rbd_mirror/image_replayer/journal/StateBuilder.h index 903cce98bfb..5605b1631fa 100644 --- a/src/tools/rbd_mirror/image_replayer/journal/StateBuilder.h +++ b/src/tools/rbd_mirror/image_replayer/journal/StateBuilder.h @@ -65,6 +65,7 @@ public: Threads* threads, InstanceWatcher* instance_watcher, const std::string& local_mirror_uuid, + const std::string& local_mirror_peer_uuid, PoolMetaCache* pool_meta_cache, ReplayerListener* replayer_listener) override; diff --git a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc index 14a2113bea5..b85edfc105d 100644 --- a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc +++ b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc @@ -116,12 +116,14 @@ Replayer::Replayer( Threads* threads, InstanceWatcher* instance_watcher, const std::string& local_mirror_uuid, + const std::string& local_mirror_peer_uuid, PoolMetaCache* pool_meta_cache, StateBuilder* state_builder, ReplayerListener* replayer_listener) : m_threads(threads), m_instance_watcher(instance_watcher), m_local_mirror_uuid(local_mirror_uuid), + m_local_mirror_peer_uuid(local_mirror_peer_uuid), m_pool_meta_cache(pool_meta_cache), m_state_builder(state_builder), m_replayer_listener(replayer_listener), @@ -171,7 +173,9 @@ void Replayer::init(Context* on_finish) { } m_remote_mirror_peer_uuid = remote_pool_meta.mirror_peer_uuid; - dout(10) << "remote_mirror_peer_uuid=" << m_remote_mirror_peer_uuid << dendl; + dout(10) << "local_mirror_peer_uuid=" << m_local_mirror_peer_uuid + << ", remote_mirror_peer_uuid=" << m_remote_mirror_peer_uuid + << dendl; { auto local_image_ctx = m_state_builder->local_image_ctx; @@ -539,6 +543,18 @@ void Replayer::scan_local_mirror_snapshots( } } else if (mirror_ns->is_primary()) { if (mirror_ns->complete) { + const auto& peer_uuids = mirror_ns->mirror_peer_uuids; + if (peer_uuids.empty() || + (mirror_ns->state == cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED && + peer_uuids.size() == 1 && + peer_uuids.count(m_local_mirror_peer_uuid) == 1)) { + // After relocation, the primary snapshots on the new secondary become + // obsolete snapshots. They can be pruned if they are already unlinked. + // Additionally, in this case, a demoted primary snapshot that is linked + // to only a single remote (current primary) peer is safe to prune, + // because no other peer depends on it waiting for sync. + prune_snap_ids.insert(local_snap_id); + } m_local_snap_id_start = local_snap_id; ceph_assert(m_local_snap_id_end == CEPH_NOSNAP); } else { @@ -564,8 +580,8 @@ void Replayer::scan_local_mirror_snapshots( locker->unlock(); auto prune_snap_id = *prune_snap_ids.begin(); - dout(5) << "pruning unused non-primary snapshot " << prune_snap_id << dendl; - prune_non_primary_snapshot(prune_snap_id); + dout(5) << "pruning unused mirror snapshot " << prune_snap_id << dendl; + prune_mirror_snapshot(prune_snap_id); return; } @@ -798,7 +814,7 @@ void Replayer::scan_remote_mirror_snapshots( } template -void Replayer::prune_non_primary_snapshot(uint64_t snap_id) { +void Replayer::prune_mirror_snapshot(uint64_t snap_id) { dout(10) << "snap_id=" << snap_id << dendl; auto local_image_ctx = m_state_builder->local_image_ctx; @@ -825,18 +841,18 @@ void Replayer::prune_non_primary_snapshot(uint64_t snap_id) { } auto ctx = create_context_callback< - Replayer, &Replayer::handle_prune_non_primary_snapshot>(this); + Replayer, &Replayer::handle_prune_mirror_snapshot>(this); local_image_ctx->operations->snap_remove(snap_namespace, snap_name, ctx); } template -void Replayer::handle_prune_non_primary_snapshot(int r) { +void Replayer::handle_prune_mirror_snapshot(int r) { dout(10) << "r=" << r << dendl; if (r < 0 && r != -ENOENT) { - derr << "failed to prune non-primary snapshot: " << cpp_strerror(r) + derr << "failed to prune mirror snapshot: " << cpp_strerror(r) << dendl; - handle_replay_complete(r, "failed to prune non-primary snapshot"); + handle_replay_complete(r, "failed to prune mirror snapshot"); return; } diff --git a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h index 399e636a919..6f111b26d76 100644 --- a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h +++ b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h @@ -47,17 +47,20 @@ public: Threads* threads, InstanceWatcher* instance_watcher, const std::string& local_mirror_uuid, + const std::string& local_mirror_peer_uuid, PoolMetaCache* pool_meta_cache, StateBuilder* state_builder, ReplayerListener* replayer_listener) { return new Replayer(threads, instance_watcher, local_mirror_uuid, - pool_meta_cache, state_builder, replayer_listener); + local_mirror_peer_uuid, pool_meta_cache, state_builder, + replayer_listener); } Replayer( Threads* threads, InstanceWatcher* instance_watcher, const std::string& local_mirror_uuid, + const std::string& local_mirror_peer_uuid, PoolMetaCache* pool_meta_cache, StateBuilder* state_builder, ReplayerListener* replayer_listener); @@ -202,6 +205,7 @@ private: Threads* m_threads; InstanceWatcher* m_instance_watcher; std::string m_local_mirror_uuid; + std::string m_local_mirror_peer_uuid; PoolMetaCache* m_pool_meta_cache; StateBuilder* m_state_builder; ReplayerListener* m_replayer_listener; @@ -271,8 +275,8 @@ private: void scan_local_mirror_snapshots(std::unique_lock* locker); void scan_remote_mirror_snapshots(std::unique_lock* locker); - void prune_non_primary_snapshot(uint64_t snap_id); - void handle_prune_non_primary_snapshot(int r); + void prune_mirror_snapshot(uint64_t snap_id); + void handle_prune_mirror_snapshot(int r); void copy_snapshots(); void handle_copy_snapshots(int r); diff --git a/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.cc b/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.cc index b3c58be95f6..d678e6ea87c 100644 --- a/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.cc +++ b/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.cc @@ -105,11 +105,12 @@ image_replayer::Replayer* StateBuilder::create_replayer( Threads* threads, InstanceWatcher* instance_watcher, const std::string& local_mirror_uuid, + const std::string& local_mirror_peer_uuid, PoolMetaCache* pool_meta_cache, ReplayerListener* replayer_listener) { return Replayer::create( - threads, instance_watcher, local_mirror_uuid, pool_meta_cache, this, - replayer_listener); + threads, instance_watcher, local_mirror_uuid, local_mirror_peer_uuid, + pool_meta_cache, this, replayer_listener); } } // namespace snapshot diff --git a/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h b/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h index baa8dcedc7a..c2669074014 100644 --- a/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h +++ b/src/tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h @@ -70,6 +70,7 @@ public: Threads* threads, InstanceWatcher* instance_watcher, const std::string& local_mirror_uuid, + const std::string& local_mirror_peer_uuid, PoolMetaCache* pool_meta_cache, ReplayerListener* replayer_listener) override; -- 2.47.3