Merge pull request #4143 from obsidiansystems/typed-goal-maps

Properly type the derivation and substitution goal maps
This commit is contained in:
Eelco Dolstra 2020-10-18 18:12:21 +02:00 committed by GitHub
commit fda835b231
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 24 deletions

View file

@ -231,7 +231,7 @@ void DerivationGoal::getDerivation()
return; return;
} }
addWaitee(worker.makeSubstitutionGoal(drvPath)); addWaitee(upcast_goal(worker.makeSubstitutionGoal(drvPath)));
state = &DerivationGoal::loadDerivation; state = &DerivationGoal::loadDerivation;
} }
@ -304,10 +304,10 @@ void DerivationGoal::haveDerivation()
/* Nothing to wait for; tail call */ /* Nothing to wait for; tail call */
return DerivationGoal::gaveUpOnSubstitution(); return DerivationGoal::gaveUpOnSubstitution();
} }
addWaitee(worker.makeSubstitutionGoal( addWaitee(upcast_goal(worker.makeSubstitutionGoal(
status.known->path, status.known->path,
buildMode == bmRepair ? Repair : NoRepair, buildMode == bmRepair ? Repair : NoRepair,
getDerivationCA(*drv))); getDerivationCA(*drv))));
} }
if (waitees.empty()) /* to prevent hang (no wake-up event) */ if (waitees.empty()) /* to prevent hang (no wake-up event) */
@ -388,7 +388,7 @@ void DerivationGoal::gaveUpOnSubstitution()
if (!settings.useSubstitutes) if (!settings.useSubstitutes)
throw Error("dependency '%s' of '%s' does not exist, and substitution is disabled", throw Error("dependency '%s' of '%s' does not exist, and substitution is disabled",
worker.store.printStorePath(i), worker.store.printStorePath(drvPath)); worker.store.printStorePath(i), worker.store.printStorePath(drvPath));
addWaitee(worker.makeSubstitutionGoal(i)); addWaitee(upcast_goal(worker.makeSubstitutionGoal(i)));
} }
if (waitees.empty()) /* to prevent hang (no wake-up event) */ if (waitees.empty()) /* to prevent hang (no wake-up event) */
@ -442,7 +442,7 @@ void DerivationGoal::repairClosure()
}); });
auto drvPath2 = outputsToDrv.find(i); auto drvPath2 = outputsToDrv.find(i);
if (drvPath2 == outputsToDrv.end()) if (drvPath2 == outputsToDrv.end())
addWaitee(worker.makeSubstitutionGoal(i, Repair)); addWaitee(upcast_goal(worker.makeSubstitutionGoal(i, Repair)));
else else
addWaitee(worker.makeDerivationGoal(drvPath2->second, StringSet(), bmRepair)); addWaitee(worker.makeDerivationGoal(drvPath2->second, StringSet(), bmRepair));
} }

View file

