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)