aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2012-07-23 15:48:30 -0400
committerEelco Dolstra <eelco.dolstra@logicblox.com>2012-07-23 17:14:16 -0400
commit680ab6f83def2b636200204542ca352631a46f85 (patch)
tree694160fd33f18648bf2c2c5ca4754a2dd20f6024 /src
parent619310571002fc74e428824bd603604d1055b61b (diff)
Garbage collect unused links in /nix/store/.links
Incremental optimisation requires creating links in /nix/store/.links to all files in the store. However, this means that if we delete a store path, no files are actually deleted because links in /nix/store/.links still exists. So we need to check /nix/store/.links for files with a link count of 1 and delete them.
Diffstat (limited to 'src')
-rw-r--r--src/libstore/gc.cc37
-rw-r--r--src/libstore/local-store.hh2
2 files changed, 39 insertions, 0 deletions
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index f6ed7dd22..874efe4d3 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -436,6 +436,8 @@ bool LocalStore::tryToDelete(GCState & state, const Path & path)
{
checkInterrupt();
+ if (path == linksDir) return true;
+
struct stat st;
if (lstat(path.c_str(), &st)) {
if (errno == ENOENT) return true;
@@ -569,6 +571,37 @@ bool LocalStore::tryToDelete(GCState & state, const Path & path)
}
+/* Unlink all files in /nix/store/.links that have a link count of 1,
+ which indicates that there are no other links and so they can be
+ safely deleted. FIXME: race condition with optimisePath(): we
+ might see a link count of 1 just before optimisePath() increases
+ the link count. */
+void LocalStore::removeUnusedLinks()
+{
+ AutoCloseDir dir = opendir(linksDir.c_str());
+ if (!dir) throw SysError(format("opening directory `%1%'") % linksDir);
+
+ struct dirent * dirent;
+ while (errno = 0, dirent = readdir(dir)) {
+ checkInterrupt();
+ string name = dirent->d_name;
+ if (name == "." || name == "..") continue;
+ Path path = linksDir + "/" + name;
+
+ struct stat st;
+ if (lstat(path.c_str(), &st) == -1)
+ throw SysError(format("statting `%1%'") % path);
+
+ if (st.st_nlink != 1) continue;
+
+ printMsg(lvlTalkative, format("deleting unused link `%1%'") % path);
+
+ if (unlink(path.c_str()) == -1)
+ throw SysError(format("deleting `%1%'") % path);
+ }
+}
+
+
void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
{
GCState state(results);
@@ -682,6 +715,10 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
released. */
foreach (PathSet::iterator, i, state.invalidated)
deleteGarbage(state, *i);
+
+ /* Clean up the links directory. */
+ printMsg(lvlError, format("deleting unused links..."));
+ removeUnusedLinks();
}
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 7d30a2d40..50910f353 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -264,6 +264,8 @@ private:
int openGCLock(LockType lockType);
+ void removeUnusedLinks();
+
void startSubstituter(const Path & substituter,
RunningSubstituter & runningSubstituter);