mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-16 18:08:21 +00:00
feat(scanner): expose cycle observability controls (#3147)
Co-authored-by: Henry Guo <marshawcoco@users.noreply.github.com>
This commit is contained in:
@@ -438,6 +438,7 @@ async fn run_data_scanner_cycle(ctx: &CancellationToken, storeapi: &Arc<ECStore>
|
||||
background_heal_info.bitrot_start_cycle,
|
||||
background_heal_info.bitrot_start_time,
|
||||
);
|
||||
let _scan_mode_guard = ScannerScanModeGuard::new(scan_mode);
|
||||
if let Some(new_heal_info) =
|
||||
background_heal_info_for_scan_start(background_heal_info.clone(), cycle_info.current, scan_mode, Utc::now())
|
||||
{
|
||||
@@ -475,6 +476,7 @@ async fn run_data_scanner_cycle(ctx: &CancellationToken, storeapi: &Arc<ECStore>
|
||||
cycle_info.next += 1;
|
||||
cycle_info.current = 0;
|
||||
cycle_info.cycle_completed.push(Utc::now());
|
||||
global_metrics().clear_current_scan_mode();
|
||||
|
||||
info!(duration = ?now.elapsed(), cycles_total=cycle_info.cycle_completed.len(), "Success run data scanner cycle");
|
||||
|
||||
@@ -553,6 +555,21 @@ pub async fn run_data_scanner(ctx: CancellationToken, storeapi: Arc<ECStore>) ->
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct ScannerScanModeGuard;
|
||||
|
||||
impl ScannerScanModeGuard {
|
||||
fn new(scan_mode: HealScanMode) -> Self {
|
||||
global_metrics().set_current_scan_mode(scan_mode);
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ScannerScanModeGuard {
|
||||
fn drop(&mut self) {
|
||||
global_metrics().clear_current_scan_mode();
|
||||
}
|
||||
}
|
||||
|
||||
/// Store data usage info in backend. Will store all objects sent on the receiver until closed.
|
||||
#[instrument(skip(ctx, storeapi))]
|
||||
pub async fn store_data_usage_in_backend(
|
||||
|
||||
@@ -57,7 +57,6 @@ use tracing::{debug, error, info, warn};
|
||||
|
||||
const DATA_USAGE_UPDATE_DIR_CYCLES: u32 = 16;
|
||||
const DATA_SCANNER_COMPACT_LEAST_OBJECT: usize = 500;
|
||||
const YIELD_EVERY_N_OBJECTS: u64 = 128;
|
||||
const DATA_SCANNER_COMPACT_AT_CHILDREN: usize = 10000;
|
||||
const DATA_SCANNER_COMPACT_AT_FOLDERS: usize = DATA_SCANNER_COMPACT_AT_CHILDREN / 4;
|
||||
const DATA_SCANNER_FORCE_COMPACT_AT_FOLDERS: usize = 250_000;
|
||||
@@ -144,6 +143,17 @@ fn scanner_excess_folders_threshold() -> u64 {
|
||||
)
|
||||
}
|
||||
|
||||
fn scanner_yield_every_n_objects() -> u64 {
|
||||
rustfs_utils::get_env_u64(
|
||||
rustfs_config::ENV_SCANNER_YIELD_EVERY_N_OBJECTS,
|
||||
rustfs_config::DEFAULT_SCANNER_YIELD_EVERY_N_OBJECTS,
|
||||
)
|
||||
}
|
||||
|
||||
fn should_yield_after_object(object_count: u64, yield_every: u64) -> bool {
|
||||
yield_every > 0 && object_count.is_multiple_of(yield_every)
|
||||
}
|
||||
|
||||
fn should_alert_excessive_versions(remaining_versions: usize, cumulative_size: i64) -> (bool, bool) {
|
||||
let too_many_versions = remaining_versions as u64 >= scanner_excess_versions_threshold();
|
||||
let too_large_versions = cumulative_size > 0 && cumulative_size as u64 >= scanner_excess_version_size_threshold();
|
||||
@@ -916,6 +926,7 @@ impl FolderScanner {
|
||||
let mut new_folders: Vec<CachedFolder> = Vec::new();
|
||||
let mut found_objects = false;
|
||||
let mut object_count: u64 = 0;
|
||||
let yield_every_objects = scanner_yield_every_n_objects();
|
||||
|
||||
let dir_path = path_join_buf(&[&self.root, &folder.name]);
|
||||
|
||||
@@ -1098,7 +1109,7 @@ impl FolderScanner {
|
||||
|
||||
timer.sleep().await;
|
||||
|
||||
if object_count.is_multiple_of(YIELD_EVERY_N_OBJECTS) {
|
||||
if should_yield_after_object(object_count, yield_every_objects) {
|
||||
tokio::task::yield_now().await;
|
||||
}
|
||||
}
|
||||
@@ -1816,6 +1827,29 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_scanner_yield_every_n_objects_uses_env() {
|
||||
with_var(rustfs_config::ENV_SCANNER_YIELD_EVERY_N_OBJECTS, Some("32"), || {
|
||||
assert_eq!(scanner_yield_every_n_objects(), 32);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_scanner_yield_every_n_objects_uses_default() {
|
||||
with_var_unset(rustfs_config::ENV_SCANNER_YIELD_EVERY_N_OBJECTS, || {
|
||||
assert_eq!(scanner_yield_every_n_objects(), rustfs_config::DEFAULT_SCANNER_YIELD_EVERY_N_OBJECTS);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_yield_after_object_respects_interval_and_disable() {
|
||||
assert!(!should_yield_after_object(127, 128));
|
||||
assert!(should_yield_after_object(128, 128));
|
||||
assert!(!should_yield_after_object(128, 0));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_record_failed_prunes_to_max_entries() {
|
||||
|
||||
Reference in New Issue
Block a user