From e492c64c8e2d905dd97dc9e9870f0eb18f4a8313 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 22 Jul 2025 12:18:52 +0200 Subject: [PATCH] SQLite: fsync db.sqlite-shm before opening the database This is a workaround for https://github.com/NixOS/nix/issues/13515 (opening the SQLite DB randomly taking a couple of seconds on ZFS). (cherry picked from commit a7fceb5eec404eabf461d4f1281bf4163c5d8ad0) --- src/libstore/sqlite.cc | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) 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.