mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-19 11:06:17 +00:00
feat(heal): expose scanner heal admission outcomes (#3292)
Co-authored-by: Henry Guo <marshawcoco@users.noreply.github.com> Co-authored-by: cxymds <Cxymds@qq.com>
This commit is contained in:
@@ -1334,9 +1334,6 @@ impl Metrics {
|
|||||||
Metric::HealCheck => {
|
Metric::HealCheck => {
|
||||||
self.record_scanner_source_checked(ScannerWorkSource::Heal, count);
|
self.record_scanner_source_checked(ScannerWorkSource::Heal, count);
|
||||||
}
|
}
|
||||||
Metric::HealAbandonedObject => {
|
|
||||||
self.record_scanner_source_executed(ScannerWorkSource::Heal, count);
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2167,7 +2164,7 @@ mod tests {
|
|||||||
.find(|work| work.source == ScannerWorkSource::Heal.as_str())
|
.find(|work| work.source == ScannerWorkSource::Heal.as_str())
|
||||||
.expect("heal source work should be visible");
|
.expect("heal source work should be visible");
|
||||||
assert_eq!(heal.checked, 5);
|
assert_eq!(heal.checked, 5);
|
||||||
assert_eq!(heal.executed, 6);
|
assert_eq!(heal.executed, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|||||||
@@ -176,6 +176,29 @@ fn record_scanner_replication_admission(metrics: &Metrics, admission: Replicatio
|
|||||||
metrics.record_scanner_source_work(ScannerWorkSource::BucketReplication, work);
|
metrics.record_scanner_source_work(ScannerWorkSource::BucketReplication, work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn scanner_heal_source(scan_mode: HealScanMode) -> ScannerWorkSource {
|
||||||
|
match scan_mode {
|
||||||
|
HealScanMode::Deep => ScannerWorkSource::Bitrot,
|
||||||
|
HealScanMode::Unknown | HealScanMode::Normal => ScannerWorkSource::Heal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn record_scanner_heal_admission(metrics: &Metrics, scan_mode: HealScanMode, admission: Result<HealAdmissionResult, ()>) -> bool {
|
||||||
|
let (work, admitted) = match admission {
|
||||||
|
Ok(HealAdmissionResult::Accepted) => (ScannerSourceWorkUpdate::queued(1), true),
|
||||||
|
Ok(HealAdmissionResult::Merged) => (
|
||||||
|
ScannerSourceWorkUpdate {
|
||||||
|
skipped: 1,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
Ok(HealAdmissionResult::Full | HealAdmissionResult::Dropped(_)) | Err(_) => (ScannerSourceWorkUpdate::missed(1), false),
|
||||||
|
};
|
||||||
|
metrics.record_scanner_source_work(scanner_heal_source(scan_mode), work);
|
||||||
|
admitted
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
struct PendingScannerAccounting<'a> {
|
struct PendingScannerAccounting<'a> {
|
||||||
object: &'a ObjectInfo,
|
object: &'a ObjectInfo,
|
||||||
@@ -824,6 +847,8 @@ impl ScannerItem {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
let admission = result.as_ref().copied().map_err(|_| ());
|
||||||
|
let admitted = record_scanner_heal_admission(global_metrics(), scan_mode, admission);
|
||||||
match result {
|
match result {
|
||||||
Ok(HealAdmissionResult::Accepted | HealAdmissionResult::Merged) => {}
|
Ok(HealAdmissionResult::Accepted | HealAdmissionResult::Merged) => {}
|
||||||
Ok(result @ (HealAdmissionResult::Full | HealAdmissionResult::Dropped(_))) => {
|
Ok(result @ (HealAdmissionResult::Full | HealAdmissionResult::Dropped(_))) => {
|
||||||
@@ -836,7 +861,9 @@ impl ScannerItem {
|
|||||||
}
|
}
|
||||||
Err(e) => warn!("enqueue_heal: failed to submit heal request: {}", e),
|
Err(e) => warn!("enqueue_heal: failed to submit heal request: {}", e),
|
||||||
}
|
}
|
||||||
done_heal();
|
if admitted {
|
||||||
|
done_heal();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alert_excessive_versions(&self, remaining_versions: usize, cumulative_size: i64) {
|
fn alert_excessive_versions(&self, remaining_versions: usize, cumulative_size: i64) {
|
||||||
@@ -2165,6 +2192,68 @@ mod tests {
|
|||||||
assert_eq!(replication.missed, 1);
|
assert_eq!(replication.missed, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_scanner_heal_admission_accounting_maps_normal_scan_to_heal() {
|
||||||
|
let metrics = Metrics::new();
|
||||||
|
|
||||||
|
record_scanner_heal_admission(&metrics, HealScanMode::Normal, Ok(HealAdmissionResult::Accepted));
|
||||||
|
record_scanner_heal_admission(&metrics, HealScanMode::Normal, Ok(HealAdmissionResult::Merged));
|
||||||
|
record_scanner_heal_admission(&metrics, HealScanMode::Normal, Ok(HealAdmissionResult::Full));
|
||||||
|
record_scanner_heal_admission(
|
||||||
|
&metrics,
|
||||||
|
HealScanMode::Normal,
|
||||||
|
Ok(HealAdmissionResult::Dropped(
|
||||||
|
rustfs_common::heal_channel::HealAdmissionDropReason::QueueFull,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
record_scanner_heal_admission(&metrics, HealScanMode::Normal, Err(()));
|
||||||
|
|
||||||
|
let report = metrics.report().await;
|
||||||
|
let heal = report
|
||||||
|
.source_work
|
||||||
|
.iter()
|
||||||
|
.find(|work| work.source == ScannerWorkSource::Heal.as_str())
|
||||||
|
.expect("heal source work should be visible");
|
||||||
|
let bitrot = report
|
||||||
|
.source_work
|
||||||
|
.iter()
|
||||||
|
.find(|work| work.source == ScannerWorkSource::Bitrot.as_str())
|
||||||
|
.expect("bitrot source work should be visible");
|
||||||
|
|
||||||
|
assert_eq!(heal.queued, 1);
|
||||||
|
assert_eq!(heal.skipped, 1);
|
||||||
|
assert_eq!(heal.missed, 3);
|
||||||
|
assert_eq!(heal.executed, 0);
|
||||||
|
assert_eq!(bitrot.queued + bitrot.skipped + bitrot.missed + bitrot.executed, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_scanner_heal_admission_accounting_maps_deep_scan_to_bitrot() {
|
||||||
|
let metrics = Metrics::new();
|
||||||
|
|
||||||
|
record_scanner_heal_admission(&metrics, HealScanMode::Deep, Ok(HealAdmissionResult::Accepted));
|
||||||
|
record_scanner_heal_admission(&metrics, HealScanMode::Deep, Ok(HealAdmissionResult::Merged));
|
||||||
|
record_scanner_heal_admission(&metrics, HealScanMode::Deep, Ok(HealAdmissionResult::Full));
|
||||||
|
|
||||||
|
let report = metrics.report().await;
|
||||||
|
let heal = report
|
||||||
|
.source_work
|
||||||
|
.iter()
|
||||||
|
.find(|work| work.source == ScannerWorkSource::Heal.as_str())
|
||||||
|
.expect("heal source work should be visible");
|
||||||
|
let bitrot = report
|
||||||
|
.source_work
|
||||||
|
.iter()
|
||||||
|
.find(|work| work.source == ScannerWorkSource::Bitrot.as_str())
|
||||||
|
.expect("bitrot source work should be visible");
|
||||||
|
|
||||||
|
assert_eq!(bitrot.queued, 1);
|
||||||
|
assert_eq!(bitrot.skipped, 1);
|
||||||
|
assert_eq!(bitrot.missed, 1);
|
||||||
|
assert_eq!(bitrot.executed, 0);
|
||||||
|
assert_eq!(heal.queued + heal.skipped + heal.missed + heal.executed, 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn test_excessive_version_alert_thresholds_use_env() {
|
fn test_excessive_version_alert_thresholds_use_env() {
|
||||||
|
|||||||
Reference in New Issue
Block a user