aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/build/substitution-goal.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore/build/substitution-goal.cc')
-rw-r--r--src/libstore/build/substitution-goal.cc160
1 files changed, 73 insertions, 87 deletions
diff --git a/src/libstore/build/substitution-goal.cc b/src/libstore/build/substitution-goal.cc
index bd0ffcb9b..e0ca23a86 100644
--- a/src/libstore/build/substitution-goal.cc
+++ b/src/libstore/build/substitution-goal.cc
@@ -3,6 +3,8 @@
#include "nar-info.hh"
#include "signals.hh"
#include "finally.hh"
+#include <kj/array.h>
+#include <kj/vector.h>
namespace nix {
@@ -18,7 +20,6 @@ PathSubstitutionGoal::PathSubstitutionGoal(
, repair(repair)
, ca(ca)
{
- state = &PathSubstitutionGoal::init;
name = fmt("substitution of '%s'", worker.store.printStorePath(this->storePath));
trace("created");
maintainExpectedSubstitutions = worker.expectedSubstitutions.addTemporarily(1);
@@ -31,27 +32,21 @@ PathSubstitutionGoal::~PathSubstitutionGoal()
}
-Goal::Finished PathSubstitutionGoal::done(
+Goal::WorkResult PathSubstitutionGoal::done(
ExitCode result,
BuildResult::Status status,
std::optional<std::string> errorMsg)
{
- buildResult.status = status;
+ BuildResult buildResult{.status = status};
if (errorMsg) {
debug(*errorMsg);
buildResult.errorMsg = *errorMsg;
}
- return Finished{result, std::move(buildResult)};
+ return WorkResult{result, std::move(buildResult)};
}
-kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::work(bool inBuildSlot) noexcept
-{
- return (this->*state)(inBuildSlot);
-}
-
-
-kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::init(bool inBuildSlot) noexcept
+kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::workImpl() noexcept
try {
trace("init");
@@ -67,13 +62,13 @@ try {
subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
- return tryNext(inBuildSlot);
+ return tryNext();
} catch (...) {
return {std::current_exception()};
}
-kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::tryNext(bool inBuildSlot) noexcept
+kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::tryNext() noexcept
try {
trace("trying next substituter");
@@ -89,10 +84,10 @@ try {
/* Hack: don't indicate failure if there were no substituters.
In that case the calling derivation should just do a
build. */
- return {done(
+ co_return done(
substituterFailed ? ecFailed : ecNoSubstituters,
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();
@@ -105,26 +100,28 @@ try {
if (sub->storeDir == worker.store.storeDir)
assert(subPath == storePath);
} else if (sub->storeDir != worker.store.storeDir) {
- return tryNext(inBuildSlot);
+ co_return co_await tryNext();
}
- try {
- // FIXME: make async
- info = sub->queryPathInfo(subPath ? *subPath : storePath);
- } catch (InvalidPath &) {
- return tryNext(inBuildSlot);
- } catch (SubstituterDisabled &) {
- if (settings.tryFallback) {
- return tryNext(inBuildSlot);
- }
- throw;
- } catch (Error & e) {
- if (settings.tryFallback) {
- logError(e.info());
- return tryNext(inBuildSlot);
+ do {
+ try {
+ // FIXME: make async
+ info = sub->queryPathInfo(subPath ? *subPath : storePath);
+ break;
+ } catch (InvalidPath &) {
+ } catch (SubstituterDisabled &) {
+ if (!settings.tryFallback) {
+ throw;
+ }
+ } catch (Error & e) {
+ if (settings.tryFallback) {
+ logError(e.info());
+ } else {
+ throw;
+ }
}
- throw;
- }
+ co_return co_await tryNext();
+ } while (false);
if (info->path != storePath) {
if (info->isContentAddressed(*sub) && info->references.empty()) {
@@ -134,7 +131,7 @@ try {
} else {
printError("asked '%s' for '%s' but got '%s'",
sub->getUri(), worker.store.printStorePath(storePath), sub->printStorePath(info->path));
- return tryNext(inBuildSlot);
+ co_return co_await tryNext();
}
}
@@ -155,28 +152,26 @@ try {
{
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());
- return tryNext(inBuildSlot);
+ co_return co_await tryNext();
}
/* To maintain the closure invariant, we first have to realise the
paths referenced by this one. */
- WaitForGoals result;
+ kj::Vector<std::pair<GoalPtr, kj::Promise<Result<WorkResult>>>> dependencies;
for (auto & i : info->references)
if (i != storePath) /* ignore self-references */
- result.goals.insert(worker.goalFactory().makePathSubstitutionGoal(i));
+ dependencies.add(worker.goalFactory().makePathSubstitutionGoal(i));
- if (result.goals.empty()) {/* to prevent hang (no wake-up event) */
- return referencesValid(inBuildSlot);
- } else {
- state = &PathSubstitutionGoal::referencesValid;
- return {std::move(result)};
+ if (!dependencies.empty()) {/* to prevent hang (no wake-up event) */
+ (co_await waitForGoals(dependencies.releaseAsArray())).value();
}
+ co_return co_await referencesValid();
} 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 {
trace("all references realised");
@@ -191,33 +186,33 @@ try {
if (i != storePath) /* ignore self-references */
assert(worker.store.isValidPath(i));
- state = &PathSubstitutionGoal::tryToRun;
- return tryToRun(inBuildSlot);
+ return tryToRun();
} catch (...) {
return {std::current_exception()};
}
-kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::tryToRun(bool inBuildSlot) noexcept
+kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::tryToRun() noexcept
try {
trace("trying to run");
- if (!inBuildSlot) {
- return {WaitForSlot{}};
+ if (!slotToken.valid()) {
+ slotToken = co_await worker.substitutions.acquire();
}
maintainRunningSubstitutions = worker.runningSubstitutions.addTemporarily(1);
- outPipe.create();
+ auto pipe = kj::newPromiseAndCrossThreadFulfiller<void>();
+ outPipe = kj::mv(pipe.fulfiller);
thr = std::async(std::launch::async, [this]() {
+ /* Wake up the worker loop when we're done. */
+ Finally updateStats([this]() { outPipe->fulfill(); });
+
auto & fetchPath = subPath ? *subPath : storePath;
try {
ReceiveInterrupts receiveInterrupts;
- /* Wake up the worker loop when we're done. */
- Finally updateStats([this]() { outPipe.writeSide.close(); });
-
Activity act(*logger, actSubstitute, Logger::Fields{worker.store.printStorePath(storePath), sub->getUri()});
PushActivity pact(act.id);
@@ -233,39 +228,39 @@ try {
}
});
- state = &PathSubstitutionGoal::finished;
- return {WaitForWorld{{outPipe.readSide.get()}, true}};
+ co_await pipe.promise;
+ co_return co_await finished();
} 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 {
trace("substitute finished");
- worker.childTerminated(this);
-
- try {
- 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. */
+ do {
try {
- throw;
- } catch (SubstituteGone &) {
- } catch (...) {
- substituterFailed = true;
+ slotToken = {};
+ thr.get();
+ break;
+ } 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 = &PathSubstitutionGoal::tryNext;
- return tryNext(inBuildSlot);
- }
+ co_return co_await tryNext();
+ } while (false);
worker.markContentsGood(storePath);
@@ -282,15 +277,9 @@ try {
worker.doneNarSize += maintainExpectedNar.delta();
maintainExpectedNar.reset();
- return {done(ecSuccess, BuildResult::Substituted)};
+ co_return done(ecSuccess, BuildResult::Substituted);
} catch (...) {
- return {std::current_exception()};
-}
-
-
-Goal::WorkResult PathSubstitutionGoal::handleChildOutput(int fd, std::string_view data)
-{
- return StillAlive{};
+ co_return result::failure(std::current_exception());
}
@@ -300,12 +289,9 @@ void PathSubstitutionGoal::cleanup()
if (thr.valid()) {
// FIXME: signal worker thread to quit.
thr.get();
- worker.childTerminated(this);
}
-
- outPipe.close();
} catch (...) {
- ignoreException();
+ ignoreExceptionInDestructor();
}
}