diff --git a/src/gc.rs b/src/gc.rs index 0e8e0b6..6f03501 100644 --- a/src/gc.rs +++ b/src/gc.rs @@ -3,7 +3,7 @@ use std::collections::{HashMap, HashSet}; use std::path::Path; use std::time::{SystemTime, UNIX_EPOCH}; -type BlobInfo = (String, String, u64); // (org, repo, size) +type BlobLocation = (String, String, u64); // (org, repo, size) type UnreferencedBlob = (String, String, String, u64); // (org, repo, digest, size) #[derive(Debug, Serialize, Deserialize)] @@ -153,8 +153,8 @@ fn extract_blob_references(manifest_json: &str, referenced: &mut HashSet /// Scan all blobs in storage fn scan_all_blobs( stats: &mut GcStats, -) -> Result, Box> { - let mut all_blobs = HashMap::new(); // digest -> (org, repo, size) +) -> Result>, Box> { + let mut all_blobs: HashMap> = HashMap::new(); let blobs_dir = Path::new("./tmp/blobs"); if !blobs_dir.exists() { @@ -188,7 +188,11 @@ fn scan_all_blobs( let digest = blob_entry.file_name().to_string_lossy().to_string(); let size = blob_entry.metadata()?.len(); - all_blobs.insert(digest.clone(), (org.clone(), repo.clone(), size)); + // Track all locations for this digest + all_blobs + .entry(digest) + .or_default() + .push((org.clone(), repo.clone(), size)); } } } @@ -198,14 +202,17 @@ fn scan_all_blobs( /// Mark unreferenced blobs for deletion fn mark_unreferenced_blobs( - all_blobs: &HashMap, + all_blobs: &HashMap>, referenced_blobs: &HashSet, ) -> Result, Box> { let mut unreferenced = Vec::new(); - for (digest, (org, repo, size)) in all_blobs { + for (digest, locations) in all_blobs { if !referenced_blobs.contains(digest) { - unreferenced.push((org.clone(), repo.clone(), digest.clone(), *size)); + // Add all locations of this unreferenced blob + for (org, repo, size) in locations { + unreferenced.push((org.clone(), repo.clone(), digest.clone(), *size)); + } } } diff --git a/tests/gc_operations.rs b/tests/gc_operations.rs index 1a95aba..773820e 100644 --- a/tests/gc_operations.rs +++ b/tests/gc_operations.rs @@ -56,7 +56,7 @@ fn test_gc_identifies_unreferenced_blobs() { let result: serde_json::Value = resp.json().unwrap(); assert!(result["blobs_scanned"].as_u64().unwrap() >= 2); - assert!(result["blobs_to_delete"].as_u64().unwrap() >= 1); + assert!(result["blobs_unreferenced"].as_u64().unwrap() >= 1); // Verify orphaned blob still exists (dry-run) let resp = client