diff options
Diffstat (limited to 'third_party/nix/src/libstore/gc.cc')
-rw-r--r-- | third_party/nix/src/libstore/gc.cc | 129 |
1 files changed, 76 insertions, 53 deletions
diff --git a/third_party/nix/src/libstore/gc.cc b/third_party/nix/src/libstore/gc.cc index 94cf1b7d4187..183b3c1a4a17 100644 --- a/third_party/nix/src/libstore/gc.cc +++ b/third_party/nix/src/libstore/gc.cc @@ -13,6 +13,7 @@ #include "derivations.hh" #include "finally.hh" #include "globals.hh" +#include "glog/logging.h" #include "local-store.hh" namespace nix { @@ -28,15 +29,16 @@ static string gcRootsDir = "gcroots"; AutoCloseFD LocalStore::openGCLock(LockType lockType) { Path fnGCLock = (format("%1%/%2%") % stateDir % gcLockName).str(); - debug(format("acquiring global GC lock '%1%'") % fnGCLock); + DLOG(INFO) << "acquiring global GC lock " << fnGCLock; AutoCloseFD fdGCLock = open(fnGCLock.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600); - if (!fdGCLock) + if (!fdGCLock) { throw SysError(format("opening global GC lock '%1%'") % fnGCLock); + } if (!lockFile(fdGCLock.get(), lockType, false)) { - printError(format("waiting for the big garbage collector lock...")); + LOG(ERROR) << "waiting for the big garbage collector lock..."; lockFile(fdGCLock.get(), lockType, true); } @@ -116,12 +118,12 @@ Path LocalFSStore::addPermRoot(const Path& _storePath, const Path& _gcRoot, gcroots directory. */ if (settings.checkRootReachability) { Roots roots = findRoots(false); - if (roots[storePath].count(gcRoot) == 0) - printError( - format("warning: '%1%' is not in a directory where the garbage " - "collector looks for roots; " - "therefore, '%2%' might be removed by the garbage collector") % - gcRoot % storePath); + if (roots[storePath].count(gcRoot) == 0) { + LOG(ERROR) << "warning: '" << gcRoot + << "' is not in a directory where the garbage " + << "collector looks for roots; therefore, '" << storePath + << "' might be removed by the garbage collector"; + } } /* Grab the global GC root, causing us to block while a GC is in @@ -149,7 +151,7 @@ void LocalStore::addTempRoot(const Path& path) { fdGCLock = -1; - debug(format("acquiring read lock on '%1%'") % fnTempRoots); + DLOG(INFO) << "acquiring read lock on " << fnTempRoots; lockFile(state->fdTempRoots.get(), ltRead, true); /* Check whether the garbage collector didn't get in our @@ -167,14 +169,14 @@ void LocalStore::addTempRoot(const Path& path) { /* Upgrade the lock to a write lock. This will cause us to block if the garbage collector is holding our lock. */ - debug(format("acquiring write lock on '%1%'") % fnTempRoots); + DLOG(INFO) << "acquiring write lock on " << fnTempRoots; lockFile(state->fdTempRoots.get(), ltWrite, true); string s = path + '\0'; writeFull(state->fdTempRoots.get(), s); /* Downgrade to a read lock. */ - debug(format("downgrading to read lock on '%1%'") % fnTempRoots); + DLOG(INFO) << "downgrading to read lock on " << fnTempRoots; lockFile(state->fdTempRoots.get(), ltRead, true); } @@ -188,7 +190,7 @@ void LocalStore::findTempRoots(FDs& fds, Roots& tempRoots, bool censor) { pid_t pid = std::stoi(i.name); - debug(format("reading temporary root file '%1%'") % path); + DLOG(INFO) << "reading temporary root file " << path; FDPtr fd(new AutoCloseFD(open(path.c_str(), O_CLOEXEC | O_RDWR, 0666))); if (!*fd) { /* It's okay if the file has disappeared. */ @@ -204,7 +206,7 @@ void LocalStore::findTempRoots(FDs& fds, Roots& tempRoots, bool censor) { only succeed if the owning process has died. In that case we don't care about its temporary roots. */ if (lockFile(fd->get(), ltWrite, false)) { - printError(format("removing stale temporary roots file '%1%'") % path); + LOG(ERROR) << "removing stale temporary roots file " << path; unlink(path.c_str()); writeFull(fd->get(), "d"); continue; @@ -213,7 +215,7 @@ void LocalStore::findTempRoots(FDs& fds, Roots& tempRoots, bool censor) { /* Acquire a read lock. This will prevent the owning process from upgrading to a write lock, therefore it will block in addTempRoot(). */ - debug(format("waiting for read lock on '%1%'") % path); + DLOG(INFO) << "waiting for read lock on " << path; lockFile(fd->get(), ltRead, true); /* Read the entire file. */ @@ -224,7 +226,7 @@ void LocalStore::findTempRoots(FDs& fds, Roots& tempRoots, bool censor) { while ((end = contents.find((char)0, pos)) != string::npos) { Path root(contents, pos, end - pos); - debug("got temporary root '%s'", root); + DLOG(INFO) << "got temporary root " << root; assertStorePath(root); tempRoots[root].emplace(censor ? censored : fmt("{temp:%d}", pid)); pos = end + 1; @@ -240,8 +242,8 @@ void LocalStore::findRoots(const Path& path, unsigned char type, Roots& roots) { if (isStorePath(storePath) && isValidPath(storePath)) roots[storePath].emplace(path); else - printInfo(format("skipping invalid root from '%1%' to '%2%'") % path % - storePath); + LOG(INFO) << "skipping invalid root from '" << path << "' to '" + << storePath << "'"; }; try { @@ -261,8 +263,8 @@ void LocalStore::findRoots(const Path& path, unsigned char type, Roots& roots) { target = absPath(target, dirOf(path)); if (!pathExists(target)) { if (isInDir(path, stateDir + "/" + gcRootsDir + "/auto")) { - printInfo(format("removing stale link from '%1%' to '%2%'") % path % - target); + LOG(INFO) << "removing stale link from '" << path << "' to '" + << target << "'"; unlink(path.c_str()); } } else { @@ -284,10 +286,11 @@ void LocalStore::findRoots(const Path& path, unsigned char type, Roots& roots) { catch (SysError& e) { /* We only ignore permanent failures. */ - if (e.errNo == EACCES || e.errNo == ENOENT || e.errNo == ENOTDIR) - printInfo(format("cannot read potential root '%1%'") % path); - else + if (e.errNo == EACCES || e.errNo == ENOENT || e.errNo == ENOTDIR) { + LOG(INFO) << "cannot read potential root '" << path << "'"; + } else { throw; + } } } @@ -319,16 +322,21 @@ try_again: char buf[bufsiz]; auto res = readlink(file.c_str(), buf, bufsiz); if (res == -1) { - if (errno == ENOENT || errno == EACCES || errno == ESRCH) return; + if (errno == ENOENT || errno == EACCES || errno == ESRCH) { + return; + } throw SysError("reading symlink"); } if (res == bufsiz) { - if (SSIZE_MAX / 2 < bufsiz) throw Error("stupidly long symlink"); + if (SSIZE_MAX / 2 < bufsiz) { + throw Error("stupidly long symlink"); + } bufsiz *= 2; goto try_again; } - if (res > 0 && buf[0] == '/') + if (res > 0 && buf[0] == '/') { roots[std::string(static_cast<char*>(buf), res)].emplace(file); + } } static string quoteRegexChars(const string& raw) { @@ -340,7 +348,9 @@ static void readFileRoots(const char* path, Roots& roots) { try { roots[readFile(path)].emplace(path); } catch (SysError& e) { - if (e.errNo != ENOENT && e.errNo != EACCES) throw; + if (e.errNo != ENOENT && e.errNo != EACCES) { + throw; + } } } @@ -434,7 +444,7 @@ void LocalStore::findRuntimeRoots(Roots& roots, bool censor) { if (isInStore(target)) { Path path = toStorePath(target); if (isStorePath(path) && isValidPath(path)) { - debug(format("got additional root '%1%'") % path); + DLOG(INFO) << "got additional root " << path; if (censor) roots[path].insert(censored); else @@ -496,7 +506,7 @@ void LocalStore::deletePathRecursive(GCState& state, const Path& path) { throw SysError(format("getting status of %1%") % realPath); } - printInfo(format("deleting '%1%'") % path); + LOG(INFO) << "deleting '" << path << "'"; state.results.paths.insert(path); @@ -519,8 +529,8 @@ void LocalStore::deletePathRecursive(GCState& state, const Path& path) { state.bytesInvalidated += size; } catch (SysError& e) { if (e.errNo == ENOSPC) { - printInfo(format("note: can't create move '%1%': %2%") % realPath % - e.msg()); + LOG(INFO) << "note: can't create move '" << realPath + << "': " << e.msg(); deleteGarbage(state, realPath); } } @@ -529,8 +539,8 @@ void LocalStore::deletePathRecursive(GCState& state, const Path& path) { if (state.results.bytesFreed + state.bytesInvalidated > state.options.maxFreed) { - printInfo(format("deleted or invalidated more than %1% bytes; stopping") % - state.options.maxFreed); + LOG(INFO) << "deleted or invalidated more than " << state.options.maxFreed + << " bytes; stopping"; throw GCLimitReached(); } } @@ -544,7 +554,7 @@ bool LocalStore::canReachRoot(GCState& state, PathSet& visited, if (state.dead.count(path)) return false; if (state.roots.count(path)) { - debug(format("cannot delete '%1%' because it's a root") % path); + DLOG(INFO) << "cannot delete '" << path << "' because it's a root"; state.alive.insert(path); return true; } @@ -611,7 +621,7 @@ void LocalStore::tryToDelete(GCState& state, const Path& path) { PathSet visited; if (canReachRoot(state, visited, path)) { - debug(format("cannot delete '%1%' because it's still reachable") % path); + DLOG(INFO) << "cannot delete '" << path << "' because it's still reachable"; } else { /* No path we visited was a root, so everything is garbage. But we only delete ‘path’ and its referrers here so that @@ -629,7 +639,9 @@ void LocalStore::tryToDelete(GCState& state, const Path& path) { the link count. */ void LocalStore::removeUnusedLinks(const GCState& state) { AutoCloseDir dir(opendir(linksDir.c_str())); - if (!dir) throw SysError(format("opening directory '%1%'") % linksDir); + if (!dir) { + throw SysError(format("opening directory '%1%'") % linksDir); + } long long actualSize = 0, unsharedSize = 0; @@ -650,21 +662,26 @@ void LocalStore::removeUnusedLinks(const GCState& state) { continue; } - printMsg(lvlTalkative, format("deleting unused link '%1%'") % path); + LOG(INFO) << "deleting unused link " << path; - if (unlink(path.c_str()) == -1) + if (unlink(path.c_str()) == -1) { throw SysError(format("deleting '%1%'") % path); + } state.results.bytesFreed += st.st_size; } struct stat st; - if (stat(linksDir.c_str(), &st) == -1) + if (stat(linksDir.c_str(), &st) == -1) { throw SysError(format("statting '%1%'") % linksDir); + } + long long overhead = st.st_blocks * 512ULL; - printInfo(format("note: currently hard linking saves %.2f MiB") % - ((unsharedSize - actualSize - overhead) / (1024.0 * 1024.0))); + // TODO(tazjin): absl::StrFormat %.2f + LOG(INFO) << "note: currently hard linking saves " + << ((unsharedSize - actualSize - overhead) / (1024.0 * 1024.0)) + << " MiB"; } void LocalStore::collectGarbage(const GCOptions& options, GCResults& results) { @@ -694,11 +711,15 @@ void LocalStore::collectGarbage(const GCOptions& options, GCResults& results) { /* Find the roots. Since we've grabbed the GC lock, the set of permanent roots cannot increase now. */ - printError(format("finding garbage collector roots...")); + LOG(INFO) << "finding garbage collector roots..."; Roots rootMap; - if (!options.ignoreLiveness) findRootsNoTemp(rootMap, true); + if (!options.ignoreLiveness) { + findRootsNoTemp(rootMap, true); + } - for (auto& i : rootMap) state.roots.insert(i.first); + for (auto& i : rootMap) { + state.roots.insert(i.first); + } /* Read the temporary roots. This acquires read locks on all per-process temporary root files. So after this point no paths @@ -719,7 +740,7 @@ void LocalStore::collectGarbage(const GCOptions& options, GCResults& results) { createDirs(trashDir); } catch (SysError& e) { if (e.errNo == ENOSPC) { - printInfo(format("note: can't create trash directory: %1%") % e.msg()); + LOG(INFO) << "note: can't create trash directory: " << e.msg(); state.moveToTrash = false; } } @@ -739,14 +760,15 @@ void LocalStore::collectGarbage(const GCOptions& options, GCResults& results) { } else if (options.maxFreed > 0) { if (state.shouldDelete) - printError(format("deleting garbage...")); + LOG(INFO) << "deleting garbage..."; else - printError(format("determining live/dead paths...")); + LOG(ERROR) << "determining live/dead paths..."; try { AutoCloseDir dir(opendir(realStoreDir.c_str())); - if (!dir) + if (!dir) { throw SysError(format("opening directory '%1%'") % realStoreDir); + } /* Read the store and immediately delete all paths that aren't valid. When using --max-freed etc., deleting @@ -799,13 +821,13 @@ void LocalStore::collectGarbage(const GCOptions& options, GCResults& results) { fds.clear(); /* Delete the trash directory. */ - printInfo(format("deleting '%1%'") % trashDir); + LOG(INFO) << "deleting " << trashDir; deleteGarbage(state, trashDir); /* Clean up the links directory. */ if (options.action == GCOptions::gcDeleteDead || options.action == GCOptions::gcDeleteSpecific) { - printError(format("deleting unused links...")); + LOG(INFO) << "deleting unused links..."; removeUnusedLinks(state); } @@ -821,8 +843,9 @@ void LocalStore::autoGC(bool sync) { return std::stoll(readFile(fakeFreeSpaceFile)); struct statvfs st; - if (statvfs(realStoreDir.c_str(), &st)) + if (statvfs(realStoreDir.c_str(), &st)) { throw SysError("getting filesystem info about '%s'", realStoreDir); + } return (uint64_t)st.f_bavail * st.f_bsize; }; @@ -834,7 +857,7 @@ void LocalStore::autoGC(bool sync) { if (state->gcRunning) { future = state->gcFuture; - debug("waiting for auto-GC to finish"); + DLOG(INFO) << "waiting for auto-GC to finish"; goto sync; } @@ -870,7 +893,7 @@ void LocalStore::autoGC(bool sync) { GCOptions options; options.maxFreed = settings.maxFree - avail; - printInfo("running auto-GC to free %d bytes", options.maxFreed); + LOG(INFO) << "running auto-GC to free " << options.maxFreed << " bytes"; GCResults results; |