Guarantee that store entries appear atomically
When Nix has performed a derivation, the output is moved from the temporary directory in which it currently resides to /nix/store. This can be and apparently is done atomically if /tmp and /nix/store reside on the same volume.
However, what happens if they don’t? Is the derivation then just copied into /nix/store (and afterwards deleted from /tmp)? This could result in a directory under /nix/store that has the appropriate name but lacks part of the contents, in case the command that triggered the derivation is interrupted. An approach that would guarantee atomic appearance of the derivation output in the store is to copy the corresponding directory with its contents into the store under a temporary name that doesn’t follow the pattern of ordinary in-store directory names and then rename the directory, which would be an atomic operation.
Has such an alternative approach be considered, or is it perhaps even what Nix is using?
Add :+1: to issues you find important.
This issue has been mentioned on NixOS Discourse. There might be relevant details there:
https://discourse.nixos.org/t/nixos-rebuild-hangs-while-downloading-from-cache-nixos-org/68875/22
Somewhat related: https://github.com/NixOS/nix/issues/11655.
When Nix has performed a derivation, the output is moved from the temporary directory in which it currently resides to /nix/store.
Note that the output that gets moved is not in /tmp. When using sandboxing on Linux, it's in the chroot directory (/nix/store/<derivation>.chroot) which is in the same filesystem as /nix/store. When not using sandboxing, builders write their output directly to /nix/store.
This could result in a directory under /nix/store that has the appropriate name but lacks part of the contents, in case the command that triggered the derivation is interrupted.
The output is not considered valid until it is registered as such in /nix/var/nix/db/db.sqlite, so interrupting the derivation is not a problem. However, unless fsync-store-paths is set, it's not guaranteed that writes to /nix/store are flushed to disk before the database is updated. So if the system crashes after the derivation has finished, you might end up with a corrupted store path.
However, unless
fsync-store-pathsis set, it’s not guaranteed that writes to/nix/storeare flushed to disk before the database is updated.
Interesting. Is fsync-store-paths enabled in NixOS by default? Where would I enable it if it weren’t?
nix.settings.fsync-store-paths = true;