diff --git a/src/libstore/sqlite.cc b/src/libstore/sqlite.cc index 56a69470a..5f0b3ce51 100644 --- a/src/libstore/sqlite.cc +++ b/src/libstore/sqlite.cc @@ -4,6 +4,10 @@ #include "nix/util/url.hh" #include "nix/util/signals.hh" +#ifdef __linux__ +# include +#endif + #include #include @@ -60,6 +64,28 @@ static void traceSQL(void * x, const char * sql) SQLite::SQLite(const std::filesystem::path & path, SQLiteOpenMode mode) { + // Work around a ZFS issue where SQLite's truncate() call on + // db.sqlite-shm can randomly take up to a few seconds. See + // https://github.com/openzfs/zfs/issues/14290#issuecomment-3074672917. + // Remove this workaround when a fix is widely installed, perhaps 2027? Candidate: + // https://github.com/search?q=repo%3Aopenzfs%2Fzfs+%22Linux%3A+zfs_putpage%3A+complete+async+page+writeback+immediately%22&type=commits +#ifdef __linux__ + try { + auto shmFile = path; + shmFile += "-shm"; + AutoCloseFD fd = open(shmFile.string().c_str(), O_RDWR | O_CLOEXEC); + if (fd) { + struct statfs fs; + if (fstatfs(fd.get(), &fs)) + throw SysError("statfs() on '%s'", shmFile); + if (fs.f_type == /* ZFS_SUPER_MAGIC */ 801189825 && fdatasync(fd.get()) != 0) + throw SysError("fsync() on '%s'", shmFile); + } + } catch (...) { + throw; + } +#endif + // useSQLiteWAL also indicates what virtual file system we need. Using // `unix-dotfile` is needed on NFS file systems and on Windows' Subsystem // for Linux (WSL) where useSQLiteWAL should be false by default.