dm6: bump version to 0.20101024, more comprehensive garbage collector
authorZygo Blaxell <zblaxell@waya.furryterror.org>
Sun, 24 Oct 2010 21:12:22 +0000 (17:12 -0400)
committerZygo Blaxell <zblaxell@waya.furryterror.org>
Sun, 24 Oct 2010 21:12:22 +0000 (17:12 -0400)
The garbage collector now counts all links to files in the link directory,
and removes files where all links are accounted for within the link
directory.

This enables possible future enhancements, like having something
analogous to --timestamps and --access in faster-dupemerge, without
requiring a special case for each one.

dm6

diff --git a/dm6 b/dm6
index 8c1e3e964f6711ecc7c6f0ec4e9ad32634c7ebe8..ff3a9eb2b57244eed3ac9c8d071ebf58c5afcbf9 100755 (executable)
--- a/dm6
+++ b/dm6
@@ -41,7 +41,7 @@ sub usage {
 Usage: $0 link-dir
 Hashes a NUL-separated list of files on stdin into link-dir.
 
 Usage: $0 link-dir
 Hashes a NUL-separated list of files on stdin into link-dir.
 
-Version: 0.20100522
+Version: 0.20101024
 USAGE
 }
 
 USAGE
 }
 
@@ -216,13 +216,44 @@ while (<STDIN>) {
 }
 
 # Garbage collection
 }
 
 # Garbage collection
-print STDERR "\nGarbage collection in '$link_dir'...";
+print STDERR "\nGarbage collection in '$link_dir'...\n";
 chdir($link_dir) || die "chdir: $link_dir: $!";
 chdir($link_dir) || die "chdir: $link_dir: $!";
-print STDERR "\nRemoving files with link count < 3 and temporary links...";
-system('find . -type f \( -links -3 -o -name ".*" \) -print0 | xargs -0rt rm -f') and die "system: exit status $?";
-print STDERR "\nRemoving empty directories...";
+
+my ($last_inode) = '';
+my @last_links;
+
+sub handle_gc_file {
+       my ($line) = @_;
+       my ($inode, $link) = ($line =~ /^(\S+) (.+)\0$/os);
+       $inode ||= '';
+       if ($inode ne $last_inode) {
+               my ($dev, $ino, $links) = ($last_inode =~ /^(\d+):(\d+):(\d+)$/os);
+               if (defined($links)) {
+                       if ($links && $links == @last_links) {
+                               print STDERR "rm -f @last_links\n";
+                               for my $unlink (@last_links) {
+                                       unlink($unlink) or warn "unlink: $unlink: $!";
+                               }
+                       }
+               } else {
+                       warn "Could not parse '$last_inode' in '$line'" unless $last_inode eq '';
+               }
+               @last_links = ();
+       }
+       $last_inode = $inode;
+       push(@last_links, $link);
+}
+
+print STDERR "Removing files contained entirely in '$link_dir'...\n";
+open(FIND, "find . -type f -printf '%D:%i:%n %p\\0' | sort -z --compress-program=gzip |") or die "open: find: $!";
+while (<FIND>) {
+       handle_gc_file($_);
+}
+handle_gc_file('');
+
+print STDERR "Removing empty directories...\n";
 system("find . -type d -empty -print0 | xargs -0rt rmdir -p --ignore-fail-on-non-empty") and die "system: exit status $?";
 system("find . -type d -empty -print0 | xargs -0rt rmdir -p --ignore-fail-on-non-empty") and die "system: exit status $?";
-print STDERR "\nDone.\n";
+print STDERR "Done.\n";
 
 exit(0);
 
 
 exit(0);