about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2007-01-14T17·28+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2007-01-14T17·28+0000
commit63f3ce6d9a26cb46a2f066dd9c5f2af25b3610df (patch)
tree1458f08f74066952904f0bdcec02c548d1f3fbba /src
parent8f67b3588603483402440538d7dc326451bbe60d (diff)
* `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.

Diffstat (limited to 'src')
-rw-r--r--src/libstore/local-store.cc98
1 files changed, 56 insertions, 42 deletions
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index b679ffb4fa7c..34fe33461f20 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 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 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);
-                }
+            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);
             }
-            if (referrers != newReferrers)
-                nixDB.setStrings(txn, dbReferrers, *i,
-                    Paths(newReferrers.begin(), newReferrers.end()));
         }
+        
     }
-#endif    
 
+    
     txn.commit();
 }