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.
This commit is contained in:
		
							parent
							
								
									2001895f3d
								
							
						
					
					
						commit
						a3f205b249
					
				
					 3 changed files with 91 additions and 6 deletions
				
			
		|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue