From 63f3ce6d9a26cb46a2f066dd9c5f2af25b3610df Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Sun, 14 Jan 2007 17:28:30 +0000 Subject: [PATCH] * `nix-store --verify': revive checking the referrers table. This is important to get garbage collection to work if there is any inconsistency in the database (because the referrer table is used to determine whether it is safe to delete a path). * `nix-store --verify': show some progress. --- src/libstore/local-store.cc | 106 ++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 46 deletions(-) diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index b679ffb4f..34fe33461 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -722,6 +722,9 @@ void verifyStore(bool checkContents) { Transaction txn(nixDB); + + printMsg(lvlInfo, "checking path existence"); + Paths paths; PathSet validPaths; nixDB.enumTable(txn, dbValidPaths, paths); @@ -748,9 +751,12 @@ void verifyStore(bool checkContents) } } - /* "Usable" paths are those that are valid or have a + + printMsg(lvlInfo, "checking path realisability"); + + /* "Realisable" paths are those that are valid or have a substitute. */ - PathSet usablePaths(validPaths); + PathSet realisablePaths(validPaths); /* Check that the values of the substitute mappings are valid paths. */ @@ -759,47 +765,52 @@ void verifyStore(bool checkContents) for (Paths::iterator i = subKeys.begin(); i != subKeys.end(); ++i) { Substitutes subs = readSubstitutes(txn, *i); if (!isStorePath(*i)) { - printMsg(lvlError, format("found substitutes for non-store path `%1%'") % *i); + printMsg(lvlError, format("removing substitutes for non-store path `%1%'") % *i); nixDB.delPair(txn, dbSubstitutes, *i); } else if (subs.size() == 0) nixDB.delPair(txn, dbSubstitutes, *i); else - usablePaths.insert(*i); + realisablePaths.insert(*i); } + - /* Check the cleanup invariant: only usable paths can have + /* Check the cleanup invariant: only realisable paths can have `references', `referrers', or `derivers' entries. */ + /* Check the `derivers' table. */ + printMsg(lvlInfo, "checking the derivers table"); Paths deriversKeys; nixDB.enumTable(txn, dbDerivers, deriversKeys); for (Paths::iterator i = deriversKeys.begin(); i != deriversKeys.end(); ++i) { - if (usablePaths.find(*i) == usablePaths.end()) { - printMsg(lvlError, format("found deriver entry for unusable path `%1%'") + if (realisablePaths.find(*i) == realisablePaths.end()) { + printMsg(lvlError, format("removing deriver entry for unrealisable path `%1%'") % *i); nixDB.delPair(txn, dbDerivers, *i); } else { Path deriver = queryDeriver(txn, *i); if (!isStorePath(deriver)) { - printMsg(lvlError, format("found corrupt deriver `%1%' for `%2%'") + printMsg(lvlError, format("removing corrupt deriver `%1%' for `%2%'") % deriver % *i); nixDB.delPair(txn, dbDerivers, *i); } } } + /* Check the `references' table. */ + printMsg(lvlInfo, "checking the references table"); Paths referencesKeys; nixDB.enumTable(txn, dbReferences, referencesKeys); for (Paths::iterator i = referencesKeys.begin(); i != referencesKeys.end(); ++i) { - if (usablePaths.find(*i) == usablePaths.end()) { - printMsg(lvlError, format("found references entry for unusable path `%1%'") + if (realisablePaths.find(*i) == realisablePaths.end()) { + printMsg(lvlError, format("removing references entry for unrealisable path `%1%'") % *i); setReferences(txn, *i, PathSet()); } @@ -812,7 +823,7 @@ void verifyStore(bool checkContents) { string dummy; if (!nixDB.queryString(txn, dbReferrers, addPrefix(*j, *i), dummy)) { - printMsg(lvlError, format("missing referrer mapping from `%1%' to `%2%'") + printMsg(lvlError, format("adding missing referrer mapping from `%1%' to `%2%'") % *j % *i); nixDB.setString(txn, dbReferrers, addPrefix(*j, *i), ""); } @@ -824,45 +835,48 @@ void verifyStore(bool checkContents) } } -#if 0 // !!! /* Check the `referrers' table. */ - Paths referrersKeys; - nixDB.enumTable(txn, dbReferrers, referrersKeys); - for (Paths::iterator i = referrersKeys.begin(); - i != referrersKeys.end(); ++i) - { - if (usablePaths.find(*i) == usablePaths.end()) { - printMsg(lvlError, format("found referrers entry for unusable path `%1%'") - % *i); + printMsg(lvlInfo, "checking the referrers table"); + Strings referrers; + nixDB.enumTable(txn, dbReferrers, referrers); + for (Strings::iterator i = referrers.begin(); i != referrers.end(); ++i) { + + /* Decode the entry (it's a tuple of paths). */ + string::size_type nul = i->find((char) 0); + if (nul == string::npos) { + printMsg(lvlError, format("removing bad referrer table entry `%1%'") % *i); + nixDB.delPair(txn, dbReferrers, *i); + continue; + } + Path to(*i, 0, nul); + Path from(*i, nul + 1); + + if (realisablePaths.find(to) == realisablePaths.end()) { + printMsg(lvlError, format("removing referrer entry from `%1%' to unrealisable `%2%'") + % from % to); nixDB.delPair(txn, dbReferrers, *i); } - else { - PathSet referrers, newReferrers; - queryReferrers(txn, *i, referrers); - for (PathSet::iterator j = referrers.begin(); - j != referrers.end(); ++j) - { - Paths references; - if (usablePaths.find(*j) == usablePaths.end()) { - printMsg(lvlError, format("referrer mapping from `%1%' to unusable `%2%'") - % *i % *j); - } else { - nixDB.queryStrings(txn, dbReferences, *j, references); - if (find(references.begin(), references.end(), *i) == references.end()) { - printMsg(lvlError, format("missing reference mapping from `%1%' to `%2%'") - % *j % *i); - /* !!! repair by inserting *i into references */ - } - else newReferrers.insert(*j); - } - } - if (referrers != newReferrers) - nixDB.setStrings(txn, dbReferrers, *i, - Paths(newReferrers.begin(), newReferrers.end())); - } - } -#endif + else if (realisablePaths.find(from) == realisablePaths.end()) { + printMsg(lvlError, format("removing referrer entry from unrealisable `%1%' to `%2%'") + % from % to); + nixDB.delPair(txn, dbReferrers, *i); + } + + else { + PathSet references; + queryReferences(txn, from, references); + if (find(references.begin(), references.end(), to) == references.end()) { + printMsg(lvlError, format("adding missing referrer mapping from `%1%' to `%2%'") + % from % to); + references.insert(to); + setReferences(txn, from, references); + } + } + + } + + txn.commit(); }