aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libstore/build.cc10
-rw-r--r--src/libstore/gc.cc54
-rw-r--r--src/libstore/local-store.cc5
-rw-r--r--src/libstore/local-store.hh18
-rw-r--r--src/libstore/optimise-store.cc1
-rw-r--r--src/libstore/remote-store.cc22
-rw-r--r--src/libstore/remote-store.hh3
-rw-r--r--src/libstore/store-api.hh113
-rw-r--r--src/libstore/worker-protocol.hh34
-rw-r--r--src/libutil/serialise.cc31
-rw-r--r--src/libutil/serialise.hh2
-rw-r--r--src/libutil/util.cc35
-rw-r--r--src/libutil/util.hh8
-rw-r--r--src/nix-store/nix-store.cc57
-rw-r--r--src/nix-worker/nix-worker.cc25
15 files changed, 252 insertions, 166 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 0664a118a..1d624723f 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -578,17 +578,17 @@ void getOwnership(const Path & path)
void deletePathWrapped(const Path & path,
- unsigned long long & bytesFreed)
+ unsigned long long & bytesFreed, unsigned long long & blocksFreed)
{
try {
/* First try to delete it ourselves. */
- deletePath(path, bytesFreed);
+ deletePath(path, bytesFreed, blocksFreed);
} catch (SysError & e) {
/* If this failed due to a permission error, then try it with
the setuid helper. */
if (haveBuildUsers() && !amPrivileged()) {
getOwnership(path);
- deletePath(path, bytesFreed);
+ deletePath(path, bytesFreed, blocksFreed);
} else
throw;
}
@@ -597,8 +597,8 @@ void deletePathWrapped(const Path & path,
void deletePathWrapped(const Path & path)
{
- unsigned long long dummy;
- deletePathWrapped(path, dummy);
+ unsigned long long dummy1, dummy2;
+ deletePathWrapped(path, dummy1, dummy2);
}
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index c46cc817b..0caf1ce4e 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -439,9 +439,9 @@ Paths topoSortPaths(const PathSet & paths)
}
-void LocalStore::tryToDelete(GCAction action, const PathSet & livePaths,
- const PathSet & tempRootsClosed, PathSet & done, PathSet & deleted,
- const Path & path, unsigned long long & bytesFreed)
+void LocalStore::tryToDelete(const GCOptions & options, GCResults & results,
+ const PathSet & livePaths, const PathSet & tempRootsClosed, PathSet & done,
+ const Path & path)
{
if (done.find(path) != done.end()) return;
done.insert(path);
@@ -449,7 +449,7 @@ void LocalStore::tryToDelete(GCAction action, const PathSet & livePaths,
debug(format("considering deletion of `%1%'") % path);
if (livePaths.find(path) != livePaths.end()) {
- if (action == gcDeleteSpecific)
+ if (options.action == GCOptions::gcDeleteSpecific)
throw Error(format("cannot delete path `%1%' since it is still alive") % path);
debug(format("live path `%1%'") % path);
return;
@@ -470,15 +470,18 @@ void LocalStore::tryToDelete(GCAction action, const PathSet & livePaths,
queryReferrers(path, referrers);
foreach (PathSet::iterator, i, referrers)
if (*i != path)
- tryToDelete(action, livePaths, tempRootsClosed, done, deleted, *i, bytesFreed);
+ tryToDelete(options, results, livePaths, tempRootsClosed, done, *i);
debug(format("dead path `%1%'") % path);
- deleted.insert(path);
+ results.paths.insert(path);
/* If just returning the set of dead paths, we also return the
space that would be freed if we deleted them. */
- if (action == gcReturnDead) {
- bytesFreed += computePathSize(path);
+ if (options.action == GCOptions::gcReturnDead) {
+ unsigned long long bytesFreed, blocksFreed;
+ computePathSize(path, bytesFreed, blocksFreed);
+ results.bytesFreed += bytesFreed;
+ results.blocksFreed += blocksFreed;
return;
}
@@ -504,9 +507,10 @@ void LocalStore::tryToDelete(GCAction action, const PathSet & livePaths,
printMsg(lvlInfo, format("deleting `%1%'") % path);
/* Okay, it's safe to delete. */
- unsigned long long freed;
- deleteFromStore(path, freed);
- bytesFreed += freed;
+ unsigned long long bytesFreed, blocksFreed;
+ deleteFromStore(path, bytesFreed, blocksFreed);
+ results.bytesFreed += bytesFreed;
+ results.blocksFreed += blocksFreed;
#ifndef __CYGWIN__
if (fdLock != -1)
@@ -516,12 +520,8 @@ void LocalStore::tryToDelete(GCAction action, const PathSet & livePaths,
}
-void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
- bool ignoreLiveness, PathSet & result, unsigned long long & bytesFreed)
+void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
{
- result.clear();
- bytesFreed = 0;
-
bool gcKeepOutputs =
queryBoolSetting("gc-keep-outputs", false);
bool gcKeepDerivations =
@@ -537,7 +537,7 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
/* Find the roots. Since we've grabbed the GC lock, the set of
permanent roots cannot increase now. */
printMsg(lvlError, format("finding garbage collector roots..."));
- Roots rootMap = ignoreLiveness ? Roots() : nix::findRoots(true);
+ Roots rootMap = options.ignoreLiveness ? Roots() : nix::findRoots(true);
PathSet roots;
for (Roots::iterator i = rootMap.begin(); i != rootMap.end(); ++i)
@@ -547,11 +547,11 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
NIX_ROOT_FINDER environment variable. This is typically used
to add running programs to the set of roots (to prevent them
from being garbage collected). */
- if (!ignoreLiveness)
+ if (!options.ignoreLiveness)
addAdditionalRoots(roots);
- if (action == gcReturnRoots) {
- result = roots;
+ if (options.action == GCOptions::gcReturnRoots) {
+ results.paths = roots;
return;
}
@@ -595,8 +595,8 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
}
}
- if (action == gcReturnLive) {
- result = livePaths;
+ if (options.action == GCOptions::gcReturnLive) {
+ results.paths = livePaths;
return;
}
@@ -633,27 +633,25 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
paths. */
printMsg(lvlError, format("reading the Nix store..."));
PathSet storePaths;
- if (action != gcDeleteSpecific) {
+ if (options.action != GCOptions::gcDeleteSpecific) {
Paths entries = readDirectory(nixStore);
for (Paths::iterator i = entries.begin(); i != entries.end(); ++i)
storePaths.insert(canonPath(nixStore + "/" + *i));
} else {
- for (PathSet::iterator i = pathsToDelete.begin();
- i != pathsToDelete.end(); ++i)
- {
+ foreach (PathSet::iterator, i, options.pathsToDelete) {
assertStorePath(*i);
storePaths.insert(*i);
}
}
/* Try to delete store paths in the topologically sorted order. */
- printMsg(lvlError, action == gcReturnDead
+ printMsg(lvlError, options.action == GCOptions::gcReturnDead
? format("looking for garbage...")
: format("deleting garbage..."));
PathSet done;
foreach (PathSet::iterator, i, storePaths)
- tryToDelete(action, livePaths, tempRootsClosed, done, result, *i, bytesFreed);
+ tryToDelete(options, results, livePaths, tempRootsClosed, done, *i);
}
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 2e53d0dc6..105f71122 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -851,7 +851,8 @@ Path LocalStore::importPath(bool requireSignature, Source & source)
}
-void LocalStore::deleteFromStore(const Path & path, unsigned long long & bytesFreed)
+void LocalStore::deleteFromStore(const Path & path, unsigned long long & bytesFreed,
+ unsigned long long & blocksFreed)
{
bytesFreed = 0;
@@ -871,7 +872,7 @@ void LocalStore::deleteFromStore(const Path & path, unsigned long long & bytesFr
invalidatePath(path);
}
- deletePathWrapped(path, bytesFreed);
+ deletePathWrapped(path, bytesFreed, blocksFreed);
}
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 444a5f340..1957b9f57 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -25,10 +25,11 @@ struct OptimiseStats
unsigned long sameContents;
unsigned long filesLinked;
unsigned long long bytesFreed;
+ unsigned long long blocksFreed;
OptimiseStats()
{
totalFiles = sameContents = filesLinked = 0;
- bytesFreed = 0;
+ bytesFreed = blocksFreed = 0;
}
};
@@ -89,11 +90,11 @@ public:
Roots findRoots();
- void collectGarbage(GCAction action, const PathSet & pathsToDelete,
- bool ignoreLiveness, PathSet & result, unsigned long long & bytesFreed);
+ void collectGarbage(const GCOptions & options, GCResults & results);
/* Delete a path from the Nix store. */
- void deleteFromStore(const Path & path, unsigned long long & bytesFreed);
+ void deleteFromStore(const Path & path, unsigned long long & bytesFreed,
+ unsigned long long & blocksFreed);
/* Optimise the disk space usage of the Nix store by hard-linking
files with the same contents. */
@@ -143,10 +144,9 @@ private:
void upgradeStore12();
- void tryToDelete(GCAction action, const PathSet & livePaths,
- const PathSet & tempRootsClosed, PathSet & done, PathSet & deleted,
- const Path & path, unsigned long long & bytesFreed);
-
+ void tryToDelete(const GCOptions & options, GCResults & results,
+ const PathSet & livePaths, const PathSet & tempRootsClosed, PathSet & done,
+ const Path & path);
};
@@ -179,7 +179,7 @@ void getOwnership(const Path & path);
/* Like deletePath(), but changes the ownership of `path' using the
setuid wrapper if necessary (and possible). */
void deletePathWrapped(const Path & path,
- unsigned long long & bytesFreed);
+ unsigned long long & bytesFreed, unsigned long long & blocksFreed);
void deletePathWrapped(const Path & path);
diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc
index c260f253e..bd76a1aec 100644
--- a/src/libstore/optimise-store.cc
+++ b/src/libstore/optimise-store.cc
@@ -101,6 +101,7 @@ static void hashAndLink(bool dryRun, HashToPath & hashToPath,
stats.filesLinked++;
stats.bytesFreed += st.st_size;
+ stats.blocksFreed += st.st_blocks;
}
if (S_ISDIR(st.st_mode)) {
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index 14412b8c8..274196a2b 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -372,24 +372,20 @@ Roots RemoteStore::findRoots()
}
-void RemoteStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
- bool ignoreLiveness, PathSet & result, unsigned long long & bytesFreed)
+void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
{
- result.clear();
- bytesFreed = 0;
writeInt(wopCollectGarbage, to);
- writeInt(action, to);
- writeStringSet(pathsToDelete, to);
- writeInt(ignoreLiveness, to);
+ writeInt(options.action, to);
+ writeStringSet(options.pathsToDelete, to);
+ writeInt(options.ignoreLiveness, to);
+ writeLongLong(options.maxFreed, to);
+ writeInt(options.maxLinks, to);
processStderr();
- result = readStringSet(from);
-
- /* Ugh - NAR integers are 64 bits, but read/writeInt() aren't. */
- unsigned int lo = readInt(from);
- unsigned int hi = readInt(from);
- bytesFreed = (((unsigned long long) hi) << 32) | lo;
+ results.paths = readStringSet(from);
+ results.bytesFreed = readLongLong(from);
+ results.blocksFreed = readLongLong(from);
}
diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh
index 1501591e2..c40feeaa4 100644
--- a/src/libstore/remote-store.hh
+++ b/src/libstore/remote-store.hh
@@ -65,8 +65,7 @@ public:
Roots findRoots();
- void collectGarbage(GCAction action, const PathSet & pathsToDelete,
- bool ignoreLiveness, PathSet & result, unsigned long long & bytesFreed);
+ void collectGarbage(const GCOptions & options, GCResults & results);
private:
AutoCloseFD fdSocket;
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index a50dcf645..760e71adc 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -16,14 +16,82 @@ namespace nix {
typedef std::map<Path, Path> Roots;
-/* Garbage collector operation. */
-typedef enum {
- gcReturnRoots,
- gcReturnLive,
- gcReturnDead,
- gcDeleteDead,
- gcDeleteSpecific,
-} GCAction;
+
+
+struct GCOptions
+{
+ /* Garbage collector operation:
+
+ - `gcReturnRoots': find and return the set of roots for the
+ garbage collector. These are the store paths symlinked to in
+ the `gcroots' directory.
+
+ - `gcReturnLive': return the set of paths reachable from
+ (i.e. in the closure of) the roots.
+
+ - `gcReturnDead': return the set of paths not reachable from
+ the roots.
+
+ - `gcDeleteDead': actually delete the latter set.
+
+ - `gcDeleteSpecific': delete the paths listed in
+ `pathsToDelete', insofar as they are not reachable.
+ */
+ typedef enum {
+ gcReturnRoots,
+ gcReturnLive,
+ gcReturnDead,
+ gcDeleteDead,
+ gcDeleteSpecific,
+ } GCAction;
+
+ GCAction action;
+
+ /* If `ignoreLiveness' is set, then reachability from the roots is
+ ignored (dangerous!). However, the paths must still be
+ unreferenced *within* the store (i.e., there can be no other
+ store paths that depend on them). */
+ bool ignoreLiveness;
+
+ /* For `gcDeleteSpecific', the paths to delete. */
+ PathSet pathsToDelete;
+
+ /* Stop after at least `maxFreed' bytes have been freed. */
+ unsigned long long maxFreed;
+
+ /* Stop after the number of hard links to the Nix store directory
+ has dropped to at least `maxLinks'. */
+ unsigned int maxLinks;
+
+ GCOptions()
+ {
+ action = gcDeleteDead;
+ ignoreLiveness = false;
+ maxFreed = ULLONG_MAX;
+ maxLinks = UINT_MAX;
+ }
+};
+
+
+struct GCResults
+{
+ /* Depending on the action, the GC roots, or the paths that would
+ be or have been deleted. */
+ PathSet paths;
+
+ /* For `gcReturnDead', `gcDeleteDead' and `gcDeleteSpecific', the
+ number of bytes that would be or was freed. */
+ unsigned long long bytesFreed;
+
+ /* The number of file system blocks that would be or was freed. */
+ unsigned long long blocksFreed;
+
+ GCResults()
+ {
+ bytesFreed = 0;
+ blocksFreed = 0;
+ }
+};
class StoreAPI
@@ -137,33 +205,8 @@ public:
outside of the Nix store that point to `storePath'. */
virtual Roots findRoots() = 0;
- /* Depending on `action', this function does the following:
-
- - `gcReturnRoots': find and return the set of roots for the
- garbage collector. These are the store paths symlinked to in
- the `gcroots' directory.
-
- - `gcReturnLive': return the set of paths reachable from
- (i.e. in the closure of) the roots.
-
- - `gcReturnDead': return the set of paths not reachable from
- the roots.
-
- - `gcDeleteDead': actually delete the latter set.
-
- - `gcDeleteSpecific': delete the paths listed in
- `pathsToDelete', insofar as they are not reachable.
-
- If `ignoreLiveness' is set, then reachability from the roots is
- ignored (dangerous!). However, the paths must still be
- unreferenced *within* the store (i.e., there can be no other
- store paths that depend on them).
-
- For `gcReturnDead', `gcDeleteDead' and `gcDeleteSpecific', the
- number of bytes that would be or was freed is returned in
- `bytesFreed'. */
- virtual void collectGarbage(GCAction action, const PathSet & pathsToDelete,
- bool ignoreLiveness, PathSet & result, unsigned long long & bytesFreed) = 0;
+ /* Perform a garbage collection. */
+ virtual void collectGarbage(const GCOptions & options, GCResults & results) = 0;
};
diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh
index 44db4ad9b..d887ee59b 100644
--- a/src/libstore/worker-protocol.hh
+++ b/src/libstore/worker-protocol.hh
@@ -15,24 +15,24 @@ namespace nix {
typedef enum {
wopQuit = 0,
- wopIsValidPath,
+ wopIsValidPath = 1,
wopHasSubstitutes = 3,
- wopQueryPathHash,
- wopQueryReferences,
- wopQueryReferrers,
- wopAddToStore,
- wopAddTextToStore,
- wopBuildDerivations,
- wopEnsurePath,
- wopAddTempRoot,
- wopAddIndirectRoot,
- wopSyncWithGC,
- wopFindRoots,
- wopCollectGarbage,
- wopExportPath,
- wopImportPath,
- wopQueryDeriver,
- wopSetOptions,
+ wopQueryPathHash = 4,
+ wopQueryReferences = 5,
+ wopQueryReferrers = 6,
+ wopAddToStore = 7,
+ wopAddTextToStore = 8,
+ wopBuildDerivations = 9,
+ wopEnsurePath = 10,
+ wopAddTempRoot = 11,
+ wopAddIndirectRoot = 12,
+ wopSyncWithGC = 13,
+ wopFindRoots = 14,
+ wopExportPath = 16,
+ wopImportPath = 17,
+ wopQueryDeriver = 18,
+ wopSetOptions = 19,
+ wopCollectGarbage = 20,
} WorkerOp;
diff --git a/src/libutil/serialise.cc b/src/libutil/serialise.cc
index c3fd4dd10..c13e8c7e3 100644
--- a/src/libutil/serialise.cc
+++ b/src/libutil/serialise.cc
@@ -41,6 +41,21 @@ void writeInt(unsigned int n, Sink & sink)
}
+void writeLongLong(unsigned long long n, Sink & sink)
+{
+ unsigned char buf[8];
+ buf[0] = n & 0xff;
+ buf[1] = (n >> 8) & 0xff;
+ buf[2] = (n >> 16) & 0xff;
+ buf[3] = (n >> 24) & 0xff;
+ buf[4] = (n >> 32) & 0xff;
+ buf[5] = (n >> 40) & 0xff;
+ buf[6] = (n >> 48) & 0xff;
+ buf[7] = (n >> 56) & 0xff;
+ sink(buf, sizeof(buf));
+}
+
+
void writeString(const string & s, Sink & sink)
{
unsigned int len = s.length();
@@ -84,6 +99,22 @@ unsigned int readInt(Source & source)
}
+unsigned long long readLongLong(Source & source)
+{
+ unsigned char buf[8];
+ source(buf, sizeof(buf));
+ return
+ ((unsigned long long) buf[0]) |
+ ((unsigned long long) buf[1] << 8) |
+ ((unsigned long long) buf[2] << 16) |
+ ((unsigned long long) buf[3] << 24) |
+ ((unsigned long long) buf[4] << 32) |
+ ((unsigned long long) buf[5] << 40) |
+ ((unsigned long long) buf[6] << 48) |
+ ((unsigned long long) buf[7] << 56);
+}
+
+
string readString(Source & source)
{
unsigned int len = readInt(source);
diff --git a/src/libutil/serialise.hh b/src/libutil/serialise.hh
index c18e82463..75d17bc60 100644
--- a/src/libutil/serialise.hh
+++ b/src/libutil/serialise.hh
@@ -95,11 +95,13 @@ struct StringSource : Source
void writePadding(unsigned int len, Sink & sink);
void writeInt(unsigned int n, Sink & sink);
+void writeLongLong(unsigned long long n, Sink & sink);
void writeString(const string & s, Sink & sink);
void writeStringSet(const StringSet & ss, Sink & sink);
void readPadding(unsigned int len, Source & source);
unsigned int readInt(Source & source);
+unsigned long long readLongLong(Source & source);
string readString(Source & source);
StringSet readStringSet(Source & source);
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index e18f9841f..1873ccfe5 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -229,30 +229,38 @@ void writeFile(const Path & path, const string & s)
}
-unsigned long long computePathSize(const Path & path)
+static void _computePathSize(const Path & path,
+ unsigned long long & bytes, unsigned long long & blocks)
{
- unsigned long long size = 0;
-
checkInterrupt();
struct stat st;
if (lstat(path.c_str(), &st))
throw SysError(format("getting attributes of path `%1%'") % path);
- size += st.st_size;
+ bytes += st.st_size;
+ blocks += st.st_blocks;
if (S_ISDIR(st.st_mode)) {
Strings names = readDirectory(path);
for (Strings::iterator i = names.begin(); i != names.end(); ++i)
- size += computePathSize(path + "/" + *i);
+ _computePathSize(path + "/" + *i, bytes, blocks);
}
+}
- return size;
+
+void computePathSize(const Path & path,
+ unsigned long long & bytes, unsigned long long & blocks)
+{
+ bytes = 0;
+ blocks = 0;
+ _computePathSize(path, bytes, blocks);
}
-static void _deletePath(const Path & path, unsigned long long & bytesFreed)
+static void _deletePath(const Path & path, unsigned long long & bytesFreed,
+ unsigned long long & blocksFreed)
{
checkInterrupt();
@@ -263,6 +271,7 @@ static void _deletePath(const Path & path, unsigned long long & bytesFreed)
throw SysError(format("getting attributes of path `%1%'") % path);
bytesFreed += st.st_size;
+ blocksFreed += st.st_blocks;
if (S_ISDIR(st.st_mode)) {
Strings names = readDirectory(path);
@@ -274,7 +283,7 @@ static void _deletePath(const Path & path, unsigned long long & bytesFreed)
}
for (Strings::iterator i = names.begin(); i != names.end(); ++i)
- _deletePath(path + "/" + *i, bytesFreed);
+ _deletePath(path + "/" + *i, bytesFreed, blocksFreed);
}
if (remove(path.c_str()) == -1)
@@ -284,17 +293,19 @@ static void _deletePath(const Path & path, unsigned long long & bytesFreed)
void deletePath(const Path & path)
{
- unsigned long long dummy;
- deletePath(path, dummy);
+ unsigned long long dummy1, dummy2;
+ deletePath(path, dummy1, dummy2);
}
-void deletePath(const Path & path, unsigned long long & bytesFreed)
+void deletePath(const Path & path, unsigned long long & bytesFreed,
+ unsigned long long & blocksFreed)
{
startNest(nest, lvlDebug,
format("recursively deleting path `%1%'") % path);
bytesFreed = 0;
- _deletePath(path, bytesFreed);
+ blocksFreed = 0;
+ _deletePath(path, bytesFreed, blocksFreed);
}
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index d52ab3e4d..d1e30fa6b 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -61,14 +61,16 @@ string readFile(const Path & path);
void writeFile(const Path & path, const string & s);
/* Compute the sum of the sizes of all files in `path'. */
-unsigned long long computePathSize(const Path & path);
+void computePathSize(const Path & path,
+ unsigned long long & bytes, unsigned long long & blocks);
/* Delete a path; i.e., in the case of a directory, it is deleted
recursively. Don't use this at home, kids. The second variant
- returns the number of bytes freed. */
+ returns the number of bytes and blocks freed. */
void deletePath(const Path & path);
-void deletePath(const Path & path, unsigned long long & bytesFreed);
+void deletePath(const Path & path, unsigned long long & bytesFreed,
+ unsigned long long & blocksFreed);
/* Make a path read-only recursively. */
void makePathReadOnly(const Path & path);
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index df027fcc7..9618823ea 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -489,19 +489,19 @@ static void opCheckValidity(Strings opFlags, Strings opArgs)
}
-static string showBytes(unsigned long long bytes)
+static string showBytes(unsigned long long bytes, unsigned long long blocks)
{
- return (format("%d bytes (%.2f MiB)")
- % bytes % (bytes / (1024.0 * 1024.0))).str();
+ return (format("%d bytes (%.2f MiB, %d blocks)")
+ % bytes % (bytes / (1024.0 * 1024.0)) % blocks).str();
}
struct PrintFreed
{
bool show, dryRun;
- unsigned long long bytesFreed;
- PrintFreed(bool show, bool dryRun)
- : show(show), dryRun(dryRun), bytesFreed(0) { }
+ const GCResults & results;
+ PrintFreed(bool show, bool dryRun, const GCResults & results)
+ : show(show), dryRun(dryRun), results(results) { }
~PrintFreed()
{
if (show)
@@ -509,33 +509,35 @@ struct PrintFreed
(dryRun
? "%1% would be freed\n"
: "%1% freed\n"))
- % showBytes(bytesFreed);
+ % showBytes(results.bytesFreed, results.blocksFreed);
}
};
static void opGC(Strings opFlags, Strings opArgs)
{
- GCAction action = gcDeleteDead;
+ GCOptions options;
+ options.action = GCOptions::gcDeleteDead;
+
+ GCResults results;
/* Do what? */
for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i)
- 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;
+ if (*i == "--print-roots") options.action = GCOptions::gcReturnRoots;
+ else if (*i == "--print-live") options.action = GCOptions::gcReturnLive;
+ else if (*i == "--print-dead") options.action = GCOptions::gcReturnDead;
+ else if (*i == "--delete") options.action = GCOptions::gcDeleteDead;
else throw UsageError(format("bad sub-operation `%1%' in GC") % *i);
- PathSet result;
- PrintFreed freed(action == gcDeleteDead || action == gcReturnDead,
- action == gcReturnDead);
- store->collectGarbage(action, PathSet(), false, result, freed.bytesFreed);
+ PrintFreed freed(
+ options.action == GCOptions::gcDeleteDead || options.action == GCOptions::gcReturnDead,
+ options.action == GCOptions::gcReturnDead, results);
+ store->collectGarbage(options, results);
- if (action != gcDeleteDead) {
- for (PathSet::iterator i = result.begin(); i != result.end(); ++i)
+ if (options.action != GCOptions::gcDeleteDead)
+ foreach (PathSet::iterator, i, results.paths)
cout << *i << std::endl;
- }
}
@@ -544,22 +546,21 @@ static void opGC(Strings opFlags, Strings opArgs)
roots). */
static void opDelete(Strings opFlags, Strings opArgs)
{
- bool ignoreLiveness = false;
+ GCOptions options;
+ options.action = GCOptions::gcDeleteSpecific;
for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i)
- if (*i == "--ignore-liveness") ignoreLiveness = true;
+ if (*i == "--ignore-liveness") options.ignoreLiveness = true;
else throw UsageError(format("unknown flag `%1%'") % *i);
- PathSet pathsToDelete;
for (Strings::iterator i = opArgs.begin();
i != opArgs.end(); ++i)
- pathsToDelete.insert(followLinksToStorePath(*i));
+ options.pathsToDelete.insert(followLinksToStorePath(*i));
- PathSet dummy;
- PrintFreed freed(true, false);
- store->collectGarbage(gcDeleteSpecific, pathsToDelete, ignoreLiveness,
- dummy, freed.bytesFreed);
+ GCResults results;
+ PrintFreed freed(true, false, results);
+ store->collectGarbage(options, results);
}
@@ -653,7 +654,7 @@ static void showOptimiseStats(OptimiseStats & stats)
{
printMsg(lvlError,
format("%1% freed by hard-linking %2% files; there are %3% files with equal contents out of %4% files in total")
- % showBytes(stats.bytesFreed)
+ % showBytes(stats.bytesFreed, stats.blocksFreed)
% stats.filesLinked
% stats.sameContents
% stats.totalFiles);
diff --git a/src/nix-worker/nix-worker.cc b/src/nix-worker/nix-worker.cc
index 0d0964f3a..d8d86434e 100644
--- a/src/nix-worker/nix-worker.cc
+++ b/src/nix-worker/nix-worker.cc
@@ -395,23 +395,24 @@ static void performOp(unsigned int clientVersion,
}
case wopCollectGarbage: {
- GCAction action = (GCAction) readInt(from);
- PathSet pathsToDelete = readStorePaths(from);
- bool ignoreLiveness = readInt(from);
-
- PathSet result;
- unsigned long long bytesFreed;
+ GCOptions options;
+ options.action = (GCOptions::GCAction) readInt(from);
+ options.pathsToDelete = readStorePaths(from);
+ options.ignoreLiveness = readInt(from);
+ options.maxFreed = readLongLong(from);
+ options.maxLinks = readInt(from);
+
+ GCResults results;
startWork();
- if (ignoreLiveness)
+ if (options.ignoreLiveness)
throw Error("you are not allowed to ignore liveness");
- store->collectGarbage(action, pathsToDelete, ignoreLiveness,
- result, bytesFreed);
+ store->collectGarbage(options, results);
stopWork();
- writeStringSet(result, to);
- writeInt(bytesFreed & 0xffffffff, to);
- writeInt(bytesFreed >> 32, to);
+ writeStringSet(results.paths, to);
+ writeLongLong(results.bytesFreed, to);
+ writeLongLong(results.blocksFreed, to);
break;
}