@ -43,16 +43,13 @@ std::shared_ptr<DerivationGoal> Worker::makeDerivationGoalCommon(
const StringSet & wantedOutputs, const StringSet & wantedOutputs,
std::function<std::shared_ptr<DerivationGoal>()> mkDrvGoal) std::function<std::shared_ptr<DerivationGoal>()> mkDrvGoal)
{ {
WeakGoalPtr & abstract_goal_weak = derivationGoals[drvPath]; std::weak_ptr<DerivationGoal> & goal_weak = derivationGoals[drvPath];
GoalPtr abstract_goal = abstract_goal_weak.lock(); // FIXME std::shared_ptr<DerivationGoal> goal = goal_weak.lock();
std::shared_ptr<DerivationGoal> goal; if (!goal) {
if (!abstract_goal) {
goal = mkDrvGoal(); goal = mkDrvGoal();
abstract_goal_weak = goal; goal_weak = goal;
wakeUp(goal); wakeUp(goal);
} else { } else {
goal = std::dynamic_pointer_cast<DerivationGoal>(abstract_goal);
assert(goal);
goal->addWantedOutputs(wantedOutputs); goal->addWantedOutputs(wantedOutputs);
} }
return goal; return goal;
@ -77,10 +74,10 @@ std::shared_ptr<DerivationGoal> Worker::makeBasicDerivationGoal(const StorePath
} }
GoalPtr Worker::makeSubstitutionGoal(const StorePath & path, RepairFlag repair, std::optional<ContentAddress> ca) std::shared_ptr<SubstitutionGoal> Worker::makeSubstitutionGoal(const StorePath & path, RepairFlag repair, std::optional<ContentAddress> ca)
{ {
WeakGoalPtr & goal_weak = substitutionGoals[path]; std::weak_ptr<SubstitutionGoal> & goal_weak = substitutionGoals[path];
GoalPtr goal = goal_weak.lock(); // FIXME auto goal = goal_weak.lock(); // FIXME
if (!goal) { if (!goal) {
goal = std::make_shared<SubstitutionGoal>(path, *this, repair, ca); goal = std::make_shared<SubstitutionGoal>(path, *this, repair, ca);
goal_weak = goal; goal_weak = goal;
@ -89,14 +86,14 @@ GoalPtr Worker::makeSubstitutionGoal(const StorePath & path, RepairFlag repair,
return goal; return goal;
} }
template<typename G>
static void removeGoal(GoalPtr goal, WeakGoalMap & goalMap) static void removeGoal(std::shared_ptr<G> goal, std::map<StorePath, std::weak_ptr<G>> & goalMap)
{ {
/* !!! inefficient */ /* !!! inefficient */
for (WeakGoalMap::iterator i = goalMap.begin(); for (auto i = goalMap.begin();
i != goalMap.end(); ) i != goalMap.end(); )
if (i->second.lock() == goal) { if (i->second.lock() == goal) {
WeakGoalMap::iterator j = i; ++j; auto j = i; ++j;
goalMap.erase(i); goalMap.erase(i);
i = j; i = j;
} }
@ -106,8 +103,12 @@ static void removeGoal(GoalPtr goal, WeakGoalMap & goalMap)
void Worker::removeGoal(GoalPtr goal) void Worker::removeGoal(GoalPtr goal)
{ {
nix::removeGoal(goal, derivationGoals); if (auto drvGoal = std::dynamic_pointer_cast<DerivationGoal>(goal))
nix::removeGoal(goal, substitutionGoals); nix::removeGoal(drvGoal, derivationGoals);
else if (auto subGoal = std::dynamic_pointer_cast<SubstitutionGoal>(goal))
nix::removeGoal(subGoal, substitutionGoals);
else
assert(false);
if (topGoals.find(goal) != topGoals.end()) { if (topGoals.find(goal) != topGoals.end()) {
topGoals.erase(goal); topGoals.erase(goal);
/* If a top-level goal failed, then kill all other goals /* If a top-level goal failed, then kill all other goals
@ -452,4 +453,9 @@ void Worker::markContentsGood(const StorePath & path)
pathContentsGoodCache.insert_or_assign(path, true); pathContentsGoodCache.insert_or_assign(path, true);
} }
GoalPtr upcast_goal(std::shared_ptr<SubstitutionGoal> subGoal) {
return subGoal;
}
} }

View file

@ -9,6 +9,18 @@ namespace nix {
/* Forward definition. */ /* Forward definition. */
class DerivationGoal; class DerivationGoal;
class SubstitutionGoal;
/* Workaround for not being able to declare a something like
class SubstitutionGoal : public Goal;
even when Goal is a complete type.
This is still a static cast. The purpose of exporting it is to define it in
a place where `SubstitutionGoal` is concrete, and use it in a place where it
is opaque. */
GoalPtr upcast_goal(std::shared_ptr<SubstitutionGoal> subGoal);
typedef std::chrono::time_point<std::chrono::steady_clock> steady_time_point; typedef std::chrono::time_point<std::chrono::steady_clock> steady_time_point;
@ -56,8 +68,8 @@ private:
/* Maps used to prevent multiple instantiations of a goal for the /* Maps used to prevent multiple instantiations of a goal for the
same derivation / path. */ same derivation / path. */
WeakGoalMap derivationGoals; std::map<StorePath, std::weak_ptr<DerivationGoal>> derivationGoals;
WeakGoalMap substitutionGoals; std::map<StorePath, std::weak_ptr<SubstitutionGoal>> substitutionGoals;
/* Goals waiting for busy paths to be unlocked. */ /* Goals waiting for busy paths to be unlocked. */
WeakGoals waitingForAnyGoal; WeakGoals waitingForAnyGoal;
@ -131,7 +143,7 @@ public:
const StringSet & wantedOutputs, BuildMode buildMode = bmNormal); const StringSet & wantedOutputs, BuildMode buildMode = bmNormal);
/* substitution goal */ /* substitution goal */
GoalPtr makeSubstitutionGoal(const StorePath & storePath, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt); std::shared_ptr<SubstitutionGoal> makeSubstitutionGoal(const StorePath & storePath, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
/* Remove a dead goal. */ /* Remove a dead goal. */
void removeGoal(GoalPtr goal); void removeGoal(GoalPtr goal);