aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreldritch horrors <pennae@lix.systems>2024-10-05 00:38:35 +0200
committereldritch horrors <pennae@lix.systems>2024-10-05 19:44:47 +0000
commitf389a5407916ba311faa50ec053f7ebac2a608b5 (patch)
treef077ce3624fa03ab1032dda960f54be9c1f1217d
parent7ef44660181b5c9743475ea73bc2e87a5f1d318f (diff)
libstore: propagate goal exceptions using promises
drop childException since it's no longer needed. also makes waitForInput, childFinished, and childTerminated redundant. Change-Id: I05d88ffd323c5b5c909ac21056162f69ffb0eb9f
-rw-r--r--src/libstore/build/goal.cc1
-rw-r--r--src/libstore/build/worker.cc61
-rw-r--r--src/libstore/build/worker.hh20
3 files changed, 26 insertions, 56 deletions
diff --git a/src/libstore/build/goal.cc b/src/libstore/build/goal.cc
index cf52280ed..ef5e8ae96 100644
--- a/src/libstore/build/goal.cc
+++ b/src/libstore/build/goal.cc
@@ -57,6 +57,7 @@ try {
while (auto item = co_await collectDeps.next()) {
auto & [dep, _result] = *item;
+ BOOST_OUTCOME_CO_TRYV(_result);
waiteeDone(dep);
diff --git a/src/libstore/build/worker.cc b/src/libstore/build/worker.cc
index 839b56bc8..5ca7cde76 100644
--- a/src/libstore/build/worker.cc
+++ b/src/libstore/build/worker.cc
@@ -1,3 +1,4 @@
+#include "async-collect.hh"
#include "charptr-cast.hh"
#include "worker.hh"
#include "finally.hh"
@@ -6,6 +7,8 @@
#include "local-derivation-goal.hh"
#include "signals.hh"
#include "hook-instance.hh" // IWYU pragma: keep
+#include <boost/outcome/try.hpp>
+#include <kj/vector.h>
namespace nix {
@@ -231,20 +234,9 @@ void Worker::childStarted(GoalPtr goal, kj::Promise<Result<Goal::WorkResult>> pr
if (result.has_value()) {
goalFinished(goal, result.assume_value());
} else {
- childException = result.assume_error();
+ goal->notify->fulfill(result.assume_error());
}
- })
- .attach(Finally{[this, goal] {
- childTerminated(goal);
- }}));
-}
-
-
-void Worker::childTerminated(GoalPtr goal)
-{
- if (childFinished) {
- childFinished->fulfill();
- }
+ }));
}
@@ -282,9 +274,12 @@ std::vector<GoalPtr> Worker::run(std::function<Targets (GoalFactory &)> req)
running = true;
Finally const _stop([&] { running = false; });
+ std::vector<GoalPtr> results;
+
topGoals.clear();
for (auto & [goal, _promise] : _topGoals) {
topGoals.insert(goal);
+ results.push_back(goal);
}
auto onInterrupt = kj::newPromiseAndCrossThreadFulfiller<Result<void>>();
@@ -292,8 +287,9 @@ std::vector<GoalPtr> Worker::run(std::function<Targets (GoalFactory &)> req)
return result::failure(std::make_exception_ptr(makeInterrupted()));
});
- auto promise =
- runImpl().exclusiveJoin(updateStatistics()).exclusiveJoin(std::move(onInterrupt.promise));
+ auto promise = runImpl(std::move(_topGoals))
+ .exclusiveJoin(updateStatistics())
+ .exclusiveJoin(std::move(onInterrupt.promise));
// TODO GC interface?
if (auto localStore = dynamic_cast<LocalStore *>(&store); localStore && settings.minFree != 0) {
@@ -303,27 +299,24 @@ std::vector<GoalPtr> Worker::run(std::function<Targets (GoalFactory &)> req)
promise.wait(aio.waitScope).value();
- std::vector<GoalPtr> results;
- for (auto & [i, _p] : _topGoals) {
- results.push_back(i);
- }
return results;
}
-kj::Promise<Result<void>> Worker::runImpl()
+kj::Promise<Result<void>> Worker::runImpl(Targets _topGoals)
try {
debug("entered goal loop");
- while (1) {
- if (topGoals.empty()) break;
+ kj::Vector<Targets::value_type> promises(_topGoals.size());
+ for (auto & gp : _topGoals) {
+ promises.add(std::move(gp));
+ }
- /* Wait for input. */
- if (!children.isEmpty())
- (co_await waitForInput()).value();
+ auto collect = AsyncCollect(promises.releaseAsArray());
+ while (auto done = co_await collect.next()) {
+ // propagate goal exceptions outward
+ BOOST_OUTCOME_CO_TRYV(done->second);
- if (childException) {
- std::rethrow_exception(childException);
- }
+ if (topGoals.empty()) break;
}
/* If --keep-going is not set, it's possible that the main goal
@@ -346,18 +339,6 @@ try {
co_return result::failure(std::current_exception());
}
-kj::Promise<Result<void>> Worker::waitForInput()
-try {
- printMsg(lvlVomit, "waiting for children");
-
- auto pair = kj::newPromiseAndFulfiller<void>();
- this->childFinished = kj::mv(pair.fulfiller);
- co_await pair.promise;
- co_return result::success();
-} catch (...) {
- co_return result::failure(std::current_exception());
-}
-
unsigned int Worker::failingExitStatus()
{
diff --git a/src/libstore/build/worker.hh b/src/libstore/build/worker.hh
index 78e204b5a..26832c3b1 100644
--- a/src/libstore/build/worker.hh
+++ b/src/libstore/build/worker.hh
@@ -84,6 +84,9 @@ protected:
*/
class Worker : public WorkerBase
{
+public:
+ using Targets = std::map<GoalPtr, kj::Promise<Result<Goal::WorkResult>>>;
+
private:
bool running = false;
@@ -143,13 +146,6 @@ private:
void goalFinished(GoalPtr goal, Goal::WorkResult & f);
- kj::Own<kj::PromiseFulfiller<void>> childFinished;
-
- /**
- * Wait for input to become available.
- */
- kj::Promise<Result<void>> waitForInput();
-
/**
* Remove a dead goal.
*/
@@ -161,11 +157,6 @@ private:
void childStarted(GoalPtr goal, kj::Promise<Result<Goal::WorkResult>> promise);
/**
- * Unregisters a running child process.
- */
- void childTerminated(GoalPtr goal);
-
- /**
* Pass current stats counters to the logger for progress bar updates.
*/
kj::Promise<Result<void>> updateStatistics();
@@ -181,7 +172,7 @@ private:
statisticsUpdateInhibitor = {};
}
- kj::Promise<Result<void>> runImpl();
+ kj::Promise<Result<void>> runImpl(Targets _topGoals);
kj::Promise<Result<void>> boopGC(LocalStore & localStore);
public:
@@ -197,7 +188,6 @@ public:
private:
kj::TaskSet children;
- std::exception_ptr childException;
public:
struct HookState {
@@ -277,8 +267,6 @@ private:
makeGoal(const DerivedPath & req, BuildMode buildMode = bmNormal) override;
public:
- using Targets = std::map<GoalPtr, kj::Promise<Result<Goal::WorkResult>>>;
-
/**
* Loop until the specified top-level goals have finished.
*/