fix(ecstore): suppress missing rollback rename warnings (#4792)

This commit is contained in:
cxymds
2026-07-13 19:05:09 +08:00
committed by GitHub
parent 724d3ea0bc
commit 7ece747eab
2 changed files with 209 additions and 44 deletions
+17 -36
View File
@@ -26,7 +26,7 @@ use std::{
};
use tokio::fs;
use tokio::sync::{OwnedSemaphorePermit, Semaphore, SemaphorePermit};
use tracing::{debug, warn};
use tracing::warn;
/// Check path length according to OS limits.
pub fn check_path_length(path_name: &str) -> Result<()> {
@@ -527,7 +527,7 @@ async fn reliable_rename_inner(
src_file_path: impl AsRef<Path>,
dst_file_path: impl AsRef<Path>,
base_dir: impl AsRef<Path>,
warn_on_failure: bool,
warn_on_missing_source: bool,
) -> io::Result<()> {
if let Some(parent) = dst_file_path.as_ref().parent()
&& !file_exists(parent)
@@ -542,32 +542,8 @@ async fn reliable_rename_inner(
i += 1;
continue;
}
if warn_on_failure {
// NotFound is an expected outcome for speculative renames (staging
// a dataDir that inline objects never had, trashing an already-
// removed tmp path, restoring an absent rollback backup): those
// callers treat FileNotFound as acceptable, and on per-request
// delete paths a WARN becomes a log storm (one line per disk per
// DELETE). Keep it at debug so quorum-masked cases (e.g. a tmp
// file lost before a commit rename) stay diagnosable; genuine
// failures keep the WARN. The error is returned either way.
if e.kind() == io::ErrorKind::NotFound {
debug!(
"reliable_rename failed. src_file_path: {:?}, dst_file_path: {:?}, base_dir: {:?}, err: {:?}",
src_file_path.as_ref(),
dst_file_path.as_ref(),
base_dir.as_ref(),
e
);
} else {
warn!(
"reliable_rename failed. src_file_path: {:?}, dst_file_path: {:?}, base_dir: {:?}, err: {:?}",
src_file_path.as_ref(),
dst_file_path.as_ref(),
base_dir.as_ref(),
e
);
}
if warn_on_missing_source || e.kind() != io::ErrorKind::NotFound {
warn_reliable_rename_failure(src_file_path.as_ref(), dst_file_path.as_ref(), base_dir.as_ref(), &e);
}
return Err(e);
}
@@ -578,6 +554,13 @@ async fn reliable_rename_inner(
Ok(())
}
fn warn_reliable_rename_failure(src_file_path: &Path, dst_file_path: &Path, base_dir: &Path, err: &io::Error) {
warn!(
"reliable_rename failed. src_file_path: {:?}, dst_file_path: {:?}, base_dir: {:?}, err: {:?}",
src_file_path, dst_file_path, base_dir, err
);
}
/// Whether a failed `rename` in [`reliable_rename_inner`] should be retried.
///
/// Only the first failure is retried, and `NotFound` is never retried: the
@@ -755,24 +738,22 @@ mod tests {
}
#[tokio::test]
async fn rename_all_ignore_missing_source_returns_ok() {
async fn rename_all_ignore_missing_source_returns_ok_without_warn() {
let temp_dir = tempdir().expect("create temp dir");
let src = temp_dir.path().join("missing");
let dst = temp_dir.path().join("dst");
let (logs, _guard) = warn_capture();
rename_all_ignore_missing_source(&src, &dst, temp_dir.path())
.await
.expect("missing cleanup source must be ignored");
assert!(!dst.exists());
assert!(!logs.contents().contains("reliable_rename failed"));
}
#[tokio::test]
async fn rename_all_missing_source_skips_rename_warn() {
// Callers like delete_version's rollback staging accept FileNotFound
// (inline objects have no dataDir), so a missing source must not emit
// the per-disk "reliable_rename failed" WARN — under delete storms it
// was pure log noise. The error itself is still returned.
async fn rename_all_missing_source_still_warns() {
let temp_dir = tempdir().expect("create temp dir");
let src = temp_dir.path().join("missing");
let dst = temp_dir.path().join("dst");
@@ -785,8 +766,8 @@ mod tests {
assert!(matches!(err, DiskError::FileNotFound));
let captured = logs.contents();
assert!(
!captured.contains("reliable_rename failed"),
"NotFound must not emit the reliable_rename WARN, got: {captured}"
captured.contains("reliable_rename failed"),
"ordinary missing-source failures must keep the WARN, got: {captured}"
);
}