#pragma once ///@file #include "async-semaphore.hh" #include "result.hh" #include "types.hh" #include "store-api.hh" #include "build-result.hh" #include // IWYU pragma: keep #include namespace nix { /** * Forward definition. */ struct Goal; class Worker; /** * A pointer to a goal. */ typedef std::shared_ptr GoalPtr; /** * Set of goals. */ typedef std::set Goals; /** * Used as a hint to the worker on how to schedule a particular goal. For example, * builds are typically CPU- and memory-bound, while substitutions are I/O bound. * Using this information, the worker might decide to schedule more or fewer goals * of each category in parallel. */ enum struct JobCategory { /** * A build of a derivation; it will use CPU and disk resources. */ Build, /** * A substitution an arbitrary store object; it will use network resources. */ Substitution, }; struct Goal { typedef enum {ecSuccess, ecFailed, ecNoSubstituters, ecIncompleteClosure} ExitCode; /** * Backlink to the worker. */ Worker & worker; /** * Whether this goal is only a dependency of other goals. Toplevel * goals that are also dependencies of other toplevel goals do not * set this, only goals that are exclusively dependencies do this. */ const bool isDependency; /** * Number of goals we are/were waiting for that have failed. */ size_t nrFailed = 0; /** * Number of substitution goals we are/were waiting for that * failed because there are no substituters. */ size_t nrNoSubstituters = 0; /** * Number of substitution goals we are/were waiting for that * failed because they had unsubstitutable references. */ size_t nrIncompleteClosure = 0; /** * Name of this goal for debugging purposes. */ std::string name; protected: AsyncSemaphore::Token slotToken; public: struct [[nodiscard]] WorkResult { ExitCode exitCode; BuildResult result = {}; std::shared_ptr ex = {}; bool permanentFailure = false; bool timedOut = false; bool hashMismatch = false; bool checkMismatch = false; }; protected: kj::Promise waitForAWhile(); kj::Promise> waitForGoals(kj::Array>>> dependencies) noexcept; template... G> kj::Promise> waitForGoals(std::pair, kj::Promise>>... goals) noexcept { return waitForGoals( kj::arrOf>>>(std::move(goals)...) ); } virtual kj::Promise> workImpl() noexcept = 0; public: explicit Goal(Worker & worker, bool isDependency) : worker(worker) , isDependency(isDependency) { } virtual ~Goal() noexcept(false) { trace("goal destroyed"); } kj::Promise> work() noexcept; virtual void waiteeDone(GoalPtr waitee) { } void trace(std::string_view s); std::string getName() const { return name; } virtual void cleanup() { } /** * @brief Hint for the scheduler, which concurrency limit applies. * @see JobCategory */ virtual JobCategory jobCategory() const = 0; }; }