From 64fd29855a8ae49cacdaff424679821b4fd3bf57 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 14 Oct 2010 15:55:51 +0000 Subject: [PATCH] * Wrap deleteFromStore() in a transaction. Otherwise there might be a race with other processes that add new referrers to a path, resulting in the garbage collector crashing with "foreign key constraint failed". (Nix/4) * Make --gc --print-dead etc. interruptible. --- src/libstore/gc.cc | 8 +++++--- src/libstore/local-store.cc | 13 ++++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index 7d58cd50a..b8395bfc4 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -421,7 +421,7 @@ struct LocalStore::GCState }; -static bool doDelete(GCOptions::GCAction action) +static bool shouldDelete(GCOptions::GCAction action) { return action == GCOptions::gcDeleteDead || action == GCOptions::gcDeleteSpecific; @@ -438,6 +438,8 @@ bool LocalStore::isActiveTempFile(const GCState & state, bool LocalStore::tryToDelete(GCState & state, const Path & path) { + checkInterrupt(); + if (!pathExists(path)) return true; if (state.deleted.find(path) != state.deleted.end()) return true; if (state.live.find(path) != state.live.end()) return false; @@ -516,7 +518,7 @@ bool LocalStore::tryToDelete(GCState & state, const Path & path) } /* The path is garbage, so delete it. */ - if (doDelete(state.options.action)) { + if (shouldDelete(state.options.action)) { printMsg(lvlInfo, format("deleting `%1%'") % path); unsigned long long bytesFreed, blocksFreed; @@ -625,7 +627,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) vector entries_(entries.begin(), entries.end()); random_shuffle(entries_.begin(), entries_.end()); - if (doDelete(state.options.action)) + if (shouldDelete(state.options.action)) printMsg(lvlError, format("deleting garbage...")); else printMsg(lvlError, format("determining live/dead paths...")); diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index c0c1461b4..c0c75e34d 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -298,11 +298,10 @@ void LocalStore::openDB(bool create) if (sqlite3_exec(db, ("pragma synchronous = " + syncMode + ";").c_str(), 0, 0, 0) != SQLITE_OK) throw SQLiteError(db, "setting synchronous mode"); - /* Set the SQLite journal mode. The default is write-ahead - logging since it's the fastest and supports more concurrency. - The downside is that it doesn't work over NFS, so allow - truncate mode alternatively. */ - string mode = queryBoolSetting("use-sqlite-wal", true) ? "wal" : "truncate"; + /* Set the SQLite journal mode. WAL mode is fastest, but doesn't + seem entirely stable at the moment (Oct. 2010). Thus, use + truncate mode by default. */ + string mode = queryBoolSetting("use-sqlite-wal", false) ? "wal" : "truncate"; string prevMode; { SQLiteStmt stmt; @@ -1220,6 +1219,8 @@ void LocalStore::deleteFromStore(const Path & path, unsigned long long & bytesFr assertStorePath(path); + SQLiteTxn txn(db); + if (isValidPath(path)) { PathSet referrers; queryReferrers(path, referrers); referrers.erase(path); /* ignore self-references */ @@ -1230,6 +1231,8 @@ void LocalStore::deleteFromStore(const Path & path, unsigned long long & bytesFr } deletePathWrapped(path, bytesFreed, blocksFreed); + + txn.commit(); }