about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libstore/build.cc4
-rw-r--r--src/libstore/gc.cc2
-rw-r--r--src/libstore/misc.cc4
-rw-r--r--src/libstore/store.cc112
-rw-r--r--src/libstore/store.hh6
-rw-r--r--src/nix-store/main.cc4
6 files changed, 106 insertions, 26 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 64443d41a785..3785c7da7924 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -806,7 +806,7 @@ DerivationGoal::HookReply DerivationGoal::tryBuildHook()
         {
             s += *i;
             PathSet references;
-            queryReferences(*i, references);
+            queryReferences(noTxn, *i, references);
             for (PathSet::iterator j = references.begin();
                  j != references.end(); ++j)
             {
@@ -1326,7 +1326,7 @@ void SubstitutionGoal::init()
 
     /* To maintain the closure invairant, we first have to realise the
        paths referenced by this one. */
-    queryReferences(storePath, references);
+    queryReferences(noTxn, storePath, references);
 
     for (PathSet::iterator i = references.begin();
          i != references.end(); ++i)
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 020712368f52..4d63d46ea1f5 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -279,7 +279,7 @@ static void dfsVisit(const PathSet & paths, const Path & path,
     
     PathSet references;
     if (isValidPath(path))
-        queryReferences(path, references);
+        queryReferences(noTxn, path, references);
     
     for (PathSet::iterator i = references.begin();
          i != references.end(); ++i)
diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc
index b20879178805..5f20ee277513 100644
--- a/src/libstore/misc.cc
+++ b/src/libstore/misc.cc
@@ -19,9 +19,9 @@ void computeFSClosure(const Path & storePath,
 
     PathSet references;
     if (flipDirection)
-        queryReferers(storePath, references);
+        queryReferers(noTxn, storePath, references);
     else
-        queryReferences(storePath, references);
+        queryReferences(noTxn, storePath, references);
 
     for (PathSet::iterator i = references.begin();
          i != references.end(); ++i)
diff --git a/src/libstore/store.cc b/src/libstore/store.cc
index 693a388b3e1e..0c7702f973bd 100644
--- a/src/libstore/store.cc
+++ b/src/libstore/store.cc
@@ -325,21 +325,23 @@ void setReferences(const Transaction & txn, const Path & storePath,
 }
 
 
-void queryReferences(const Path & storePath, PathSet & references)
+void queryReferences(const Transaction & txn,
+    const Path & storePath, PathSet & references)
 {
     Paths references2;
-    if (!isRealisablePath(noTxn, storePath))
+    if (!isRealisablePath(txn, storePath))
         throw Error(format("path `%1%' is not valid") % storePath);
-    nixDB.queryStrings(noTxn, dbReferences, storePath, references2);
+    nixDB.queryStrings(txn, dbReferences, storePath, references2);
     references.insert(references2.begin(), references2.end());
 }
 
 
-void queryReferers(const Path & storePath, PathSet & referers)
+void queryReferers(const Transaction & txn,
+    const Path & storePath, PathSet & referers)
 {
-    if (!isRealisablePath(noTxn, storePath))
+    if (!isRealisablePath(txn, storePath))
         throw Error(format("path `%1%' is not valid") % storePath);
-    PathSet referers2 = getReferers(noTxn, storePath);
+    PathSet referers2 = getReferers(txn, storePath);
     referers.insert(referers2.begin(), referers2.end());
 }
 
@@ -358,7 +360,7 @@ void setDeriver(const Transaction & txn, const Path & storePath,
 
 Path queryDeriver(const Transaction & txn, const Path & storePath)
 {
-    if (!isRealisablePath(noTxn, storePath))
+    if (!isRealisablePath(txn, storePath))
         throw Error(format("path `%1%' is not valid") % storePath);
     Path deriver;
     if (nixDB.queryString(txn, dbDerivers, storePath, deriver))
@@ -641,13 +643,8 @@ void verifyStore()
             validPaths.insert(path);
     }
 
-    /* !!! the code below does not allow transitive substitutes.
-       I.e., if B is a substitute of A, then B must be a valid path.
-       B cannot itself be invalid but have a substitute. */
-
-    /* "Usable" paths are those that are valid or have a substitute.
-       These are the paths that are allowed to appear in the
-       right-hand side of a sute mapping. */
+    /* "Usable" paths are those that are valid or have a
+       substitute. */
     PathSet usablePaths(validPaths);
 
     /* Check that the values of the substitute mappings are valid
@@ -656,10 +653,91 @@ void verifyStore()
     nixDB.enumTable(txn, dbSubstitutes, subKeys);
     for (Paths::iterator i = subKeys.begin(); i != subKeys.end(); ++i) {
         Substitutes subs = readSubstitutes(txn, *i);
-	if (subs.size() > 0)
-	    usablePaths.insert(*i);
-        else
+        if (!isStorePath(*i)) {
+            printMsg(lvlError, format("found 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);
+    }
+
+    /* Check the cleanup invariant: only usable paths can have
+       `references', `referers', or `derivers' entries. */
+
+    /* Check 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%'")
+                % *i);
+            nixDB.delPair(txn, dbDerivers, *i);
+        }
+        else {
+            Path deriver = queryDeriver(txn, *i);
+            if (!isStorePath(deriver)) {
+                printMsg(lvlError, format("found corrupt deriver `%1%' for `%2%'")
+                    % deriver % *i);
+                nixDB.delPair(txn, dbDerivers, *i);
+            }
+        }
+    }
+
+    /* Check 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%'")
+                % *i);
+            nixDB.delPair(txn, dbReferences, *i);
+        }
+        else {
+            PathSet references;
+            queryReferences(txn, *i, references);
+            for (PathSet::iterator j = references.begin();
+                 j != references.end(); ++j)
+            {
+                PathSet referers = getReferers(txn, *j);
+                if (referers.find(*i) == referers.end()) {
+                    printMsg(lvlError, format("missing referer mapping from `%1%' to `%2%'")
+                        % *j % *i);
+                }
+            }
+        }
+    }
+
+    /* Check the `referers' table. */
+    Paths referersKeys;
+    nixDB.enumTable(txn, dbReferers, referersKeys);
+    for (Paths::iterator i = referersKeys.begin();
+         i != referersKeys.end(); ++i)
+    {
+        if (usablePaths.find(*i) == usablePaths.end()) {
+            printMsg(lvlError, format("found referers entry for unusable path `%1%'")
+                % *i);
+            nixDB.delPair(txn, dbReferers, *i);
+        }
+        else {
+            PathSet referers;
+            queryReferers(txn, *i, referers);
+            for (PathSet::iterator j = referers.begin();
+                 j != referers.end(); ++j)
+            {
+                Paths references;
+                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);
+                }
+            }
+        }
     }
 
     txn.commit();
diff --git a/src/libstore/store.hh b/src/libstore/store.hh
index 1f2b630e106c..e981ade1009b 100644
--- a/src/libstore/store.hh
+++ b/src/libstore/store.hh
@@ -90,11 +90,13 @@ void setReferences(const Transaction & txn, const Path & storePath,
 
 /* Queries the set of outgoing FS references for a store path.  The
    result is not cleared. */
-void queryReferences(const Path & storePath, PathSet & references);
+void queryReferences(const Transaction & txn,
+    const Path & storePath, PathSet & references);
 
 /* Queries the set of incoming FS references for a store path.  The
    result is not cleared. */
-void queryReferers(const Path & storePath, PathSet & referers);
+void queryReferers(const Transaction & txn,
+    const Path & storePath, PathSet & referers);
 
 /* Sets the deriver of a store path.  Use with care! */
 void setDeriver(const Transaction & txn, const Path & storePath,
diff --git a/src/nix-store/main.cc b/src/nix-store/main.cc
index f9bd3323f447..a3c1b8fa782e 100644
--- a/src/nix-store/main.cc
+++ b/src/nix-store/main.cc
@@ -215,8 +215,8 @@ static void opQuery(Strings opFlags, Strings opArgs)
                 Path path = maybeUseOutput(*i, useOutput, forceRealise);
                 if (query == qRequisites)
                     storePathRequisites(path, includeOutputs, paths);
-                else if (query == qReferences) queryReferences(path, paths);
-                else if (query == qReferers) queryReferers(path,  paths);
+                else if (query == qReferences) queryReferences(noTxn, path, paths);
+                else if (query == qReferers) queryReferers(noTxn, path,  paths);
                 else if (query == qReferersClosure) computeFSClosure(path, paths, true);
             }
             printPathSet(paths);