refactor(ecstore): make store-to-disk error narrowing named and fallible (#6626)

refactor(ecstore): make store-to-disk error narrowing a named fallible operation

Backlog#1845 step 4. The blanket impl From<StorageError> for DiskError let ? silently push store-only errors (locks, buckets, quotas) across the disk boundary into DiskError::other, where the rendered message fragments reduce_errs quorum buckets. Same story for the blanket From<StorageError> for rustfs_filemeta::Error and its other() catch-all.

Both impls are replaced by named, fallible methods: StorageError::narrow_to_disk() and StorageError::narrow_to_filemeta(). Variants with an identity on the far side map across unchanged - including the two documented lossy collapses (SlowDown -> TooManyOpenFiles, StorageFull -> DiskFull) that the round-trip tests pin - and everything else returns Err(self) so the call site decides what crossing the boundary means. Removing the impls let the compiler enumerate every conversion site; the census that scoped this issue had found 5, the compiler found 33.

Call sites keep their existing behavior: the io identity bridge and the generic sites fold Err into the io-backed other() exactly as the old catch-all did (identity still recoverable by downcast), listing paths use one shared to_filemeta_err helper, and the two sites that relied on the SlowDown collapse now construct DiskError::TooManyOpenFiles directly so the loss is visible where it happens. No behavior change intended anywhere; the io::Error bridge itself is untouched by design.

Ref rustfs/backlog#1845
This commit is contained in:
Zhengchao An
2026-08-26 12:32:37 +08:00
committed by GitHub
parent 1590d9107b
commit aa56d4b847
11 changed files with 155 additions and 88 deletions
+2 -2
View File
@@ -351,7 +351,7 @@ impl From<std::io::Error> for DiskError {
// classification instead of degrading to `DiskError::Io`, which
// quorum aggregation (`reduce_errs`) would count as a distinct error.
Err(io_error) => match io_error.downcast::<crate::error::StorageError>() {
Ok(storage_error) => storage_error.into(),
Ok(storage_error) => storage_error.narrow_to_disk().unwrap_or_else(DiskError::other),
Err(io_error) => DiskError::Io(io_error),
},
}
@@ -1189,7 +1189,7 @@ mod tests {
&storage,
crate::error::StorageError::RemoteClientUnavailable(detail) if detail == "handshake timed out"
));
let narrowed: DiskError = storage.into();
let narrowed: DiskError = storage.narrow_to_disk().expect("typed variant must narrow");
assert_eq!(narrowed, original);
assert!(matches!(
&narrowed,
+1 -1
View File
@@ -5096,7 +5096,7 @@ impl LocalDisk {
ensure_data_usage_layout(&io_root)
.await
.map_err(DiskError::from)
.map_err(|e| e.narrow_to_disk().unwrap_or_else(DiskError::other))
.inspect_err(|err| {
log_startup_disk_error("ensure_data_usage_layout", &root, err);
})?;