X-Git-Url: http://git.hcoop.net/jackhill/guix/guix.git/blobdiff_plain/2e3e5d21988fc2cafb2a9eaf4b00976ea425629d..69a81892acf71aae4ea2aa98c015bfaf1649caba:/nix/libstore/gc.cc diff --git a/nix/libstore/gc.cc b/nix/libstore/gc.cc index c466996668..e1d0765154 100644 --- a/nix/libstore/gc.cc +++ b/nix/libstore/gc.cc @@ -11,6 +11,7 @@ #include #include #include +#include namespace nix { @@ -391,7 +392,14 @@ bool LocalStore::isActiveTempFile(const GCState & state, void LocalStore::deleteGarbage(GCState & state, const Path & path) { unsigned long long bytesFreed; - deletePath(path, bytesFreed); + + /* When deduplication is on, store items always have at least two links: + the one at PATH, and one in /gnu/store/.links. In that case, increase + bytesFreed when PATH has two or fewer links. */ + size_t linkThreshold = + (settings.autoOptimiseStore && isStorePath(path)) ? 2 : 1; + + deletePath(path, bytesFreed, linkThreshold); state.results.bytesFreed += bytesFreed; } @@ -417,7 +425,16 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path) throw SysError(format("getting status of %1%") % path); } - printMsg(lvlInfo, format("deleting `%1%'") % path); + if (state.options.maxFreed != ULLONG_MAX) { + auto freed = state.results.bytesFreed + state.bytesInvalidated; + double fraction = ((double) freed) / (double) state.options.maxFreed; + unsigned int percentage = (fraction > 1. ? 1. : fraction) * 100.; + printMsg(lvlInfo, format("[%1%%%] deleting '%2%'") % percentage % path); + } else { + auto freed = state.results.bytesFreed + state.bytesInvalidated; + freed /= 1024ULL * 1024ULL; + printMsg(lvlInfo, format("[%1% MiB] deleting '%2%'") % freed % path); + } state.results.paths.insert(path); @@ -438,7 +455,10 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path) throw SysError(format("unable to rename `%1%' to `%2%'") % path % tmp); state.bytesInvalidated += size; } catch (SysError & e) { - if (e.errNo == ENOSPC) { + /* In a Docker container, rename(2) returns EXDEV when the source + and destination are not both on the "top layer". See: + https://bugs.gnu.org/41607 */ + if (e.errNo == ENOSPC || e.errNo == EXDEV) { printMsg(lvlInfo, format("note: can't create move `%1%': %2%") % path % e.msg()); deleteGarbage(state, path); } @@ -561,9 +581,30 @@ void LocalStore::removeUnusedLinks(const GCState & state) if (name == "." || name == "..") continue; Path path = linksDir + "/" + name; +#ifdef HAVE_STATX +# define st_size stx_size +# define st_nlink stx_nlink + static int statx_flags = AT_SYMLINK_NOFOLLOW | AT_STATX_DONT_SYNC; + struct statx st; + + if (statx(AT_FDCWD, path.c_str(), statx_flags, + STATX_SIZE | STATX_NLINK, &st) == -1) { + if (errno == EINVAL) { + /* Old 3.10 kernels (CentOS 7) don't support + AT_STATX_DONT_SYNC, so try again without it. */ + statx_flags &= ~AT_STATX_DONT_SYNC; + if (statx(AT_FDCWD, path.c_str(), statx_flags, + STATX_SIZE | STATX_NLINK, &st) == -1) + throw SysError(format("statting `%1%'") % path); + } else { + throw SysError(format("statting `%1%'") % path); + } + } +#else struct stat st; if (lstat(path.c_str(), &st) == -1) throw SysError(format("statting `%1%'") % path); +#endif if (st.st_nlink != 1) { actualSize += st.st_size; @@ -577,6 +618,8 @@ void LocalStore::removeUnusedLinks(const GCState & state) throw SysError(format("deleting `%1%'") % path); state.results.bytesFreed += st.st_size; +#undef st_size +#undef st_nlink } struct stat st; @@ -620,10 +663,9 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) foreach (Roots::iterator, i, rootMap) state.roots.insert(i->second); - /* Add additional roots returned by the program specified by the - 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). */ + /* Add additional roots returned by 'guix gc --list-busy'. This is + typically used to add running programs to the set of roots (to prevent + them from being garbage collected). */ if (!options.ignoreLiveness) addAdditionalRoots(*this, state.roots);