forked from lix-project/lix
libstore: make PathSubstitutionGoal::work *one* promise
Change-Id: I38cfe8c7059251b581f1013c4213804f36b985ea
This commit is contained in:
parent
9889c79fe3
commit
9b05636937
|
@ -20,7 +20,6 @@ PathSubstitutionGoal::PathSubstitutionGoal(
|
||||||
, repair(repair)
|
, repair(repair)
|
||||||
, ca(ca)
|
, ca(ca)
|
||||||
{
|
{
|
||||||
state = &PathSubstitutionGoal::init;
|
|
||||||
name = fmt("substitution of '%s'", worker.store.printStorePath(this->storePath));
|
name = fmt("substitution of '%s'", worker.store.printStorePath(this->storePath));
|
||||||
trace("created");
|
trace("created");
|
||||||
maintainExpectedSubstitutions = worker.expectedSubstitutions.addTemporarily(1);
|
maintainExpectedSubstitutions = worker.expectedSubstitutions.addTemporarily(1);
|
||||||
|
@ -48,12 +47,6 @@ Goal::Finished PathSubstitutionGoal::done(
|
||||||
|
|
||||||
|
|
||||||
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::work() noexcept
|
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::work() noexcept
|
||||||
{
|
|
||||||
return (this->*state)(slotToken.valid());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::init(bool inBuildSlot) noexcept
|
|
||||||
try {
|
try {
|
||||||
trace("init");
|
trace("init");
|
||||||
|
|
||||||
|
@ -69,13 +62,13 @@ try {
|
||||||
|
|
||||||
subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
|
subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
|
||||||
|
|
||||||
return tryNext(inBuildSlot);
|
return tryNext();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return {std::current_exception()};
|
return {std::current_exception()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::tryNext(bool inBuildSlot) noexcept
|
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::tryNext() noexcept
|
||||||
try {
|
try {
|
||||||
trace("trying next substituter");
|
trace("trying next substituter");
|
||||||
|
|
||||||
|
@ -91,10 +84,10 @@ try {
|
||||||
/* Hack: don't indicate failure if there were no substituters.
|
/* Hack: don't indicate failure if there were no substituters.
|
||||||
In that case the calling derivation should just do a
|
In that case the calling derivation should just do a
|
||||||
build. */
|
build. */
|
||||||
return {done(
|
co_return done(
|
||||||
substituterFailed ? ecFailed : ecNoSubstituters,
|
substituterFailed ? ecFailed : ecNoSubstituters,
|
||||||
BuildResult::NoSubstituters,
|
BuildResult::NoSubstituters,
|
||||||
fmt("path '%s' is required, but there is no substituter that can build it", worker.store.printStorePath(storePath)))};
|
fmt("path '%s' is required, but there is no substituter that can build it", worker.store.printStorePath(storePath)));
|
||||||
}
|
}
|
||||||
|
|
||||||
sub = subs.front();
|
sub = subs.front();
|
||||||
|
@ -107,26 +100,28 @@ try {
|
||||||
if (sub->storeDir == worker.store.storeDir)
|
if (sub->storeDir == worker.store.storeDir)
|
||||||
assert(subPath == storePath);
|
assert(subPath == storePath);
|
||||||
} else if (sub->storeDir != worker.store.storeDir) {
|
} else if (sub->storeDir != worker.store.storeDir) {
|
||||||
return tryNext(inBuildSlot);
|
co_return co_await tryNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
do {
|
||||||
// FIXME: make async
|
try {
|
||||||
info = sub->queryPathInfo(subPath ? *subPath : storePath);
|
// FIXME: make async
|
||||||
} catch (InvalidPath &) {
|
info = sub->queryPathInfo(subPath ? *subPath : storePath);
|
||||||
return tryNext(inBuildSlot);
|
break;
|
||||||
} catch (SubstituterDisabled &) {
|
} catch (InvalidPath &) {
|
||||||
if (settings.tryFallback) {
|
} catch (SubstituterDisabled &) {
|
||||||
return tryNext(inBuildSlot);
|
if (!settings.tryFallback) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
} catch (Error & e) {
|
||||||
|
if (settings.tryFallback) {
|
||||||
|
logError(e.info());
|
||||||
|
} else {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw;
|
co_return co_await tryNext();
|
||||||
} catch (Error & e) {
|
} while (false);
|
||||||
if (settings.tryFallback) {
|
|
||||||
logError(e.info());
|
|
||||||
return tryNext(inBuildSlot);
|
|
||||||
}
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->path != storePath) {
|
if (info->path != storePath) {
|
||||||
if (info->isContentAddressed(*sub) && info->references.empty()) {
|
if (info->isContentAddressed(*sub) && info->references.empty()) {
|
||||||
|
@ -136,7 +131,7 @@ try {
|
||||||
} else {
|
} else {
|
||||||
printError("asked '%s' for '%s' but got '%s'",
|
printError("asked '%s' for '%s' but got '%s'",
|
||||||
sub->getUri(), worker.store.printStorePath(storePath), sub->printStorePath(info->path));
|
sub->getUri(), worker.store.printStorePath(storePath), sub->printStorePath(info->path));
|
||||||
return tryNext(inBuildSlot);
|
co_return co_await tryNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +152,7 @@ try {
|
||||||
{
|
{
|
||||||
warn("ignoring substitute for '%s' from '%s', as it's not signed by any of the keys in 'trusted-public-keys'",
|
warn("ignoring substitute for '%s' from '%s', as it's not signed by any of the keys in 'trusted-public-keys'",
|
||||||
worker.store.printStorePath(storePath), sub->getUri());
|
worker.store.printStorePath(storePath), sub->getUri());
|
||||||
return tryNext(inBuildSlot);
|
co_return co_await tryNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* To maintain the closure invariant, we first have to realise the
|
/* To maintain the closure invariant, we first have to realise the
|
||||||
|
@ -167,18 +162,16 @@ try {
|
||||||
if (i != storePath) /* ignore self-references */
|
if (i != storePath) /* ignore self-references */
|
||||||
dependencies.add(worker.goalFactory().makePathSubstitutionGoal(i));
|
dependencies.add(worker.goalFactory().makePathSubstitutionGoal(i));
|
||||||
|
|
||||||
if (dependencies.empty()) {/* to prevent hang (no wake-up event) */
|
if (!dependencies.empty()) {/* to prevent hang (no wake-up event) */
|
||||||
return referencesValid(inBuildSlot);
|
(co_await waitForGoals(dependencies.releaseAsArray())).value();
|
||||||
} else {
|
|
||||||
state = &PathSubstitutionGoal::referencesValid;
|
|
||||||
return waitForGoals(dependencies.releaseAsArray());
|
|
||||||
}
|
}
|
||||||
|
co_return co_await referencesValid();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return {std::current_exception()};
|
co_return result::failure(std::current_exception());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::referencesValid(bool inBuildSlot) noexcept
|
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::referencesValid() noexcept
|
||||||
try {
|
try {
|
||||||
trace("all references realised");
|
trace("all references realised");
|
||||||
|
|
||||||
|
@ -193,22 +186,18 @@ try {
|
||||||
if (i != storePath) /* ignore self-references */
|
if (i != storePath) /* ignore self-references */
|
||||||
assert(worker.store.isValidPath(i));
|
assert(worker.store.isValidPath(i));
|
||||||
|
|
||||||
state = &PathSubstitutionGoal::tryToRun;
|
return tryToRun();
|
||||||
return tryToRun(inBuildSlot);
|
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return {std::current_exception()};
|
return {std::current_exception()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::tryToRun(bool inBuildSlot) noexcept
|
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::tryToRun() noexcept
|
||||||
try {
|
try {
|
||||||
trace("trying to run");
|
trace("trying to run");
|
||||||
|
|
||||||
if (!inBuildSlot) {
|
if (!slotToken.valid()) {
|
||||||
return worker.substitutions.acquire().then([this](auto token) {
|
slotToken = co_await worker.substitutions.acquire();
|
||||||
slotToken = std::move(token);
|
|
||||||
return work();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
maintainRunningSubstitutions = worker.runningSubstitutions.addTemporarily(1);
|
maintainRunningSubstitutions = worker.runningSubstitutions.addTemporarily(1);
|
||||||
|
@ -239,38 +228,39 @@ try {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
state = &PathSubstitutionGoal::finished;
|
co_await pipe.promise;
|
||||||
return pipe.promise.then([]() -> Result<WorkResult> { return StillAlive{}; });
|
co_return co_await finished();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return {std::current_exception()};
|
co_return result::failure(std::current_exception());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::finished(bool inBuildSlot) noexcept
|
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::finished() noexcept
|
||||||
try {
|
try {
|
||||||
trace("substitute finished");
|
trace("substitute finished");
|
||||||
|
|
||||||
try {
|
do {
|
||||||
slotToken = {};
|
|
||||||
thr.get();
|
|
||||||
} 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 {
|
try {
|
||||||
throw;
|
slotToken = {};
|
||||||
} catch (SubstituteGone &) {
|
thr.get();
|
||||||
} catch (...) {
|
break;
|
||||||
substituterFailed = true;
|
} 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. */
|
/* Try the next substitute. */
|
||||||
state = &PathSubstitutionGoal::tryNext;
|
co_return co_await tryNext();
|
||||||
return tryNext(inBuildSlot);
|
} while (false);
|
||||||
}
|
|
||||||
|
|
||||||
worker.markContentsGood(storePath);
|
worker.markContentsGood(storePath);
|
||||||
|
|
||||||
|
@ -287,9 +277,9 @@ try {
|
||||||
worker.doneNarSize += maintainExpectedNar.delta();
|
worker.doneNarSize += maintainExpectedNar.delta();
|
||||||
maintainExpectedNar.reset();
|
maintainExpectedNar.reset();
|
||||||
|
|
||||||
return {done(ecSuccess, BuildResult::Substituted)};
|
co_return done(ecSuccess, BuildResult::Substituted);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return {std::current_exception()};
|
co_return result::failure(std::current_exception());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -67,9 +67,6 @@ struct PathSubstitutionGoal : public Goal
|
||||||
NotifyingCounter<uint64_t>::Bump maintainExpectedSubstitutions,
|
NotifyingCounter<uint64_t>::Bump maintainExpectedSubstitutions,
|
||||||
maintainRunningSubstitutions, maintainExpectedNar, maintainExpectedDownload;
|
maintainRunningSubstitutions, maintainExpectedNar, maintainExpectedDownload;
|
||||||
|
|
||||||
typedef kj::Promise<Result<WorkResult>> (PathSubstitutionGoal::*GoalState)(bool inBuildSlot) noexcept;
|
|
||||||
GoalState state;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Content address for recomputing store path
|
* Content address for recomputing store path
|
||||||
*/
|
*/
|
||||||
|
@ -95,11 +92,10 @@ public:
|
||||||
/**
|
/**
|
||||||
* The states.
|
* The states.
|
||||||
*/
|
*/
|
||||||
kj::Promise<Result<WorkResult>> init(bool inBuildSlot) noexcept;
|
kj::Promise<Result<WorkResult>> tryNext() noexcept;
|
||||||
kj::Promise<Result<WorkResult>> tryNext(bool inBuildSlot) noexcept;
|
kj::Promise<Result<WorkResult>> referencesValid() noexcept;
|
||||||
kj::Promise<Result<WorkResult>> referencesValid(bool inBuildSlot) noexcept;
|
kj::Promise<Result<WorkResult>> tryToRun() noexcept;
|
||||||
kj::Promise<Result<WorkResult>> tryToRun(bool inBuildSlot) noexcept;
|
kj::Promise<Result<WorkResult>> finished() noexcept;
|
||||||
kj::Promise<Result<WorkResult>> finished(bool inBuildSlot) noexcept;
|
|
||||||
|
|
||||||
/* Called by destructor, can't be overridden */
|
/* Called by destructor, can't be overridden */
|
||||||
void cleanup() override final;
|
void cleanup() override final;
|
||||||
|
|
Loading…
Reference in a new issue