From 8062d3af30b27eb4d617c14856d4f3a173f8012e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 6 Dec 2010 15:29:38 +0000 Subject: [PATCH] * `nix-store --verify --check-contents': don't hold the global GC lock while checking the contents, since this operation can take a very long time to finish. Also, fill in missing narSize fields in the DB while doing this. --- src/libstore/local-store.cc | 55 ++++++++++++++++++++++++++++++------- src/libstore/local-store.hh | 3 ++ 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 88548706b8..3782d1b169 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -353,6 +353,8 @@ void LocalStore::openDB(bool create) /* Prepare SQL statements. */ stmtRegisterValidPath.create(db, "insert into ValidPaths (path, hash, registrationTime, deriver, narSize) values (?, ?, ?, ?, ?);"); + stmtUpdatePathInfo.create(db, + "update ValidPaths set narSize = ? where path = ?;"); stmtAddReference.create(db, "insert or replace into Refs (referrer, reference) values (?, ?);"); stmtQueryPathInfo.create(db, @@ -645,6 +647,21 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path) } +/* Update path info in the database. Currently only updated the + narSize field. */ +void LocalStore::updatePathInfo(const ValidPathInfo & info) +{ + SQLiteStmtUse use(stmtUpdatePathInfo); + if (info.narSize != 0) + stmtUpdatePathInfo.bind64(info.narSize); + else + stmtUpdatePathInfo.bind(); // null + stmtUpdatePathInfo.bind(info.path); + if (sqlite3_step(stmtUpdatePathInfo) != SQLITE_DONE) + throwSQLiteError(db, format("updating info of path `%1%' in database") % info.path); +} + + unsigned long long LocalStore::queryValidPathId(const Path & path) { SQLiteStmtUse use(stmtQueryPathInfo); @@ -1305,23 +1322,41 @@ void LocalStore::verifyStore(bool checkContents) foreach (PathSet::iterator, i, validPaths2) verifyPath(*i, store, done, validPaths); + /* Release the GC lock so that checking content hashes (which can + take ages) doesn't block the GC or builds. */ + fdGCLock.close(); + /* Optionally, check the content hashes (slow). */ if (checkContents) { printMsg(lvlInfo, "checking hashes..."); foreach (PathSet::iterator, i, validPaths) { - ValidPathInfo info = queryPathInfo(*i); + try { + ValidPathInfo info = queryPathInfo(*i); - /* Check the content hash (optionally - slow). */ - printMsg(lvlTalkative, format("checking contents of `%1%'") % *i); - Hash current = hashPath(info.hash.type, *i).first; - if (current != info.hash) { - printMsg(lvlError, format("path `%1%' was modified! " - "expected hash `%2%', got `%3%'") - % *i % printHash(info.hash) % printHash(current)); - } + /* Check the content hash (optionally - slow). */ + printMsg(lvlTalkative, format("checking contents of `%1%'") % *i); + HashResult current = hashPath(info.hash.type, *i); + + if (current.first != info.hash) { + printMsg(lvlError, format("path `%1%' was modified! " + "expected hash `%2%', got `%3%'") + % *i % printHash(info.hash) % printHash(current.first)); + } else { + /* Fill in missing narSize fields (from old stores). */ + if (info.narSize == 0) { + printMsg(lvlError, format("updating size field on `%1%' to %2%") % *i % current.second); + info.narSize = current.second; + updatePathInfo(info); + } + } - /* !!! Check info.narSize */ + } catch (Error & e) { + /* It's possible that the path got GC'ed, so ignore + errors on invalid paths. */ + if (isValidPath(*i)) throw; + printMsg(lvlError, format("warning: %1%") % e.msg()); + } } } } diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index 4076e59574..f270fb7239 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -203,6 +203,7 @@ private: /* Some precompiled SQLite statements. */ SQLiteStmt stmtRegisterValidPath; + SQLiteStmt stmtUpdatePathInfo; SQLiteStmt stmtAddReference; SQLiteStmt stmtQueryPathInfo; SQLiteStmt stmtQueryReferences; @@ -235,6 +236,8 @@ private: void verifyPath(const Path & path, const PathSet & store, PathSet & done, PathSet & validPaths); + void updatePathInfo(const ValidPathInfo & info); + void upgradeStore6(); PathSet queryValidPathsOld(); ValidPathInfo queryPathInfoOld(const Path & path);