Skip to content

Commit 93e6259

Browse files
authored
Merge pull request #20 from nuclearcat/cleanup-broken-cache
Validate and clean cache on startup from broken pairs
2 parents 68696b3 + 22c4c2a commit 93e6259

2 files changed

Lines changed: 97 additions & 1 deletion

File tree

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ async fn initial_setup() -> Option<RustlsConfig> {
305305
std::fs::create_dir(cache_dir).unwrap();
306306
}
307307

308+
let _validation = tokio::spawn(storcaching::validate_cache(cache_dir.to_string()));
308309
let _handle = tokio::spawn(storcaching::cache_loop(cache_dir));
309310

310311
if !std::path::Path::new(download_dir).exists() {

src/storcaching.rs

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{debug_log, get_config_content};
22
use serde::Deserialize;
33
use std::cmp::Ordering;
4-
use std::collections::BinaryHeap;
4+
use std::collections::{BinaryHeap, HashSet};
55
use std::fs;
66
use std::time::{SystemTime, UNIX_EPOCH};
77
use tokio::time::{Duration, Instant};
@@ -369,3 +369,98 @@ pub async fn cache_loop(cache_dir: &str) {
369369
tokio::time::sleep(Duration::from_secs(HOUSEKEEPING_INTERVAL_SECS)).await;
370370
}
371371
}
372+
373+
fn remove_zero_sized_files(cache_dir: &str) -> u64 {
374+
let mut removed = 0;
375+
let entries = match fs::read_dir(cache_dir) {
376+
Ok(entries) => entries,
377+
Err(e) => {
378+
eprintln!("Error reading cache directory during zero-sized cleanup: {}", e);
379+
return 0;
380+
}
381+
};
382+
383+
for entry in entries.flatten() {
384+
let path = entry.path();
385+
let metadata = match entry.metadata() {
386+
Ok(metadata) => metadata,
387+
Err(_) => continue,
388+
};
389+
390+
if !metadata.is_file() || metadata.len() != 0 {
391+
continue;
392+
}
393+
394+
if let Err(e) = fs::remove_file(&path) {
395+
debug_log!("Failed to remove zero-sized file {:?}: {}", path, e);
396+
} else {
397+
removed += 1;
398+
}
399+
}
400+
401+
removed
402+
}
403+
404+
fn remove_orphan_files(cache_dir: &str) -> u64 {
405+
let entries = match fs::read_dir(cache_dir) {
406+
Ok(entries) => entries,
407+
Err(e) => {
408+
eprintln!("Error reading cache directory during orphan cleanup: {}", e);
409+
return 0;
410+
}
411+
};
412+
413+
let mut contents = HashSet::new();
414+
let mut headers = HashSet::new();
415+
416+
for entry in entries.flatten() {
417+
let path = match entry.path().to_str() {
418+
Some(path) => path.to_string(),
419+
None => continue,
420+
};
421+
422+
if let Some(base) = path.strip_suffix(".content") {
423+
contents.insert(base.to_string());
424+
} else if let Some(base) = path.strip_suffix(".headers") {
425+
headers.insert(base.to_string());
426+
}
427+
}
428+
429+
let mut removed = 0;
430+
431+
for base in contents.difference(&headers) {
432+
let file = format!("{}.content", base);
433+
if let Err(e) = fs::remove_file(&file) {
434+
debug_log!("Failed to remove orphan content {}: {}", file, e);
435+
} else {
436+
removed += 1;
437+
}
438+
}
439+
440+
for base in headers.difference(&contents) {
441+
let file = format!("{}.headers", base);
442+
if let Err(e) = fs::remove_file(&file) {
443+
debug_log!("Failed to remove orphan headers {}: {}", file, e);
444+
} else {
445+
removed += 1;
446+
}
447+
}
448+
449+
removed
450+
}
451+
452+
fn run_cache_validation(cache_dir: String) {
453+
let zero_removed = remove_zero_sized_files(&cache_dir);
454+
let orphan_removed = remove_orphan_files(&cache_dir);
455+
456+
println!(
457+
"[cache-validation] removed {} zero-sized files and {} orphaned cache entries.",
458+
zero_removed, orphan_removed
459+
);
460+
}
461+
462+
pub async fn validate_cache(cache_dir: String) {
463+
if let Err(e) = tokio::task::spawn_blocking(move || run_cache_validation(cache_dir)).await {
464+
eprintln!("Cache validation task failed: {}", e);
465+
}
466+
}

0 commit comments

Comments
 (0)