diff --git a/doc/manual/conf-file.xml b/doc/manual/conf-file.xml index 66df3edd5..2ee268097 100644 --- a/doc/manual/conf-file.xml +++ b/doc/manual/conf-file.xml @@ -233,7 +233,17 @@ build-use-chroot = /dev /proc /bin configure at build time. - + + + fsync-metadata + + If set to true, changes to the + Nix store metadata (in /nix/var/nix/db) are + synchronously flushed to disk. This improves robustness in case + of system crashes, but reduces performance. The default is + false. + + diff --git a/src/libstore/build.cc b/src/libstore/build.cc index d56ae4570..77cffba25 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -1318,18 +1318,18 @@ DerivationGoal::HookReply DerivationGoal::tryBuildHook() string s; foreach (PathSet::iterator, i, allInputs) s += *i + "\n"; - writeStringToFile(inputListFN, s); + writeFile(inputListFN, s); /* The `outputs' file lists all outputs that have to be copied from the remote system. */ s = ""; foreach (DerivationOutputs::iterator, i, drv.outputs) s += i->second.path + "\n"; - writeStringToFile(outputListFN, s); + writeFile(outputListFN, s); /* The `references' file has exactly the format accepted by `nix-store --register-validity'. */ - writeStringToFile(referencesFN, + writeFile(referencesFN, makeValidityRegistration(allInputs, true, false)); /* Tell the hook to proceed. */ @@ -1493,7 +1493,7 @@ void DerivationGoal::startBuilder() } /* Write closure info to `fileName'. */ - writeStringToFile(tmpDir + "/" + fileName, + writeFile(tmpDir + "/" + fileName, makeValidityRegistration(paths, false, false)); } @@ -1570,7 +1570,7 @@ void DerivationGoal::startBuilder() support Samba-in-QEMU. */ createDirs(chrootRootDir + "/etc"); - writeStringToFile(chrootRootDir + "/etc/passwd", + writeFile(chrootRootDir + "/etc/passwd", (format( "nixbld:x:%1%:65534:Nix build user:/:/noshell\n" "nobody:x:65534:65534:Nobody:/:/noshell\n") diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 93ce8c047..7c8db745c 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -89,6 +89,8 @@ LocalStore::LocalStore() } if (curSchema == 1) throw Error("your Nix store is no longer supported"); if (curSchema < nixSchemaVersion) upgradeStore12(); + + doFsync = queryBoolSetting("fsync-metadata", false); } @@ -222,7 +224,7 @@ static Path tmpFileForAtomicUpdate(const Path & path) } -static void appendReferrer(const Path & from, const Path & to, bool lock) +void LocalStore::appendReferrer(const Path & from, const Path & to, bool lock) { Path referrersFile = referrersFileFor(from); @@ -237,6 +239,8 @@ static void appendReferrer(const Path & from, const Path & to, bool lock) string s = " " + to; writeFull(fd, (const unsigned char *) s.c_str(), s.size()); + + if (doFsync) fdatasync(fd); } @@ -267,6 +271,8 @@ void LocalStore::rewriteReferrers(const Path & path, bool purge, PathSet referre writeFull(fd, (const unsigned char *) s.c_str(), s.size()); + if (doFsync) fdatasync(fd); + fd.close(); /* for Windows; can't rename open file */ if (rename(tmpFile.c_str(), referrersFile.c_str()) == -1) @@ -347,7 +353,7 @@ void LocalStore::registerValidPath(const ValidPathInfo & info, bool ignoreValidi /* Atomically rewrite the info file. */ Path tmpFile = tmpFileForAtomicUpdate(infoFile); - writeFile(tmpFile, s); + writeFile(tmpFile, s, doFsync); if (rename(tmpFile.c_str(), infoFile.c_str()) == -1) throw SysError(format("cannot rename `%1%' to `%2%'") % tmpFile % infoFile); @@ -737,7 +743,7 @@ Path LocalStore::addToStoreFromDump(const string & dump, const string & name, StringSource source(dump); restorePath(dstPath, source); } else - writeStringToFile(dstPath, dump); + writeFile(dstPath, dump); canonicalisePathMetaData(dstPath); @@ -792,7 +798,7 @@ Path LocalStore::addTextToStore(const string & name, const string & s, if (pathExists(dstPath)) deletePathWrapped(dstPath); - writeStringToFile(dstPath, s); + writeFile(dstPath, s); canonicalisePathMetaData(dstPath); @@ -871,7 +877,7 @@ void LocalStore::exportPath(const Path & path, bool sign, Path tmpDir = createTempDir(); AutoDelete delTmp(tmpDir); Path hashFile = tmpDir + "/hash"; - writeStringToFile(hashFile, printHash(hash)); + writeFile(hashFile, printHash(hash)); Path secretKey = nixConfDir + "/signing-key.sec"; checkSecrecy(secretKey); @@ -947,7 +953,7 @@ Path LocalStore::importPath(bool requireSignature, Source & source) if (requireSignature) { Path sigFile = tmpDir + "/sig"; - writeStringToFile(sigFile, signature); + writeFile(sigFile, signature); Strings args; args.push_back("rsautl"); diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index ef585fdaa..31f8d9109 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -158,12 +158,17 @@ private: /* Store paths for which the referrers file must be purged. */ PathSet delayedUpdates; + /* Whether to do an fsync() after writing Nix metadata. */ + bool doFsync; + int getSchema(); void registerValidPath(const ValidPathInfo & info, bool ignoreValidity = false); ValidPathInfo queryPathInfo(const Path & path, bool ignoreErrors = false); + void appendReferrer(const Path & from, const Path & to, bool lock); + void rewriteReferrers(const Path & path, bool purge, PathSet referrers); void flushDelayedUpdates(); diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 1b86e88d7..711a969e4 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include "util.hh" @@ -220,12 +221,13 @@ string readFile(const Path & path) } -void writeFile(const Path & path, const string & s) +void writeFile(const Path & path, const string & s, bool doFsync) { AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666); if (fd == -1) throw SysError(format("opening file `%1%'") % path); writeFull(fd, (unsigned char *) s.c_str(), s.size()); + if (doFsync) fdatasync(fd); } @@ -413,16 +415,6 @@ Paths createDirs(const Path & path) } -void writeStringToFile(const Path & path, const string & s) -{ - AutoCloseFD fd(open(path.c_str(), - O_CREAT | O_EXCL | O_WRONLY, 0666)); - if (fd == -1) - throw SysError(format("creating file `%1%'") % path); - writeFull(fd, (unsigned char *) s.c_str(), s.size()); -} - - LogType logType = ltPretty; Verbosity verbosity = lvlInfo; diff --git a/src/libutil/util.hh b/src/libutil/util.hh index a5d0445c1..837382433 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -62,7 +62,7 @@ string readFile(int fd); string readFile(const Path & path); /* Write a string to a file. */ -void writeFile(const Path & path, const string & s); +void writeFile(const Path & path, const string & s, bool doFsync = false); /* Read a line from a file descriptor. */ string readLine(int fd); @@ -93,10 +93,6 @@ Path createTempDir(const Path & tmpRoot = "", const Path & prefix = "nix", list of created directories, in order of creation. */ Paths createDirs(const Path & path); -/* Create a file and write the given text to it. The file is written - in binary mode (i.e., no end-of-line conversions). The path should - not already exist. */ -void writeStringToFile(const Path & path, const string & s); template T singleton(const A & a)