This commit is contained in:
Eelco Dolstra 2021-10-08 14:58:35 +02:00
parent dced45f146
commit 1785ba2980
2 changed files with 88 additions and 88 deletions

View file

@ -479,21 +479,36 @@ struct LocalStore::GCState
}; };
void LocalStore::deleteFromStore(GCState & state, std::string_view baseName)
{
Path path = storeDir + "/" + std::string(baseName);
Path realPath = realStoreDir + "/" + std::string(baseName);
printInfo("deleting '%1%'", path);
state.results.paths.insert(path);
uint64_t bytesFreed;
deletePath(realPath, bytesFreed);
state.results.bytesFreed += bytesFreed;
if (state.results.bytesFreed > state.options.maxFreed) {
printInfo("deleted more than %d bytes; stopping", state.options.maxFreed);
throw GCLimitReached();
}
}
bool LocalStore::tryToDelete( bool LocalStore::tryToDelete(
GCState & state, GCState & state,
StorePathSet & visited, StorePathSet & visited,
const Path & path, const StorePath & path,
bool recursive) bool recursive)
{ {
checkInterrupt(); checkInterrupt();
auto realPath = realStoreDir + "/" + std::string(baseNameOf(path));
if (realPath == linksDir) return false;
//Activity act(*logger, lvlDebug, format("considering whether to delete '%1%'") % path); //Activity act(*logger, lvlDebug, format("considering whether to delete '%1%'") % path);
auto storePath = maybeParseStorePath(path);
/* Wake up any client waiting for deletion of this path to /* Wake up any client waiting for deletion of this path to
finish. */ finish. */
Finally releasePending([&]() { Finally releasePending([&]() {
@ -502,89 +517,66 @@ bool LocalStore::tryToDelete(
state.wakeup.notify_all(); state.wakeup.notify_all();
}); });
if (storePath) { if (!visited.insert(path).second) return true;
if (!visited.insert(*storePath).second) return true; if (state.alive.count(path)) return false;
if (state.alive.count(*storePath)) return false; if (state.dead.count(path)) return true;
if (state.dead.count(*storePath)) return true; if (state.roots.count(path)) {
debug("cannot delete '%s' because it's a root", printStorePath(path));
if (state.roots.count(*storePath)) { state.alive.insert(path);
debug("cannot delete '%s' because it's a root", path); return false;
state.alive.insert(*storePath);
return false;
}
if (isValidPath(*storePath)) {
StorePathSet incoming;
/* Don't delete this path if any of its referrers are alive. */
queryReferrers(*storePath, incoming);
/* If keep-derivations is set and this is a derivation, then
don't delete the derivation if any of the outputs are alive. */
if (state.gcKeepDerivations && storePath->isDerivation()) {
for (auto & [name, maybeOutPath] : queryPartialDerivationOutputMap(*storePath))
if (maybeOutPath &&
isValidPath(*maybeOutPath) &&
queryPathInfo(*maybeOutPath)->deriver == *storePath)
incoming.insert(*maybeOutPath);
}
/* If keep-outputs is set, then don't delete this path if there
are derivers of this path that are not garbage. */
if (state.gcKeepOutputs) {
auto derivers = queryValidDerivers(*storePath);
for (auto & i : derivers)
incoming.insert(i);
}
for (auto & i : incoming)
if (i != *storePath
&& (recursive || state.options.pathsToDelete.count(i))
&& !tryToDelete(state, visited, printStorePath(i), recursive))
{
state.alive.insert(*storePath);
return false;
}
}
{
auto hashPart = std::string(storePath->hashPart());
auto shared(state.shared.lock());
if (shared->tempRoots.count(hashPart))
return false;
shared->pending = hashPart;
}
state.dead.insert(*storePath);
if (state.shouldDelete)
invalidatePathChecked(*storePath);
} }
if (isValidPath(path)) {
StorePathSet incoming;
/* Don't delete this path if any of its referrers are alive. */
queryReferrers(path, incoming);
/* If keep-derivations is set and this is a derivation, then
don't delete the derivation if any of the outputs are
alive. */
if (state.gcKeepDerivations && path.isDerivation()) {
for (auto & [name, maybeOutPath] : queryPartialDerivationOutputMap(path))
if (maybeOutPath &&
isValidPath(*maybeOutPath) &&
queryPathInfo(*maybeOutPath)->deriver == path)
incoming.insert(*maybeOutPath);
}
/* If keep-outputs is set, then don't delete this path if
there are derivers of this path that are not garbage. */
if (state.gcKeepOutputs) {
auto derivers = queryValidDerivers(path);
for (auto & i : derivers)
incoming.insert(i);
}
for (auto & i : incoming)
if (i != path
&& (recursive || state.options.pathsToDelete.count(i))
&& !tryToDelete(state, visited, i, recursive))
{
state.alive.insert(path);
return false;
}
}
{
auto hashPart = std::string(path.hashPart());
auto shared(state.shared.lock());
if (shared->tempRoots.count(hashPart))
return false;
shared->pending = hashPart;
}
state.dead.insert(path);
if (state.shouldDelete) { if (state.shouldDelete) {
Path realPath = realStoreDir + "/" + std::string(baseNameOf(path)); invalidatePathChecked(path);
deleteFromStore(state, path.to_string());
struct stat st;
if (lstat(realPath.c_str(), &st)) {
if (errno == ENOENT) return true;
throw SysError("getting status of %1%", realPath);
}
printInfo("deleting '%1%'", path);
state.results.paths.insert(path);
uint64_t bytesFreed;
deletePath(realPath, bytesFreed);
state.results.bytesFreed += bytesFreed;
if (state.results.bytesFreed > state.options.maxFreed) {
printInfo("deleted more than %d bytes; stopping", state.options.maxFreed);
throw GCLimitReached();
}
} }
return true; return true;
@ -777,7 +769,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
for (auto & i : options.pathsToDelete) { for (auto & i : options.pathsToDelete) {
StorePathSet visited; StorePathSet visited;
if (!tryToDelete(state, visited, printStorePath(i), false)) if (!tryToDelete(state, visited, i, false))
throw Error( throw Error(
"cannot delete path '%1%' since it is still alive. " "cannot delete path '%1%' since it is still alive. "
"To find out why, use: " "To find out why, use: "
@ -799,14 +791,20 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
/* Read the store and delete all paths that are invalid or /* Read the store and delete all paths that are invalid or
unreachable. We don't use readDirectory() here so that unreachable. We don't use readDirectory() here so that
GCing can start faster. */ GCing can start faster. */
auto linksName = baseNameOf(linksDir);
Paths entries; Paths entries;
struct dirent * dirent; struct dirent * dirent;
while (errno = 0, dirent = readdir(dir.get())) { while (errno = 0, dirent = readdir(dir.get())) {
checkInterrupt(); checkInterrupt();
string name = dirent->d_name; string name = dirent->d_name;
if (name == "." || name == "..") continue; if (name == "." || name == ".." || name == linksName) continue;
StorePathSet visited;
tryToDelete(state, visited, storeDir + "/" + name, true); if (auto storePath = maybeParseStorePath(storeDir + "/" + name)) {
StorePathSet visited;
tryToDelete(state, visited, *storePath, true);
} else
deleteFromStore(state, name);
} }
} catch (GCLimitReached & e) { } catch (GCLimitReached & e) {
} }

View file

@ -243,9 +243,11 @@ private:
bool tryToDelete( bool tryToDelete(
GCState & state, GCState & state,
StorePathSet & visited, StorePathSet & visited,
const Path & path, const StorePath & path,
bool recursive); bool recursive);
void deleteFromStore(GCState & state, std::string_view baseName);
void findRoots(const Path & path, unsigned char type, Roots & roots); void findRoots(const Path & path, unsigned char type, Roots & roots);
void findRootsNoTemp(Roots & roots, bool censor); void findRootsNoTemp(Roots & roots, bool censor);