aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2005-02-01 15:05:32 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2005-02-01 15:05:32 +0000
commit65b6c8ab4c7832abdad46a29ce2ef18d289b2471 (patch)
tree3038d7ed1f60efdf2e2dad43cfec93023d7c699f /src
parent630ae0c9d7f65a2d6bef85a5194b4d704e54eded (diff)
* Move root finding from `nix-collect-garbage' to `nix-store --gc'.
This was necessary becase root finding must be done after acquisition of the global GC lock. This makes `nix-collect-garbage' obsolete; it is now just a wrapper around `nix-store --gc'. * Automatically remove stale GC roots (i.e., indirect GC roots that point to non-existent paths).
Diffstat (limited to 'src')
-rw-r--r--src/libstore/gc.cc59
-rw-r--r--src/libstore/gc.hh24
-rw-r--r--src/nix-store/main.cc20
3 files changed, 74 insertions, 29 deletions
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 8385e31b1..323acf265 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -26,7 +26,9 @@ static int openGCLock(LockType lockType)
{
Path fnGCLock = (format("%1%/%2%")
% nixStateDir % gcLockName).str();
-
+
+ debug(format("acquiring global GC lock `%1%'") % fnGCLock);
+
AutoCloseFD fdGCLock = open(fnGCLock.c_str(), O_RDWR | O_CREAT, 0600);
if (fdGCLock == -1)
throw SysError(format("opening global GC lock `%1%'") % fnGCLock);
@@ -234,6 +236,46 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds)
}
+static void findRoots(const Path & path, bool recurseSymlinks,
+ PathSet & roots)
+{
+ struct stat st;
+ if (lstat(path.c_str(), &st) == -1)
+ throw SysError(format("statting `%1%'") % path);
+
+ printMsg(lvlVomit, format("looking at `%1%'") % path);
+
+ if (S_ISDIR(st.st_mode)) {
+ Strings names = readDirectory(path);
+ for (Strings::iterator i = names.begin(); i != names.end(); ++i)
+ findRoots(path + "/" + *i, recurseSymlinks, roots);
+ }
+
+ else if (S_ISLNK(st.st_mode)) {
+ string target = readLink(path);
+ Path target2 = absPath(target, dirOf(path));
+
+ if (isStorePath(target2)) {
+ debug(format("found root `%1%' in `%2%'")
+ % target2 % path);
+ roots.insert(target2);
+ }
+
+ else if (recurseSymlinks) {
+ if (pathExists(target2))
+ findRoots(target2, false, roots);
+ else {
+ printMsg(lvlInfo, format("removing stale link from `%1%' to `%2%'") % path % target2);
+ /* Note that we only delete when recursing, i.e., when
+ we are still in the `gcroots' tree. We never
+ delete stuff outside that tree. */
+ unlink(path.c_str());
+ }
+ }
+ }
+}
+
+
static void dfsVisit(const PathSet & paths, const Path & path,
PathSet & visited, Paths & sorted)
{
@@ -265,8 +307,7 @@ static Paths topoSort(const PathSet & paths)
}
-void collectGarbage(const PathSet & roots, GCAction action,
- PathSet & result)
+void collectGarbage(GCAction action, PathSet & result)
{
result.clear();
@@ -275,8 +316,16 @@ void collectGarbage(const PathSet & roots, GCAction action,
b) Processes from creating new temporary root files. */
AutoCloseFD fdGCLock = openGCLock(ltWrite);
- /* !!! Find the roots here, after we've grabbed the GC lock, since
- the set of permanent roots cannot increase now. */
+ /* Find the roots. Since we've grabbed the GC lock, the set of
+ permanent roots cannot increase now. */
+ Path rootsDir = canonPath((format("%1%/%2%") % nixStateDir % gcRootsDir).str());
+ PathSet roots;
+ findRoots(rootsDir, true, roots);
+
+ if (action == gcReturnRoots) {
+ result = roots;
+ return;
+ }
/* Determine the live paths which is just the closure of the
roots under the `references' relation. */
diff --git a/src/libstore/gc.hh b/src/libstore/gc.hh
index e3da4505d..b6a367c4b 100644
--- a/src/libstore/gc.hh
+++ b/src/libstore/gc.hh
@@ -5,15 +5,21 @@
/* Garbage collector operation. */
-typedef enum { gcReturnLive, gcReturnDead, gcDeleteDead } GCAction;
-
-/* If `action' is set to `soReturnLive', return the set of paths
- reachable from (i.e. in the closure of) the specified roots. If
- `action' is `soReturnDead', return the set of paths not reachable
- from the roots. If `action' is `soDeleteDead', actually delete the
- latter set. */
-void collectGarbage(const PathSet & roots, GCAction action,
- PathSet & result);
+typedef enum {
+ gcReturnRoots,
+ gcReturnLive,
+ gcReturnDead,
+ gcDeleteDead,
+} GCAction;
+
+/* If `action' is set to `gcReturnRoots', find and return the set of
+ roots for the garbage collector. These are the store paths
+ symlinked to in the `gcroots' directory. If `action' is
+ `gcReturnLive', return the set of paths reachable from (i.e. in the
+ closure of) the roots. If `action' is `gcReturnDead', return the
+ set of paths not reachable from the roots. If `action' is
+ `gcDeleteDead', actually delete the latter set. */
+void collectGarbage(GCAction action, PathSet & result);
/* Register a temporary GC root. This root will automatically
disappear when this process exits. WARNING: this function should
diff --git a/src/nix-store/main.cc b/src/nix-store/main.cc
index 3edcff7ee..d473475b8 100644
--- a/src/nix-store/main.cc
+++ b/src/nix-store/main.cc
@@ -38,9 +38,7 @@ static Path followSymlinks(Path & path)
while (!isStorePath(path)) {
if (!isLink(path)) return path;
string target = readLink(path);
- path = canonPath(string(target, 0, 1) == "/"
- ? target
- : path + "/" + target);
+ path = absPath(target, dirOf(path));
}
return path;
}
@@ -308,27 +306,19 @@ static void opIsValid(Strings opFlags, Strings opArgs)
static void opGC(Strings opFlags, Strings opArgs)
{
- GCAction action;
+ GCAction action = gcDeleteDead;
/* Do what? */
for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i)
- if (*i == "--print-live") action = gcReturnLive;
+ if (*i == "--print-roots") action = gcReturnRoots;
+ else if (*i == "--print-live") action = gcReturnLive;
else if (*i == "--print-dead") action = gcReturnDead;
else if (*i == "--delete") action = gcDeleteDead;
else throw UsageError(format("bad sub-operation `%1%' in GC") % *i);
- /* Read the roots. */
- PathSet roots;
- while (1) {
- Path root;
- getline(cin, root);
- if (cin.eof()) break;
- roots.insert(root);
- }
-
PathSet result;
- collectGarbage(roots, action, result);
+ collectGarbage(action, result);
if (action != gcDeleteDead) {
for (PathSet::iterator i = result.begin(); i != result.end(); ++i)