diff options
-rw-r--r-- | doc/manual/nix-collect-garbage.xml | 11 | ||||
-rw-r--r-- | doc/manual/nix-store.xml | 12 | ||||
-rwxr-xr-x | scripts/nix-collect-garbage.in | 16 | ||||
-rw-r--r-- | src/libstore/gc.cc | 17 | ||||
-rw-r--r-- | src/libstore/gc.hh | 6 | ||||
-rw-r--r-- | src/nix-store/main.cc | 25 |
6 files changed, 70 insertions, 17 deletions
diff --git a/doc/manual/nix-collect-garbage.xml b/doc/manual/nix-collect-garbage.xml index adc6c1e730a7..1de50408e01e 100644 --- a/doc/manual/nix-collect-garbage.xml +++ b/doc/manual/nix-collect-garbage.xml @@ -11,6 +11,7 @@ <arg choice='plain'><option>--print-live</option></arg> <arg choice='plain'><option>--print-dead</option></arg> </group> + <arg><option>--min-age</option> <replaceable>age</replaceable></arg> </cmdsynopsis> </refsynopsisdiv> @@ -56,6 +57,16 @@ </listitem> </varlistentry> + <varlistentry> + <term><option>--min-age</option> <replaceable>age</replaceable></term> + <listitem> + <para> + This option corresponds to the <option>--min-age</option> + option in <command>nix-store <option>--gc</option></command>. + </para> + </listitem> + </varlistentry> + </variablelist> </refsection> diff --git a/doc/manual/nix-store.xml b/doc/manual/nix-store.xml index febe02fd4ada..522de60d3696 100644 --- a/doc/manual/nix-store.xml +++ b/doc/manual/nix-store.xml @@ -147,6 +147,7 @@ <arg choice='plain'><option>--print-dead</option></arg> <arg choice='plain'><option>--delete</option></arg> </group> + <arg><option>--min-age</option> <replaceable>age</replaceable></arg> </cmdsynopsis> </refsection> @@ -207,6 +208,17 @@ Each line should contain exactly one store path. </para> + <para> + The option <option>--min-age</option> specifies a minimum time + in hours that an unreachable store path must not have been + used before it is considered dead. The default is 0 (consider + all unreachable store paths dead). Whether a store path has + been used is determined by looking at its access time + (<literal>atime</literal>), so this does not work if the store + is located on a file system that has the + <literal>noatime</literal> option set. + </para> + <warning> <para> You generally will want to use the command diff --git a/scripts/nix-collect-garbage.in b/scripts/nix-collect-garbage.in index 539979cbb6c0..44bcc16bbca0 100755 --- a/scripts/nix-collect-garbage.in +++ b/scripts/nix-collect-garbage.in @@ -9,16 +9,24 @@ my $storeDir = "@storedir@"; my %alive; my $gcOper = "--delete"; -my $keepSuccessors = 1; +my $minAge = 0; my @roots = (); # Parse the command line. -foreach my $arg (@ARGV) { +for (my $i = 0; $i < scalar @ARGV; $i++) { + my $arg = $ARGV[$i]; if ($arg eq "--delete" || $arg eq "--print-live" || $arg eq "--print-dead") { $gcOper = $arg; - } else { die "unknown argument `$arg'" }; + } + elsif ($arg eq "--min-age") { + $i++; + $minAge = undef; + $minAge = $ARGV[$i]; + die "invalid minimum age" unless defined $minAge && $minAge =~ /^\d*$/; + } + else { die "unknown argument `$arg'" }; } @@ -69,7 +77,7 @@ findRoots 1, $rootsDir; # Run the collector with the roots we found. -my $pid = open2(">&1", \*WRITE, "@bindir@/nix-store --gc $gcOper") +my $pid = open2(">&1", \*WRITE, "@bindir@/nix-store --gc $gcOper --min-age $minAge") or die "cannot run `nix-store --gc'"; foreach my $root (@roots) { diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index aed7c2294b04..9af957693f0c 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -2,6 +2,11 @@ #include "globals.hh" +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + + void followLivePaths(Path nePath, PathSet & live) { /* Just to be sure, canonicalise the path. It is important to do @@ -62,16 +67,26 @@ PathSet findLivePaths(const Paths & roots) } -PathSet findDeadPaths(const PathSet & live) +PathSet findDeadPaths(const PathSet & live, time_t minAge) { PathSet dead; startNest(nest, lvlDebug, "finding dead paths"); + time_t now = time(0); + Strings storeNames = readDirectory(nixStore); for (Strings::iterator i = storeNames.begin(); i != storeNames.end(); ++i) { Path p = canonPath(nixStore + "/" + *i); + + if (minAge > 0) { + struct stat st; + if (lstat(p.c_str(), &st) != 0) + throw SysError(format("obtaining information about `%1%'") % p); + if (st.st_atime + minAge >= now) continue; + } + if (live.find(p) == live.end()) { debug(format("dead path `%1%'") % p); dead.insert(p); diff --git a/src/libstore/gc.hh b/src/libstore/gc.hh index 997057ba9b7b..1ada419da439 100644 --- a/src/libstore/gc.hh +++ b/src/libstore/gc.hh @@ -17,8 +17,10 @@ PathSet findLivePaths(const Paths & roots); /* Given a set of "live" store paths, determine the set of "dead" store paths (which are simply all store paths that are not in the - live set). */ -PathSet findDeadPaths(const PathSet & live); + live set). The value `minAge' specifies the minimum age in seconds + for an unreachable file to be considered dead (0 meaning that any + unreachable file is dead). */ +PathSet findDeadPaths(const PathSet & live, time_t minAge); #endif /* !__GC_H */ diff --git a/src/nix-store/main.cc b/src/nix-store/main.cc index 7bc8565d293d..e9948c7cf8ac 100644 --- a/src/nix-store/main.cc +++ b/src/nix-store/main.cc @@ -212,17 +212,22 @@ static void opIsValid(Strings opFlags, Strings opArgs) static void opGC(Strings opFlags, Strings opArgs) { - if (opFlags.size() != 1) throw UsageError("missing flag"); - if (!opArgs.empty()) - throw UsageError("no arguments expected"); - /* Do what? */ - string flag = opFlags.front(); enum { soPrintLive, soPrintDead, soDelete } subOp; - if (flag == "--print-live") subOp = soPrintLive; - else if (flag == "--print-dead") subOp = soPrintDead; - else if (flag == "--delete") subOp = soDelete; - else throw UsageError(format("bad sub-operation `%1%' in GC") % flag); + time_t minAge = 0; + for (Strings::iterator i = opFlags.begin(); + i != opFlags.end(); ++i) + if (*i == "--print-live") subOp = soPrintLive; + else if (*i == "--print-dead") subOp = soPrintDead; + else if (*i == "--delete") subOp = soDelete; + else if (*i == "--min-age") { + if (opArgs.size() == 0) + throw UsageError("`--min-age' requires an argument"); + istringstream st(opArgs.front()); + st >> minAge; + if (!st) throw Error("number expected"); + } + else throw UsageError(format("bad sub-operation `%1%' in GC") % *i); Paths roots; while (1) { @@ -240,7 +245,7 @@ static void opGC(Strings opFlags, Strings opArgs) return; } - PathSet dead = findDeadPaths(live); + PathSet dead = findDeadPaths(live, minAge * 3600); if (subOp == soPrintDead) { for (PathSet::iterator i = dead.begin(); i != dead.end(); ++i) |