From: Kotresh HR Date: Mon, 13 Jul 2026 07:58:10 +0000 (+0530) Subject: tools/cephfs_mirror: Fix failed-to-syncing state priority across metrics paths X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=a06b744e7146f420b69acf0fc32376672faaed6c;p=ceph.git tools/cephfs_mirror: Fix failed-to-syncing state priority across metrics paths When a mirrored directory hits the consecutive failure threshold, the failed flag stays set until the next successful sync. On retry, the directory can be actively syncing while failed remains true, but dump_sync_stat() and update_directory_current_sync_perf_counters() checked failed before current_syncing_snap and kept reporting "failed". Introduce get_dir_sync_state() and use it in peer_status, omap persistence, and per-directory perf counters so syncing takes precedence over the sticky failed flag. Fixes: https://tracker.ceph.com/issues/76616 Signed-off-by: Kotresh HR --- diff --git a/src/tools/cephfs_mirror/PeerReplayer.cc b/src/tools/cephfs_mirror/PeerReplayer.cc index 8cb8dbdd183..f5189cde582 100644 --- a/src/tools/cephfs_mirror/PeerReplayer.cc +++ b/src/tools/cephfs_mirror/PeerReplayer.cc @@ -443,16 +443,17 @@ void PeerReplayer::update_directory_current_sync_perf_counters( perf->set(l_cephfs_mirror_directory_current_eta_seconds, 0); }; - if (sync_stat.failed) { + switch (get_dir_sync_state(sync_stat)) { + case DirSyncState::Failed: perf->set(l_cephfs_mirror_directory_dir_state, 2); clear_current(); return; - } - - if (!sync_stat.current_syncing_snap) { + case DirSyncState::Idle: perf->set(l_cephfs_mirror_directory_dir_state, 0); clear_current(); return; + case DirSyncState::Syncing: + break; } perf->set(l_cephfs_mirror_directory_dir_state, 1); @@ -972,7 +973,8 @@ void PeerReplayer::remove_persisted_dir_sync_stat(const std::string &dir_root) { void PeerReplayer::add_live_sync_metrics_to_persist(json_spirit::mObject &obj, SnapSyncStat &sync_stat) { - if (sync_stat.current_syncing_snap) { + switch (get_dir_sync_state(sync_stat)) { + case DirSyncState::Syncing: { json_spirit::mObject snap; snap["id"] = json_spirit::mValue(static_cast(sync_stat.current_syncing_snap->first)); @@ -1055,13 +1057,17 @@ void PeerReplayer::add_live_sync_metrics_to_persist(json_spirit::mObject &obj, obj["state"] = json_spirit::mValue("syncing"); obj["current_syncing_snap"] = json_spirit::mValue(snap); - } else if (sync_stat.failed) { + break; + } + case DirSyncState::Failed: obj["state"] = json_spirit::mValue("failed"); if (sync_stat.last_failed_reason) { obj["failure_reason"] = json_spirit::mValue(*sync_stat.last_failed_reason); } - } else { + break; + case DirSyncState::Idle: obj["state"] = json_spirit::mValue("idle"); + break; } } @@ -3736,14 +3742,17 @@ double PeerReplayer::compute_eta(const PeerReplayer::SnapSyncStat& sync_stat) { } void PeerReplayer::dump_sync_stat(Formatter *f, const SnapSyncStat &sync_stat) { - if (sync_stat.failed) { + switch (get_dir_sync_state(sync_stat)) { + case DirSyncState::Failed: f->dump_string("state", "failed"); if (sync_stat.last_failed_reason) { f->dump_string("failure_reason", *sync_stat.last_failed_reason); } - } else if (!sync_stat.current_syncing_snap) { + break; + case DirSyncState::Idle: f->dump_string("state", "idle"); - } else { + break; + case DirSyncState::Syncing: f->dump_string("state", "syncing"); f->open_object_section("current_syncing_snap"); f->dump_unsigned("id", (*sync_stat.current_syncing_snap).first); @@ -3815,6 +3824,7 @@ void PeerReplayer::dump_sync_stat(Formatter *f, const SnapSyncStat &sync_stat) { else f->dump_string("eta", format_time(compute_eta(sync_stat))); f->close_section(); //current_syncing_snap + break; } if (sync_stat.last_synced_snap) { f->open_object_section("last_synced_snap"); diff --git a/src/tools/cephfs_mirror/PeerReplayer.h b/src/tools/cephfs_mirror/PeerReplayer.h index 0a12fe87d25..40f5cc637e7 100644 --- a/src/tools/cephfs_mirror/PeerReplayer.h +++ b/src/tools/cephfs_mirror/PeerReplayer.h @@ -440,6 +440,22 @@ private: boost::optional datasync_queue_wait_start_time; // until first pop; for in-progress display }; + enum class DirSyncState { + Idle, + Syncing, + Failed, + }; + + static DirSyncState get_dir_sync_state(const SnapSyncStat &sync_stat) { + if (sync_stat.current_syncing_snap) { + return DirSyncState::Syncing; + } + if (sync_stat.failed) { + return DirSyncState::Failed; + } + return DirSyncState::Idle; + } + void _inc_failed_count(const std::string &dir_root) { auto max_failures = g_ceph_context->_conf.get_val( "cephfs_mirror_max_consecutive_failures_per_directory");