aboutsummaryrefslogtreecommitdiff
path: root/src/libstore
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2012-10-03 10:38:09 -0400
committerEelco Dolstra <eelco.dolstra@logicblox.com>2012-10-03 10:38:09 -0400
commita3f205b24954c7f0983a937b0b9b3d64c22a2fa7 (patch)
tree245d2daa9ac4816507105bffb588fac38ad31fc3 /src/libstore
parent2001895f3d2668549feb60a182aa624a7b6292eb (diff)
When repairing a derivation, check and repair the entire output closure
If we find a corrupted path in the output closure, we rebuild the derivation that produced that particular path.
Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/build.cc68
-rw-r--r--src/libstore/local-store.cc24
-rw-r--r--src/libstore/local-store.hh5
3 files changed, 91 insertions, 6 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index ddcd45a61..6c40b6686 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -853,6 +853,7 @@ private:
void init();
void haveDerivation();
void outputsSubstituted();
+ void closureRepaired();
void inputsRealised();
void tryToBuild();
void buildDone();
@@ -896,6 +897,8 @@ private:
void killChild();
Path addHashRewrite(const Path & path);
+
+ void repairClosure();
};
@@ -1046,7 +1049,7 @@ void DerivationGoal::outputsSubstituted()
nrFailed = nrNoSubstituters = 0;
if (checkPathValidity(false, repair).size() == 0) {
- amDone(ecSuccess);
+ if (repair) repairClosure(); else amDone(ecSuccess);
return;
}
@@ -1055,7 +1058,7 @@ void DerivationGoal::outputsSubstituted()
/* The inputs must be built before we can build this goal. */
foreach (DerivationInputs::iterator, i, drv.inputDrvs)
- addWaitee(worker.makeDerivationGoal(i->first));
+ addWaitee(worker.makeDerivationGoal(i->first, repair));
foreach (PathSet::iterator, i, drv.inputSrcs)
addWaitee(worker.makeSubstitutionGoal(*i));
@@ -1067,6 +1070,63 @@ void DerivationGoal::outputsSubstituted()
}
+void DerivationGoal::repairClosure()
+{
+ /* If we're repairing, we now know that our own outputs are valid.
+ Now check whether the other paths in the outputs closure are
+ good. If not, then start derivation goals for the derivations
+ that produced those outputs. */
+
+ /* Get the output closure. */
+ PathSet outputClosure;
+ foreach (DerivationOutputs::iterator, i, drv.outputs)
+ computeFSClosure(worker.store, i->second.path, outputClosure);
+
+ /* Filter out our own outputs (which we have already checked). */
+ foreach (DerivationOutputs::iterator, i, drv.outputs)
+ outputClosure.erase(i->second.path);
+
+ /* Get all dependencies of this derivation so that we know which
+ derivation is responsible for which path in the output
+ closure. */
+ PathSet inputClosure;
+ computeFSClosure(worker.store, drvPath, inputClosure);
+ std::map<Path, Path> outputsToDrv;
+ foreach (PathSet::iterator, i, inputClosure)
+ if (isDerivation(*i)) {
+ Derivation drv = derivationFromPath(worker.store, *i);
+ foreach (DerivationOutputs::iterator, j, drv.outputs)
+ outputsToDrv[j->second.path] = *i;
+ }
+
+ /* Check each path (slow!). */
+ PathSet broken;
+ foreach (PathSet::iterator, i, outputClosure) {
+ if (worker.store.pathContentsGood(*i)) continue;
+ printMsg(lvlError, format("found corrupted or missing path `%1%' in the output closure of `%2%'") % *i % drvPath);
+ Path drvPath2 = outputsToDrv[*i];
+ if (drvPath2 == "") throw Error(format("don't know how to repair corrupted or missing path `%1%'") % *i);
+ addWaitee(worker.makeDerivationGoal(drvPath2, true));
+ }
+
+ if (waitees.empty()) {
+ amDone(ecSuccess);
+ return;
+ }
+
+ state = &DerivationGoal::closureRepaired;
+}
+
+
+void DerivationGoal::closureRepaired()
+{
+ trace("closure repaired");
+ if (nrFailed > 0)
+ throw Error(format("some paths in the output closure of derivation `%1%' could not be repaired") % drvPath);
+ amDone(ecSuccess);
+}
+
+
void DerivationGoal::inputsRealised()
{
trace("all inputs realised");
@@ -2197,6 +2257,8 @@ void DerivationGoal::computeClosure()
}
worker.store.optimisePath(path); // FIXME: combine with scanForReferences()
+
+ worker.store.markContentsGood(path);
}
/* Register each output path as valid, and register the sets of
@@ -2729,6 +2791,8 @@ void SubstitutionGoal::finished()
outputLock->setDeletion(true);
+ worker.store.markContentsGood(storePath);
+
printMsg(lvlChatty,
format("substitution of path `%1%' succeeded") % storePath);
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index a4ad97331..b55ab4284 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -1673,11 +1673,27 @@ void LocalStore::verifyPath(const Path & path, const PathSet & store,
bool LocalStore::pathContentsGood(const Path & path)
{
+ std::map<Path, bool>::iterator i = pathContentsGoodCache.find(path);
+ if (i != pathContentsGoodCache.end()) return i->second;
+ printMsg(lvlInfo, format("checking path `%1%'...") % path);
ValidPathInfo info = queryPathInfo(path);
- if (!pathExists(path)) return false;
- HashResult current = hashPath(info.hash.type, path);
- Hash nullHash(htSHA256);
- return info.hash == nullHash || info.hash == current.first;
+ bool res;
+ if (!pathExists(path))
+ res = false;
+ else {
+ HashResult current = hashPath(info.hash.type, path);
+ Hash nullHash(htSHA256);
+ res = info.hash == nullHash || info.hash == current.first;
+ }
+ pathContentsGoodCache[path] = res;
+ if (!res) printMsg(lvlError, format("path `%1%' is corrupted or missing!") % path);
+ return res;
+}
+
+
+void LocalStore::markContentsGood(const Path & path)
+{
+ pathContentsGoodCache[path] = true;
}
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 00356bf9d..b2f06d811 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -206,6 +206,8 @@ public:
contents. */
bool pathContentsGood(const Path & path);
+ void markContentsGood(const Path & path);
+
private:
Path schemaPath;
@@ -233,6 +235,9 @@ private:
SQLiteStmt stmtQueryDerivationOutputs;
SQLiteStmt stmtQueryPathFromHashPart;
+ /* Cache for pathContentsGood(). */
+ std::map<Path, bool> pathContentsGoodCache;
+
int getSchema();
void openDB(bool create);