From 2f0143ef15a7371bec232c00edc3b5ed5fe6fdc4 Mon Sep 17 00:00:00 2001 From: ormandj Date: Wed, 7 Oct 2026 03:02:47 -0500 Subject: [PATCH] fix(ecstore): skip warning for absent .minio.sys volume (#8373) * fix(ecstore): skip warning for absent .minio.sys volume Startup MinIO migrations read from .minio.sys and treat its absence as expected, but resolve_read_all_result logged a disk_local_read_version_fallback warning for every such read. Keep the access check and the VolumeNotFound return, and skip only the warning for the migrating metadata volume. Refs #8372 * test(ecstore): cover .minio.sys descendants and lookalike volumes --------- Co-authored-by: Chris --- crates/ecstore/src/disk/local.rs | 68 ++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/crates/ecstore/src/disk/local.rs b/crates/ecstore/src/disk/local.rs index 1e41c2dce..7480ddaae 100644 --- a/crates/ecstore/src/disk/local.rs +++ b/crates/ecstore/src/disk/local.rs @@ -7084,14 +7084,21 @@ impl LocalDisk { && let Err(access_err) = access(volume_dir).await && access_err.kind() == ErrorKind::NotFound { - warn!( - event = EVENT_DISK_LOCAL_READ_VERSION_FALLBACK, - component = LOG_COMPONENT_ECSTORE, - subsystem = LOG_SUBSYSTEM_DISK_LOCAL, - reason = "read_all_data_with_dmtime_volume_not_found", - error = ?access_err, - "Disk local read fallback failed" - ); + // An absent legacy MinIO volume is expected: startup migrations probe it. + let migrating_meta = volume == super::MIGRATING_META_BUCKET + || volume + .strip_prefix(super::MIGRATING_META_BUCKET) + .is_some_and(|rest| rest.starts_with('/')); + if !migrating_meta { + warn!( + event = EVENT_DISK_LOCAL_READ_VERSION_FALLBACK, + component = LOG_COMPONENT_ECSTORE, + subsystem = LOG_SUBSYSTEM_DISK_LOCAL, + reason = "read_all_data_with_dmtime_volume_not_found", + error = ?access_err, + "Disk local read fallback failed" + ); + } return Err(DiskError::VolumeNotFound); } @@ -17671,6 +17678,51 @@ mod test { assert!(!logs.contents().contains("reliable_rename failed")); } + #[tokio::test(flavor = "current_thread")] + async fn read_all_data_absent_migrating_meta_volume_does_not_warn() { + let dir = tempfile::tempdir().expect("temp dir should be created"); + let endpoint = Endpoint::try_from(dir.path().to_str().expect("temp dir should be utf8")).expect("endpoint should parse"); + let disk = LocalDisk::new(&endpoint, false).await.expect("local disk should be created"); + + let logs = CapturedLogs::default(); + let subscriber = tracing_subscriber::fmt() + .with_writer(logs.clone()) + .with_ansi(false) + .without_time() + .finish(); + let _guard = tracing::subscriber::set_default(subscriber); + + let read_absent = |volume: &str| { + let volume_dir = dir.path().join(volume); + let file_path = volume_dir + .join("buckets/bucket/.replication/resync.bin") + .join(STORAGE_FORMAT_FILE); + let disk = &disk; + let volume = volume.to_string(); + async move { disk.read_all_data(&volume, &volume_dir, &file_path).await } + }; + + let cases = [ + ("missing-bucket", true), + (".minio.sysfoo", true), + (super::super::MIGRATING_META_BUCKET, false), + (".minio.sys/buckets", false), + ]; + for (volume, expect_warning) in cases { + logs.buffer + .lock() + .expect("captured logs mutex should not be poisoned") + .clear(); + let err = read_absent(volume).await.expect_err("absent volume should fail"); + assert!(matches!(err, DiskError::VolumeNotFound), "volume {volume}: {err:?}"); + assert_eq!( + logs.contents().contains("read_all_data_with_dmtime_volume_not_found"), + expect_warning, + "volume {volume}" + ); + } + } + #[tokio::test(flavor = "current_thread")] async fn test_delete_versions_missing_inline_data_dir_does_not_warn() { use tempfile::tempdir;