about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/manual/conf-file.xml12
-rw-r--r--src/libstore/build.cc10
-rw-r--r--src/libstore/local-store.cc18
-rw-r--r--src/libstore/local-store.hh5
-rw-r--r--src/libutil/util.cc14
-rw-r--r--src/libutil/util.hh6
6 files changed, 37 insertions, 28 deletions
diff --git a/doc/manual/conf-file.xml b/doc/manual/conf-file.xml
index 66df3edd5f..2ee2680970 100644
--- a/doc/manual/conf-file.xml
+++ b/doc/manual/conf-file.xml
@@ -233,7 +233,17 @@ build-use-chroot = /dev /proc /bin</programlisting>
     <filename>configure</filename> at build time.</para></listitem>
 
   </varlistentry>
-  
+
+
+  <varlistentry><term><literal>fsync-metadata</literal></term>
+
+    <listitem><para>If set to <literal>true</literal>, changes to the
+    Nix store metadata (in <filename>/nix/var/nix/db</filename>) are
+    synchronously flushed to disk.  This improves robustness in case
+    of system crashes, but reduces performance.  The default is
+    <literal>false</literal>.</para></listitem>
+
+  </varlistentry>
     
 </variablelist>
 
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index d56ae4570d..77cffba25d 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 93ce8c047a..7c8db745cb 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 ef585fdaa8..31f8d91096 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 1b86e88d7f..711a969e4f 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -15,6 +15,7 @@
 #include <sys/wait.h>
 #include <sys/types.h>
 #include <fcntl.h>
+#include <unistd.h>
 
 #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 a5d0445c14..837382433a 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<class T, class A>
 T singleton(const A & a)