Don't require --fallback to recover from disappeared binary cache NARs

This commit is contained in:
Eelco Dolstra 2018-06-05 16:04:41 +02:00
parent 691b7582c7
commit 4ac4f675df
No known key found for this signature in database
GPG Key ID: 8170B4726D7198DE
4 changed files with 41 additions and 17 deletions

View File

@ -218,7 +218,11 @@ void BinaryCacheStore::narFromPath(const Path & storePath, Sink & sink)
auto info = queryPathInfo(storePath).cast<const NarInfo>();
auto source = sinkToSource([this, url{info->url}](Sink & sink) {
getFile(url, sink);
try {
getFile(url, sink);
} catch (NoSuchBinaryCacheFile & e) {
throw SubstituteGone(e.what());
}
});
stats.narRead++;

View File

@ -733,7 +733,7 @@ private:
/* Whether to retry substituting the outputs after building the
inputs. */
bool retrySubstitution = false;
bool retrySubstitution;
/* The derivation stored at drvPath. */
std::unique_ptr<BasicDerivation> drv;
@ -1123,6 +1123,8 @@ void DerivationGoal::haveDerivation()
{
trace("have derivation");
retrySubstitution = false;
for (auto & i : drv->outputs)
worker.store.addTempRoot(i.second.path);
@ -1161,7 +1163,7 @@ void DerivationGoal::outputsSubstituted()
/* If the substitutes form an incomplete closure, then we should
build the dependencies of this derivation, but after that, we
can still use the substitutes for this derivation itself. */
if (nrIncompleteClosure > 0 && !retrySubstitution) retrySubstitution = true;
if (nrIncompleteClosure > 0) retrySubstitution = true;
nrFailed = nrNoSubstituters = nrIncompleteClosure = 0;
@ -3524,8 +3526,8 @@ private:
/* The current substituter. */
std::shared_ptr<Store> sub;
/* Whether any substituter can realise this path. */
bool hasSubstitute;
/* Whether a substituter failed. */
bool substituterFailed = false;
/* Path info returned by the substituter's query info operation. */
std::shared_ptr<const ValidPathInfo> info;
@ -3589,7 +3591,6 @@ public:
SubstitutionGoal::SubstitutionGoal(const Path & storePath, Worker & worker, RepairFlag repair)
: Goal(worker)
, hasSubstitute(false)
, repair(repair)
{
this->storePath = storePath;
@ -3653,9 +3654,9 @@ void SubstitutionGoal::tryNext()
/* Hack: don't indicate failure if there were no substituters.
In that case the calling derivation should just do a
build. */
amDone(hasSubstitute ? ecFailed : ecNoSubstituters);
amDone(substituterFailed ? ecFailed : ecNoSubstituters);
if (hasSubstitute) {
if (substituterFailed) {
worker.failedSubstitutions++;
worker.updateProgress();
}
@ -3691,8 +3692,6 @@ void SubstitutionGoal::tryNext()
worker.updateProgress();
hasSubstitute = true;
/* Bail out early if this substituter lacks a valid
signature. LocalStore::addToStore() also checks for this, but
only after we've downloaded the path. */
@ -3807,8 +3806,19 @@ void SubstitutionGoal::finished()
state = &SubstitutionGoal::init;
worker.waitForAWhile(shared_from_this());
return;
} catch (Error & e) {
printError(e.msg());
} catch (std::exception & e) {
printError(e.what());
/* Cause the parent build to fail unless --fallback is given,
or the substitute has disappeared. The latter case behaves
the same as the substitute never having existed in the
first place. */
try {
throw;
} catch (SubstituteGone &) {
} catch (...) {
substituterFailed = true;
}
/* Try the next substitute. */
state = &SubstitutionGoal::tryNext;

View File

@ -22,6 +22,7 @@ MakeError(SubstError, Error)
MakeError(BuildError, Error) /* denotes a permanent build failure */
MakeError(InvalidPath, Error)
MakeError(Unsupported, Error)
MakeError(SubstituteGone, Error)
struct BasicDerivation;

View File

@ -76,19 +76,28 @@ if nix-store --substituters "file://$cacheDir" -r $outPath; then
fi
# Test whether fallback works if we have cached info but the
# corresponding NAR has disappeared.
# Test whether fallback works if a NAR has disappeared. This does not require --fallback.
clearStore
nix-build --substituters "file://$cacheDir" dependencies.nix --dry-run # get info
mkdir $cacheDir/tmp
mv $cacheDir/nar $cacheDir/nar2
nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result
mv $cacheDir/nar2 $cacheDir/nar
# Test whether fallback works if a NAR is corrupted. This does require --fallback.
clearStore
mv $cacheDir/nar $cacheDir/nar2
mkdir $cacheDir/nar
for i in $(cd $cacheDir/nar2 && echo *); do touch $cacheDir/nar/$i; done
(! nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result)
nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result --fallback
rm -rf $cacheDir/nar
mv $cacheDir/nar2 $cacheDir/nar