[pve-devel] [PATCH proxmox-offline-mirror v2 4/5] pool: gc: remove empty directories under link_dir

Stoiko Ivanov s.ivanov at proxmox.com
Tue Jul 9 12:47:04 CEST 2024


garbage collection currently is quite aggressive in removing all files
under the link_dir, which are not a hard-link to a checksum file.
removing directories that remain empty below the link_dir should thus
not too dangerous.

without this patch, removing a snapshot on a mirror, running gc there,
and syncing everything to a medium, leaves the medium with an
hierarchy of empty directories below the removed snapshot (the files
get cleaned up the directories remain).

using WalkDir::content_first() seems better than to check for
emptiness after each file-removal [0]

[0] https://docs.rs/walkdir/latest/walkdir/struct.WalkDir.html#method.contents_first

Signed-off-by: Stoiko Ivanov <s.ivanov at proxmox.com>
---
 src/pool.rs | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/src/pool.rs b/src/pool.rs
index b4f2a6a..56dcbb4 100644
--- a/src/pool.rs
+++ b/src/pool.rs
@@ -451,6 +451,7 @@ impl PoolLockGuard<'_> {
     /// Run a garbage collection, removing
     /// - any checksum files that have no links outside of `pool_dir`
     /// - any files in `link_dir` that have no corresponding checksum files
+    /// - any empty directories below `link_dir` remaining after the file removal
     pub(crate) fn gc(&self) -> Result<(usize, u64), Error> {
         let (inode_map, _link_count) = self.get_inode_csum_map()?;
 
@@ -459,7 +460,8 @@ impl PoolLockGuard<'_> {
 
         let handle_entry = |entry: Result<walkdir::DirEntry, walkdir::Error>,
                             count: &mut usize,
-                            size: &mut u64|
+                            size: &mut u64,
+                            remove_empty_dir: bool|
          -> Result<(), Error> {
             let path = entry?.into_path();
             if path == self.lock_path() {
@@ -467,6 +469,10 @@ impl PoolLockGuard<'_> {
             }
 
             let meta = path.metadata()?;
+            if remove_empty_dir && meta.is_dir() && path.read_dir()?.next().is_none() {
+                std::fs::remove_dir(path)?;
+                return Ok(());
+            }
             if !meta.is_file() {
                 return Ok(());
             };
@@ -507,11 +513,12 @@ impl PoolLockGuard<'_> {
         };
 
         WalkDir::new(&self.pool.link_dir)
+            .contents_first(true)
             .into_iter()
-            .try_for_each(|entry| handle_entry(entry, &mut count, &mut size))?;
+            .try_for_each(|entry| handle_entry(entry, &mut count, &mut size, true))?;
         WalkDir::new(&self.pool.pool_dir)
             .into_iter()
-            .try_for_each(|entry| handle_entry(entry, &mut count, &mut size))?;
+            .try_for_each(|entry| handle_entry(entry, &mut count, &mut size, false))?;
 
         Ok((count, size))
     }
-- 
2.39.2





More information about the pve-devel mailing list