From: Miki Patel Date: Sun, 19 Apr 2026 06:29:40 +0000 (+0530) Subject: rbd-mirror: prune obsolete primary mirror snapshots after relocation X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=a10f58df8cb95deae899f35562bd024ad0c2bae9;p=ceph.git 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 --- diff --git a/qa/workunits/rbd/rbd_mirror.sh b/qa/workunits/rbd/rbd_mirror.sh index 7f8afddc6135..99166f169ba5 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 324b0877655a..509039716432 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 db85304f06b2..a2dabf2e0ae8 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 0788ce51bfa3..1bdd0c6b96f5 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 de4ef76b7c74..9aee9a96b4d8 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 f5e9c67fde84..ef13f20fa9c6 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 0831f72f1301..79c27cb19b97 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 358af64bea27..9e346e7adc67 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 903cce98bfb4..5605b1631fa8 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 14a2113bea5e..b85edfc105d4 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 399e636a9197..6f111b26d760 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 b3c58be95f6c..d678e6ea87cc 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 baa8dcedc7ae..c26690740144 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;