perf(dedup): remove blocking std::fs calls from async context

Two fixes in dedup_service.rs:

1. Rename error path (L234): std::fs::remove_file → tokio::fs::remove_file
   Restructured from map_err closure to match block since .await
   cannot be used inside a sync closure.

2. Integrity verify (L691): fused blocking .exists() + async metadata()
   into a single fs::metadata().await call. Eliminates one stat()
   syscall per blob AND removes the only remaining blocking I/O from
   the verify_integrity hot loop (buffer_unordered × VERIFY_CONCURRENCY).
This commit is contained in:
Dionisio
2026-02-24 13:06:40 +01:00
parent 78ae145af5
commit 962468a1ce
+31 -20
View File
@@ -231,10 +231,14 @@ impl DedupService {
DomainError::internal_error("Dedup", format!("Failed to write temp blob: {}", e))
})?;
fs::rename(&temp_path, &blob_path).await.map_err(|e| {
let _ = std::fs::remove_file(&temp_path);
DomainError::internal_error("Dedup", format!("Failed to move blob: {}", e))
})?;
if let Err(e) = fs::rename(&temp_path, &blob_path).await {
// Clean up temp file asynchronously (never block the Tokio worker)
let _ = fs::remove_file(&temp_path).await;
return Err(DomainError::internal_error(
"Dedup",
format!("Failed to move blob: {}", e),
));
}
// Register in PostgreSQL (ON CONFLICT handles rare race with another writer)
sqlx::query(
@@ -687,10 +691,29 @@ impl DedupService {
let mut issues = Vec::new();
// Check file exists
if !blob_path.exists() {
issues.push(format!("{}: file missing on disk", hash));
return issues;
// Single async metadata() replaces the previous
// blocking .exists() + separate metadata() — one
// stat() syscall instead of two, and non-blocking.
let file_meta = match fs::metadata(&blob_path).await {
Ok(m) => m,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
issues.push(format!("{}: file missing on disk", hash));
return issues;
}
Err(e) => {
issues.push(format!("{}: metadata error ({})", hash, e));
return issues;
}
};
// Check size
if file_meta.len() != expected_size as u64 {
issues.push(format!(
"{}: size mismatch (expected: {}, actual: {})",
hash,
expected_size,
file_meta.len(),
));
}
// Verify hash
@@ -708,18 +731,6 @@ impl DedupService {
}
}
// Check size
if let Ok(file_meta) = fs::metadata(&blob_path).await
&& file_meta.len() != expected_size as u64
{
issues.push(format!(
"{}: size mismatch (expected: {}, actual: {})",
hash,
expected_size,
file_meta.len(),
));
}
issues
}
})