GC: Handle ENOSPC creating/moving to the trash directory

Issue #564.
This commit is contained in:
Eelco Dolstra 2015-06-30 21:41:26 +02:00 committed by Ludovic Courtès
parent 5e0a9ae2e2
commit 6e38685ef6
1 changed files with 23 additions and 8 deletions

View File

@ -376,6 +376,7 @@ struct LocalStore::GCState
bool gcKeepOutputs; bool gcKeepOutputs;
bool gcKeepDerivations; bool gcKeepDerivations;
unsigned long long bytesInvalidated; unsigned long long bytesInvalidated;
bool moveToTrash = true;
Path trashDir; Path trashDir;
bool shouldDelete; bool shouldDelete;
GCState(GCResults & results_) : results(results_), bytesInvalidated(0) { } GCState(GCResults & results_) : results(results_), bytesInvalidated(0) { }
@ -428,16 +429,23 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
not holding the global GC lock) we can delete the path without not holding the global GC lock) we can delete the path without
being afraid that the path has become alive again. Otherwise being afraid that the path has become alive again. Otherwise
delete it right away. */ delete it right away. */
if (S_ISDIR(st.st_mode)) { if (state.moveToTrash && S_ISDIR(st.st_mode)) {
// Estimate the amount freed using the narSize field. FIXME: // Estimate the amount freed using the narSize field. FIXME:
// if the path was not valid, need to determine the actual // if the path was not valid, need to determine the actual
// size. // size.
state.bytesInvalidated += size; try {
if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1) if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
throw SysError(format("making `%1%' writable") % path); throw SysError(format("making `%1%' writable") % path);
Path tmp = state.trashDir + "/" + baseNameOf(path); Path tmp = state.trashDir + "/" + baseNameOf(path);
if (rename(path.c_str(), tmp.c_str())) if (rename(path.c_str(), tmp.c_str()))
throw SysError(format("unable to rename `%1%' to `%2%'") % path % tmp); throw SysError(format("unable to rename `%1%' to `%2%'") % path % tmp);
state.bytesInvalidated += size;
} catch (SysError & e) {
if (e.errNo == ENOSPC) {
printMsg(lvlInfo, format("note: can't create move `%1%': %2%") % path % e.msg());
deleteGarbage(state, path);
}
}
} else } else
deleteGarbage(state, path); deleteGarbage(state, path);
@ -636,7 +644,14 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
if (state.shouldDelete) { if (state.shouldDelete) {
if (pathExists(state.trashDir)) deleteGarbage(state, state.trashDir); if (pathExists(state.trashDir)) deleteGarbage(state, state.trashDir);
createDirs(state.trashDir); try {
createDirs(state.trashDir);
} catch (SysError & e) {
if (e.errNo == ENOSPC) {
printMsg(lvlInfo, format("note: can't create trash directory: %1%") % e.msg());
state.moveToTrash = false;
}
}
} }
/* Now either delete all garbage paths, or just the specified /* Now either delete all garbage paths, or just the specified