2020-10-11 19:17:24 +03:00
|
|
|
#pragma once
|
2023-04-01 06:18:41 +03:00
|
|
|
///@file
|
2020-10-11 19:17:24 +03:00
|
|
|
|
2020-10-12 20:16:48 +03:00
|
|
|
#include "types.hh"
|
2020-10-11 19:17:24 +03:00
|
|
|
#include "lock.hh"
|
2020-12-20 19:36:52 +02:00
|
|
|
#include "store-api.hh"
|
2020-10-12 20:16:48 +03:00
|
|
|
#include "goal.hh"
|
2020-11-09 16:40:10 +02:00
|
|
|
#include "realisation.hh"
|
2009-01-12 18:30:32 +02:00
|
|
|
|
2020-12-20 19:36:52 +02:00
|
|
|
#include <future>
|
|
|
|
#include <thread>
|
|
|
|
|
2006-09-05 00:06:23 +03:00
|
|
|
namespace nix {
|
|
|
|
|
2004-06-18 21:09:32 +03:00
|
|
|
/* Forward definition. */
|
2020-12-01 15:57:56 +02:00
|
|
|
struct DerivationGoal;
|
2020-11-09 14:47:06 +02:00
|
|
|
struct PathSubstitutionGoal;
|
2020-11-09 16:40:10 +02:00
|
|
|
class DrvOutputSubstitutionGoal;
|
2020-10-12 23:47:22 +03:00
|
|
|
|
2020-10-13 21:04:24 +03:00
|
|
|
/* Workaround for not being able to declare a something like
|
|
|
|
|
2020-11-09 14:47:06 +02:00
|
|
|
class PathSubstitutionGoal : public Goal;
|
2020-10-13 21:04:24 +03:00
|
|
|
|
2020-10-18 00:50:12 +03:00
|
|
|
even when Goal is a complete type.
|
|
|
|
|
|
|
|
This is still a static cast. The purpose of exporting it is to define it in
|
2020-11-09 14:47:06 +02:00
|
|
|
a place where `PathSubstitutionGoal` is concrete, and use it in a place where it
|
2020-10-18 00:50:12 +03:00
|
|
|
is opaque. */
|
2020-11-09 14:47:06 +02:00
|
|
|
GoalPtr upcast_goal(std::shared_ptr<PathSubstitutionGoal> subGoal);
|
2020-11-09 16:40:10 +02:00
|
|
|
GoalPtr upcast_goal(std::shared_ptr<DrvOutputSubstitutionGoal> subGoal);
|
2004-06-18 21:09:32 +03:00
|
|
|
|
2016-12-06 22:58:04 +02:00
|
|
|
typedef std::chrono::time_point<std::chrono::steady_clock> steady_time_point;
|
|
|
|
|
|
|
|
|
2004-06-18 21:09:32 +03:00
|
|
|
/* A mapping used to remember for each child process to what goal it
|
2005-10-17 18:33:24 +03:00
|
|
|
belongs, and file descriptors for receiving log data and output
|
|
|
|
path creation commands. */
|
2004-06-20 00:45:04 +03:00
|
|
|
struct Child
|
|
|
|
{
|
2004-06-25 18:36:09 +03:00
|
|
|
WeakGoalPtr goal;
|
2016-08-30 16:45:39 +03:00
|
|
|
Goal * goal2; // ugly hackery
|
2022-02-21 17:28:23 +02:00
|
|
|
std::set<int> fds;
|
2013-04-23 19:04:59 +03:00
|
|
|
bool respectTimeouts;
|
2004-06-20 00:45:04 +03:00
|
|
|
bool inBuildSlot;
|
2016-12-06 22:58:04 +02:00
|
|
|
steady_time_point lastOutput; /* time we last got output on stdout/stderr */
|
|
|
|
steady_time_point timeStarted;
|
2004-06-20 00:45:04 +03:00
|
|
|
};
|
|
|
|
|
2020-10-12 20:16:48 +03:00
|
|
|
/* Forward definition. */
|
|
|
|
struct HookInstance;
|
2004-06-18 21:09:32 +03:00
|
|
|
|
|
|
|
/* The worker class. */
|
|
|
|
class Worker
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2004-06-25 18:36:09 +03:00
|
|
|
/* Note: the worker should only have strong pointers to the
|
|
|
|
top-level goals. */
|
|
|
|
|
|
|
|
/* The top-level goals of the worker. */
|
|
|
|
Goals topGoals;
|
2004-06-18 21:09:32 +03:00
|
|
|
|
|
|
|
/* Goals that are ready to do some work. */
|
2004-06-25 18:36:09 +03:00
|
|
|
WeakGoals awake;
|
2004-06-18 21:09:32 +03:00
|
|
|
|
|
|
|
/* Goals waiting for a build slot. */
|
2004-06-25 18:36:09 +03:00
|
|
|
WeakGoals wantingToBuild;
|
2004-06-18 21:09:32 +03:00
|
|
|
|
|
|
|
/* Child processes currently running. */
|
2016-04-29 14:57:08 +03:00
|
|
|
std::list<Child> children;
|
2004-06-18 21:09:32 +03:00
|
|
|
|
2009-04-01 00:14:07 +03:00
|
|
|
/* Number of build slots occupied. This includes local builds and
|
|
|
|
substitutions but not remote builds via the build hook. */
|
|
|
|
unsigned int nrLocalBuilds;
|
2004-06-20 00:45:04 +03:00
|
|
|
|
2005-01-19 13:16:11 +02:00
|
|
|
/* Maps used to prevent multiple instantiations of a goal for the
|
2005-01-20 18:01:07 +02:00
|
|
|
same derivation / path. */
|
2020-10-12 23:47:22 +03:00
|
|
|
std::map<StorePath, std::weak_ptr<DerivationGoal>> derivationGoals;
|
2020-11-09 14:47:06 +02:00
|
|
|
std::map<StorePath, std::weak_ptr<PathSubstitutionGoal>> substitutionGoals;
|
2020-11-09 16:40:10 +02:00
|
|
|
std::map<DrvOutput, std::weak_ptr<DrvOutputSubstitutionGoal>> drvOutputSubstitutionGoals;
|
2004-06-18 21:09:32 +03:00
|
|
|
|
2007-08-28 14:36:17 +03:00
|
|
|
/* Goals waiting for busy paths to be unlocked. */
|
|
|
|
WeakGoals waitingForAnyGoal;
|
2012-07-27 16:59:18 +03:00
|
|
|
|
2009-03-23 03:05:54 +02:00
|
|
|
/* Goals sleeping for a few seconds (polling a lock). */
|
|
|
|
WeakGoals waitingForAWhile;
|
|
|
|
|
|
|
|
/* Last time the goals in `waitingForAWhile' where woken up. */
|
2016-12-06 22:58:04 +02:00
|
|
|
steady_time_point lastWokenUp;
|
2011-06-30 18:19:13 +03:00
|
|
|
|
2016-04-08 19:07:13 +03:00
|
|
|
/* Cache for pathContentsGood(). */
|
2019-12-05 20:11:09 +02:00
|
|
|
std::map<StorePath, bool> pathContentsGoodCache;
|
2016-04-08 19:07:13 +03:00
|
|
|
|
2004-06-18 21:09:32 +03:00
|
|
|
public:
|
|
|
|
|
2017-08-14 21:14:55 +03:00
|
|
|
const Activity act;
|
2017-08-15 16:31:59 +03:00
|
|
|
const Activity actDerivations;
|
2017-08-14 23:12:36 +03:00
|
|
|
const Activity actSubstitutions;
|
2017-08-14 21:14:55 +03:00
|
|
|
|
2010-12-13 18:53:23 +02:00
|
|
|
/* Set if at least one derivation had a BuildError (i.e. permanent
|
|
|
|
failure). */
|
|
|
|
bool permanentFailure;
|
|
|
|
|
2014-08-17 20:09:03 +03:00
|
|
|
/* Set if at least one derivation had a timeout. */
|
|
|
|
bool timedOut;
|
|
|
|
|
2019-07-02 01:12:12 +03:00
|
|
|
/* Set if at least one derivation fails with a hash mismatch. */
|
|
|
|
bool hashMismatch;
|
|
|
|
|
|
|
|
/* Set if at least one derivation is not deterministic in check mode. */
|
|
|
|
bool checkMismatch;
|
|
|
|
|
2020-12-20 19:36:52 +02:00
|
|
|
Store & store;
|
2021-07-19 16:43:08 +03:00
|
|
|
Store & evalStore;
|
2008-06-09 16:52:45 +03:00
|
|
|
|
2017-01-19 16:15:09 +02:00
|
|
|
std::unique_ptr<HookInstance> hook;
|
2012-07-27 16:59:18 +03:00
|
|
|
|
2017-08-15 16:31:59 +03:00
|
|
|
uint64_t expectedBuilds = 0;
|
|
|
|
uint64_t doneBuilds = 0;
|
|
|
|
uint64_t failedBuilds = 0;
|
|
|
|
uint64_t runningBuilds = 0;
|
|
|
|
|
2017-08-14 23:12:36 +03:00
|
|
|
uint64_t expectedSubstitutions = 0;
|
|
|
|
uint64_t doneSubstitutions = 0;
|
2017-08-15 16:31:59 +03:00
|
|
|
uint64_t failedSubstitutions = 0;
|
2017-08-14 23:42:17 +03:00
|
|
|
uint64_t runningSubstitutions = 0;
|
2017-08-14 21:14:55 +03:00
|
|
|
uint64_t expectedDownloadSize = 0;
|
|
|
|
uint64_t doneDownloadSize = 0;
|
|
|
|
uint64_t expectedNarSize = 0;
|
|
|
|
uint64_t doneNarSize = 0;
|
|
|
|
|
2017-10-24 12:00:16 +03:00
|
|
|
/* Whether to ask the build hook if it can build a derivation. If
|
|
|
|
it answers with "decline-permanently", we don't try again. */
|
|
|
|
bool tryBuildHook = true;
|
|
|
|
|
2021-07-19 16:43:08 +03:00
|
|
|
Worker(Store & store, Store & evalStore);
|
2004-06-18 21:09:32 +03:00
|
|
|
~Worker();
|
|
|
|
|
2004-06-25 18:36:09 +03:00
|
|
|
/* Make a goal (with caching). */
|
2020-08-22 23:44:47 +03:00
|
|
|
|
|
|
|
/* derivation goal */
|
|
|
|
private:
|
|
|
|
std::shared_ptr<DerivationGoal> makeDerivationGoalCommon(
|
2023-01-12 01:57:18 +02:00
|
|
|
const StorePath & drvPath, const OutputsSpec & wantedOutputs,
|
2020-08-22 23:44:47 +03:00
|
|
|
std::function<std::shared_ptr<DerivationGoal>()> mkDrvGoal);
|
|
|
|
public:
|
|
|
|
std::shared_ptr<DerivationGoal> makeDerivationGoal(
|
|
|
|
const StorePath & drvPath,
|
2023-01-12 01:57:18 +02:00
|
|
|
const OutputsSpec & wantedOutputs, BuildMode buildMode = bmNormal);
|
2020-08-22 23:44:47 +03:00
|
|
|
std::shared_ptr<DerivationGoal> makeBasicDerivationGoal(
|
|
|
|
const StorePath & drvPath, const BasicDerivation & drv,
|
2023-01-12 01:57:18 +02:00
|
|
|
const OutputsSpec & wantedOutputs, BuildMode buildMode = bmNormal);
|
2020-08-22 23:44:47 +03:00
|
|
|
|
|
|
|
/* substitution goal */
|
2020-11-09 14:47:06 +02:00
|
|
|
std::shared_ptr<PathSubstitutionGoal> makePathSubstitutionGoal(const StorePath & storePath, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
|
2020-11-09 16:40:10 +02:00
|
|
|
std::shared_ptr<DrvOutputSubstitutionGoal> makeDrvOutputSubstitutionGoal(const DrvOutput & id, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
|
2004-06-18 21:09:32 +03:00
|
|
|
|
2004-06-25 18:36:09 +03:00
|
|
|
/* Remove a dead goal. */
|
2004-06-18 21:09:32 +03:00
|
|
|
void removeGoal(GoalPtr goal);
|
|
|
|
|
|
|
|
/* Wake up a goal (i.e., there is something for it to do). */
|
|
|
|
void wakeUp(GoalPtr goal);
|
|
|
|
|
2009-04-01 00:14:07 +03:00
|
|
|
/* Return the number of local build and substitution processes
|
|
|
|
currently running (but not remote builds via the build
|
|
|
|
hook). */
|
|
|
|
unsigned int getNrLocalBuilds();
|
2004-06-18 21:09:32 +03:00
|
|
|
|
2006-12-08 19:26:21 +02:00
|
|
|
/* Registers a running child process. `inBuildSlot' means that
|
|
|
|
the process counts towards the jobs limit. */
|
2022-02-21 17:28:23 +02:00
|
|
|
void childStarted(GoalPtr goal, const std::set<int> & fds,
|
2016-04-29 14:57:08 +03:00
|
|
|
bool inBuildSlot, bool respectTimeouts);
|
2006-12-08 19:26:21 +02:00
|
|
|
|
|
|
|
/* Unregisters a running child process. `wakeSleepers' should be
|
|
|
|
false if there is no sense in waking up goals that are sleeping
|
|
|
|
because they can't run yet (e.g., there is no free build slot,
|
|
|
|
or the hook would still say `postpone'). */
|
2016-08-30 16:45:39 +03:00
|
|
|
void childTerminated(Goal * goal, bool wakeSleepers = true);
|
2004-06-18 21:09:32 +03:00
|
|
|
|
2006-12-08 19:26:21 +02:00
|
|
|
/* Put `goal' to sleep until a build slot becomes available (which
|
|
|
|
might be right away). */
|
|
|
|
void waitForBuildSlot(GoalPtr goal);
|
|
|
|
|
2007-08-28 14:36:17 +03:00
|
|
|
/* Wait for any goal to finish. Pretty indiscriminate way to
|
|
|
|
wait for some resource that some other goal is holding. */
|
|
|
|
void waitForAnyGoal(GoalPtr goal);
|
2012-07-27 16:59:18 +03:00
|
|
|
|
2009-03-23 03:05:54 +02:00
|
|
|
/* Wait for a few seconds and then retry this goal. Used when
|
|
|
|
waiting for a lock held by another process. This kind of
|
|
|
|
polling is inefficient, but POSIX doesn't really provide a way
|
|
|
|
to wait for multiple locks in the main select() loop. */
|
|
|
|
void waitForAWhile(GoalPtr goal);
|
2012-07-27 16:59:18 +03:00
|
|
|
|
2005-02-23 13:19:27 +02:00
|
|
|
/* Loop until the specified top-level goals have finished. */
|
|
|
|
void run(const Goals & topGoals);
|
2004-06-18 21:09:32 +03:00
|
|
|
|
|
|
|
/* Wait for input to become available. */
|
|
|
|
void waitForInput();
|
2010-12-13 18:53:23 +02:00
|
|
|
|
|
|
|
unsigned int exitStatus();
|
2016-04-08 19:07:13 +03:00
|
|
|
|
|
|
|
/* Check whether the given valid path exists and has the right
|
|
|
|
contents. */
|
2019-12-05 20:11:09 +02:00
|
|
|
bool pathContentsGood(const StorePath & path);
|
2016-04-08 19:07:13 +03:00
|
|
|
|
2020-06-16 23:20:18 +03:00
|
|
|
void markContentsGood(const StorePath & path);
|
2017-08-14 21:14:55 +03:00
|
|
|
|
|
|
|
void updateProgress()
|
|
|
|
{
|
2017-08-15 16:31:59 +03:00
|
|
|
actDerivations.progress(doneBuilds, expectedBuilds + doneBuilds, runningBuilds, failedBuilds);
|
|
|
|
actSubstitutions.progress(doneSubstitutions, expectedSubstitutions + doneSubstitutions, runningSubstitutions, failedSubstitutions);
|
2020-04-07 00:43:43 +03:00
|
|
|
act.setExpected(actFileTransfer, expectedDownloadSize + doneDownloadSize);
|
2017-08-16 17:38:23 +03:00
|
|
|
act.setExpected(actCopyPath, expectedNarSize + doneNarSize);
|
2017-08-14 21:14:55 +03:00
|
|
|
}
|
2004-06-18 21:09:32 +03:00
|
|
|
};
|
|
|
|
|
2006-09-05 00:06:23 +03:00
|
|
|
}
|