aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libstore/gc.cc46
-rw-r--r--src/libutil/util.cc10
-rw-r--r--src/libutil/util.hh1
3 files changed, 45 insertions, 12 deletions
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index a99bb1a81..20f194e6e 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -617,27 +617,51 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
} else {
- printMsg(lvlError, format("reading the Nix store..."));
- Paths entries = readDirectory(nixStore);
-
- /* Randomise the order in which we delete entries to make the
- collector less biased towards deleting paths that come
- alphabetically first (e.g. /nix/store/000...). This
- matters when using --max-freed etc. */
- vector<Path> entries_(entries.begin(), entries.end());
- random_shuffle(entries_.begin(), entries_.end());
-
if (shouldDelete(state.options.action))
printMsg(lvlError, format("deleting garbage..."));
else
printMsg(lvlError, format("determining live/dead paths..."));
try {
+
+ AutoCloseDir dir = opendir(nixStore.c_str());
+ if (!dir) throw SysError(format("opening directory `%1%'") % nixStore);
+
+ /* Read the store and immediately delete all paths that
+ aren't valid. When using --max-freed etc., deleting
+ invalid paths is preferred over deleting unreachable
+ paths, since unreachable paths could become reachable
+ again. We don't use readDirectory() here so that GCing
+ can start faster. */
+ Paths entries;
+ struct dirent * dirent;
+ while (errno = 0, dirent = readdir(dir)) {
+ checkInterrupt();
+ string name = dirent->d_name;
+ if (name == "." || name == "..") continue;
+ Path path = nixStore + "/" + name;
+ if (isValidPath(path))
+ entries.push_back(path);
+ else
+ tryToDelete(state, path);
+ }
+
+ dir.close();
+
+ /* Now delete the unreachable valid paths. Randomise the
+ order in which we delete entries to make the collector
+ less biased towards deleting paths that come
+ alphabetically first (e.g. /nix/store/000...). This
+ matters when using --max-freed etc. */
+ vector<Path> entries_(entries.begin(), entries.end());
+ random_shuffle(entries_.begin(), entries_.end());
+
foreach (vector<Path>::iterator, i, entries_)
tryToDelete(state, nixStore + "/" + *i);
+
} catch (GCLimitReached & e) {
}
- }
+ }
}
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 9adaac40d..0352754f5 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -701,7 +701,7 @@ AutoCloseDir::AutoCloseDir(DIR * dir)
AutoCloseDir::~AutoCloseDir()
{
- if (dir) closedir(dir);
+ close();
}
@@ -717,6 +717,14 @@ AutoCloseDir::operator DIR *()
}
+void AutoCloseDir::close()
+{
+ if (dir) {
+ closedir(dir);
+ dir = 0;
+ }
+}
+
//////////////////////////////////////////////////////////////////////
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index f86290f31..a1cf68e69 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -223,6 +223,7 @@ public:
~AutoCloseDir();
void operator =(DIR * dir);
operator DIR *();
+ void close();
};