diff options
Diffstat (limited to 'src/libstore')
-rw-r--r-- | src/libstore/build.cc | 10 | ||||
-rw-r--r-- | src/libstore/gc.cc | 54 | ||||
-rw-r--r-- | src/libstore/local-store.cc | 5 | ||||
-rw-r--r-- | src/libstore/local-store.hh | 18 | ||||
-rw-r--r-- | src/libstore/optimise-store.cc | 1 | ||||
-rw-r--r-- | src/libstore/remote-store.cc | 22 | ||||
-rw-r--r-- | src/libstore/remote-store.hh | 3 | ||||
-rw-r--r-- | src/libstore/store-api.hh | 113 | ||||
-rw-r--r-- | src/libstore/worker-protocol.hh | 34 |
9 files changed, 149 insertions, 111 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 0664a118a00f..1d624723f92b 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 c46cc817bc9d..0caf1ce4e627 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 2e53d0dc6da4..105f711228a8 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 444a5f3402df..1957b9f57948 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 c260f253e3c7..bd76a1aeccef 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 14412b8c8b60..274196a2b6a9 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 1501591e2a57..c40feeaa4743 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 a50dcf645193..760e71adc70b 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 44db4ad9b141..d887ee59bd95 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; |