diff --git a/src/db.cc b/src/db.cc index 64f9813a40..a8741342ce 100644 --- a/src/db.cc +++ b/src/db.cc @@ -157,7 +157,7 @@ void delDB(const string & filename, const string & dbname, void enumDB(const string & filename, const string & dbname, - DBPairs & contents) + Strings & keys) { try { @@ -168,11 +168,9 @@ void enumDB(const string & filename, const string & dbname, DbcClose cursorCloser(cursor); Dbt kt, dt; - while (cursor->get(&kt, &dt, DB_NEXT) != DB_NOTFOUND) { - string key((char *) kt.get_data(), kt.get_size()); - string data((char *) dt.get_data(), dt.get_size()); - contents.push_back(DBPair(key, data)); - } + while (cursor->get(&kt, &dt, DB_NEXT) != DB_NOTFOUND) + keys.push_back( + string((char *) kt.get_data(), kt.get_size())); } catch (DbException e) { rethrow(e); } } diff --git a/src/db.hh b/src/db.hh index aee6ce9bff..6f13eb30c8 100644 --- a/src/db.hh +++ b/src/db.hh @@ -8,9 +8,6 @@ using namespace std; -typedef pair DBPair; -typedef list DBPairs; - void createDB(const string & filename, const string & dbname); bool queryDB(const string & filename, const string & dbname, @@ -29,6 +26,6 @@ void delDB(const string & filename, const string & dbname, const string & key); void enumDB(const string & filename, const string & dbname, - DBPairs & contents); + Strings & keys); #endif /* !__DB_H */ diff --git a/src/fstate.hh b/src/fstate.hh index 2ae876b7cd..0d89e7e360 100644 --- a/src/fstate.hh +++ b/src/fstate.hh @@ -1,8 +1,6 @@ #ifndef __FSTATE_H #define __FSTATE_H -#include - extern "C" { #include } @@ -53,8 +51,6 @@ using namespace std; typedef ATerm FState; typedef ATerm Content; -typedef set StringSet; - typedef list FSIds; diff --git a/src/nix.cc b/src/nix.cc index fe762798e7..5785cd6b4c 100644 --- a/src/nix.cc +++ b/src/nix.cc @@ -283,6 +283,13 @@ static void opInit(Strings opFlags, Strings opArgs) } +/* Verify the consistency of the Nix environment. */ +static void opVerify(Strings opFlags, Strings opArgs) +{ + verifyStore(); +} + + /* Scan the arguments; find the operation, set global flags, put all other flags in a list, and put all other arguments in another list. */ @@ -316,6 +323,8 @@ void run(Strings args) op = opRestore; else if (arg == "--init") op = opInit; + else if (arg == "--verify") + op = opVerify; else if (arg[0] == '-') opFlags.push_back(arg); else diff --git a/src/store.cc b/src/store.cc index d75458d8a5..864213692e 100644 --- a/src/store.cc +++ b/src/store.cc @@ -260,3 +260,124 @@ void deleteFromStore(const string & path) deletePath(path); } + + +void verifyStore() +{ + Strings paths; + enumDB(nixDB, dbPath2Id, paths); + + for (Strings::iterator i = paths.begin(); + i != paths.end(); i++) + { + bool erase = true; + string path = *i; + + if (!pathExists(path)) { + debug(format("path `%1%' disappeared") % path); + } + + else { + string id; + if (!queryDB(nixDB, dbPath2Id, path, id)) abort(); + + Strings idPaths; + queryListDB(nixDB, dbId2Paths, id, idPaths); + + bool found = false; + for (Strings::iterator j = idPaths.begin(); + j != idPaths.end(); j++) + if (path == *j) { + found = true; + break; + } + + if (found) + erase = false; + else + /* !!! perhaps we should add path to idPaths? */ + debug(format("reverse mapping for path `%1%' missing") % path); + } + + if (erase) delDB(nixDB, dbPath2Id, path); + } + + Strings ids; + enumDB(nixDB, dbId2Paths, ids); + + for (Strings::iterator i = ids.begin(); + i != ids.end(); i++) + { + FSId id = parseHash(*i); + + Strings idPaths; + queryListDB(nixDB, dbId2Paths, id, idPaths); + + for (Strings::iterator j = idPaths.begin(); + j != idPaths.end(); ) + { + string id2; + if (!queryDB(nixDB, dbPath2Id, *j, id2) || + id != parseHash(id2)) { + debug(format("erasing path `%1%' from mapping for id %2%") + % *j % (string) id); + j = idPaths.erase(j); + } else j++; + } + + setListDB(nixDB, dbId2Paths, id, idPaths); + } + + + Strings subs; + enumDB(nixDB, dbSubstitutes, subs); + + for (Strings::iterator i = subs.begin(); + i != subs.end(); i++) + { + FSId srcId = parseHash(*i); + + Strings subIds; + queryListDB(nixDB, dbSubstitutes, srcId, subIds); + + for (Strings::iterator j = subIds.begin(); + j != subIds.end(); ) + { + FSId subId = parseHash(*j); + + Strings subPaths; + queryListDB(nixDB, dbId2Paths, subId, subPaths); + if (subPaths.size() == 0) { + debug(format("erasing substitute %1% for %2%") + % (string) subId % (string) srcId); + j = subIds.erase(j); + } else j++; + } + + setListDB(nixDB, dbSubstitutes, srcId, subIds); + } + + Strings sucs; + enumDB(nixDB, dbSuccessors, sucs); + + for (Strings::iterator i = sucs.begin(); + i != sucs.end(); i++) + { + FSId id1 = parseHash(*i); + + string id2; + if (!queryDB(nixDB, dbSuccessors, id1, id2)) abort(); + + Strings id2Paths; + queryListDB(nixDB, dbId2Paths, id2, id2Paths); + if (id2Paths.size() == 0) { + Strings id2Subs; + queryListDB(nixDB, dbSubstitutes, id2, id2Subs); + if (id2Subs.size() == 0) { + debug(format("successor %1% for %2% missing") + % id2 % (string) id1); + delDB(nixDB, dbSuccessors, (string) id1); + } + } + } +} diff --git a/src/store.hh b/src/store.hh index 7dd0f72e6f..78d5529e77 100644 --- a/src/store.hh +++ b/src/store.hh @@ -35,5 +35,7 @@ void addToStore(string srcPath, string & dstPath, FSId & id, /* Delete a value from the nixStore directory. */ void deleteFromStore(const string & path); +void verifyStore(); + #endif /* !__STORE_H */ diff --git a/src/util.hh b/src/util.hh index 684bafbb55..611612a589 100644 --- a/src/util.hh +++ b/src/util.hh @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -38,6 +39,7 @@ public: typedef list Strings; +typedef set StringSet; /* The canonical system name, as returned by config.guess. */