nix store gc: account for auto-optimised store

Before the change on a system with `auto-optimise-store = true`:

    $ nix store gc --verbose --max 1

deleted all the paths instead of one path (we requested 1 byte limit).

It happens because every file in `auto-optimise-store = true` has at
least 2 links: file itself and a link in /nix/store/.links/ directory.

The change conservatively assumes that any file that has one (as before)
or two links (assume auto-potimise mode) will free space.

Co-authored-by: Sandro <sandro.jaeckel@gmail.com>
This commit is contained in:
Sergei Trofimovich 2022-03-12 21:56:08 +00:00
parent d5322698a2
commit 6b1872312f
2 changed files with 25 additions and 3 deletions

View file

@ -841,7 +841,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
if (unlink(path.c_str()) == -1) if (unlink(path.c_str()) == -1)
throw SysError("deleting '%1%'", path); throw SysError("deleting '%1%'", path);
results.bytesFreed += st.st_size; /* Do not accound for deleted file here. Rely on deletePath()
accounting. */
} }
struct stat st; struct stat st;

View file

@ -406,8 +406,29 @@ static void _deletePath(int parentfd, const Path & path, uint64_t & bytesFreed)
throw SysError("getting status of '%1%'", path); throw SysError("getting status of '%1%'", path);
} }
if (!S_ISDIR(st.st_mode) && st.st_nlink == 1) if (!S_ISDIR(st.st_mode)) {
bytesFreed += st.st_size; /* We are about to delete a file. Will it likely free space? */
switch (st.st_nlink) {
/* Yes: last link. */
case 1:
bytesFreed += st.st_size;
break;
/* Maybe: yes, if 'auto-optimise-store' or manual optimisation
was performed. Instead of checking for real let's assume
it's an optimised file and space will be freed.
In worst case we will double count on freed space for files
with exactly two hardlinks for unoptimised packages.
*/
case 2:
bytesFreed += st.st_size;
break;
/* No: 3+ links. */
default:
break;
}
}
if (S_ISDIR(st.st_mode)) { if (S_ISDIR(st.st_mode)) {
/* Make the directory accessible. */ /* Make the directory accessible. */