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 8c1e3e9..ff3a9eb 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.
 
-Version: 0.20100522
+Version: 0.20101024
 USAGE
 }
 
@@ -216,13 +216,44 @@ while (<STDIN>) {
 }
 
 # Garbage collection
-print STDERR "\nGarbage collection in '$link_dir'...";
+print STDERR "\nGarbage collection in '$link_dir'...\n";
 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 $?";
-print STDERR "\nDone.\n";
+print STDERR "Done.\n";
 
 exit(0);