forked from lix-project/lix
Deduplicate basic derivation goals too
See comments for security concerns. Also optimize goal creation by not traversing map twice.
This commit is contained in:
parent
980edd1f3a
commit
993229cdaf
|
@ -296,9 +296,21 @@ public:
|
||||||
~Worker();
|
~Worker();
|
||||||
|
|
||||||
/* Make a goal (with caching). */
|
/* Make a goal (with caching). */
|
||||||
GoalPtr makeDerivationGoal(const StorePath & drvPath, const StringSet & wantedOutputs, BuildMode buildMode = bmNormal);
|
|
||||||
std::shared_ptr<DerivationGoal> makeBasicDerivationGoal(const StorePath & drvPath,
|
/* derivation goal */
|
||||||
const BasicDerivation & drv, BuildMode buildMode = bmNormal);
|
private:
|
||||||
|
std::shared_ptr<DerivationGoal> makeDerivationGoalCommon(
|
||||||
|
const StorePath & drvPath, const StringSet & wantedOutputs,
|
||||||
|
std::function<std::shared_ptr<DerivationGoal>()> mkDrvGoal);
|
||||||
|
public:
|
||||||
|
std::shared_ptr<DerivationGoal> makeDerivationGoal(
|
||||||
|
const StorePath & drvPath,
|
||||||
|
const StringSet & wantedOutputs, BuildMode buildMode = bmNormal);
|
||||||
|
std::shared_ptr<DerivationGoal> makeBasicDerivationGoal(
|
||||||
|
const StorePath & drvPath, const BasicDerivation & drv,
|
||||||
|
const StringSet & wantedOutputs, BuildMode buildMode = bmNormal);
|
||||||
|
|
||||||
|
/* substitution goal */
|
||||||
GoalPtr makeSubstitutionGoal(const StorePath & storePath, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
|
GoalPtr makeSubstitutionGoal(const StorePath & storePath, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
|
||||||
|
|
||||||
/* Remove a dead goal. */
|
/* Remove a dead goal. */
|
||||||
|
@ -949,10 +961,12 @@ private:
|
||||||
friend struct RestrictedStore;
|
friend struct RestrictedStore;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DerivationGoal(const StorePath & drvPath, const StringSet & wantedOutputs,
|
DerivationGoal(const StorePath & drvPath,
|
||||||
Worker & worker, BuildMode buildMode = bmNormal);
|
const StringSet & wantedOutputs, Worker & worker,
|
||||||
|
BuildMode buildMode = bmNormal);
|
||||||
DerivationGoal(const StorePath & drvPath, const BasicDerivation & drv,
|
DerivationGoal(const StorePath & drvPath, const BasicDerivation & drv,
|
||||||
Worker & worker, BuildMode buildMode = bmNormal);
|
const StringSet & wantedOutputs, Worker & worker,
|
||||||
|
BuildMode buildMode = bmNormal);
|
||||||
~DerivationGoal();
|
~DerivationGoal();
|
||||||
|
|
||||||
/* Whether we need to perform hash rewriting if there are valid output paths. */
|
/* Whether we need to perform hash rewriting if there are valid output paths. */
|
||||||
|
@ -1085,8 +1099,8 @@ private:
|
||||||
const Path DerivationGoal::homeDir = "/homeless-shelter";
|
const Path DerivationGoal::homeDir = "/homeless-shelter";
|
||||||
|
|
||||||
|
|
||||||
DerivationGoal::DerivationGoal(const StorePath & drvPath, const StringSet & wantedOutputs,
|
DerivationGoal::DerivationGoal(const StorePath & drvPath,
|
||||||
Worker & worker, BuildMode buildMode)
|
const StringSet & wantedOutputs, Worker & worker, BuildMode buildMode)
|
||||||
: Goal(worker)
|
: Goal(worker)
|
||||||
, useDerivation(true)
|
, useDerivation(true)
|
||||||
, drvPath(drvPath)
|
, drvPath(drvPath)
|
||||||
|
@ -1094,7 +1108,9 @@ DerivationGoal::DerivationGoal(const StorePath & drvPath, const StringSet & want
|
||||||
, buildMode(buildMode)
|
, buildMode(buildMode)
|
||||||
{
|
{
|
||||||
state = &DerivationGoal::getDerivation;
|
state = &DerivationGoal::getDerivation;
|
||||||
name = fmt("building of '%s'", worker.store.printStorePath(this->drvPath));
|
name = fmt(
|
||||||
|
"building of '%s' from .drv file",
|
||||||
|
StorePathWithOutputs { drvPath, wantedOutputs }.to_string(worker.store));
|
||||||
trace("created");
|
trace("created");
|
||||||
|
|
||||||
mcExpectedBuilds = std::make_unique<MaintainCount<uint64_t>>(worker.expectedBuilds);
|
mcExpectedBuilds = std::make_unique<MaintainCount<uint64_t>>(worker.expectedBuilds);
|
||||||
|
@ -1103,15 +1119,18 @@ DerivationGoal::DerivationGoal(const StorePath & drvPath, const StringSet & want
|
||||||
|
|
||||||
|
|
||||||
DerivationGoal::DerivationGoal(const StorePath & drvPath, const BasicDerivation & drv,
|
DerivationGoal::DerivationGoal(const StorePath & drvPath, const BasicDerivation & drv,
|
||||||
Worker & worker, BuildMode buildMode)
|
const StringSet & wantedOutputs, Worker & worker, BuildMode buildMode)
|
||||||
: Goal(worker)
|
: Goal(worker)
|
||||||
, useDerivation(false)
|
, useDerivation(false)
|
||||||
, drvPath(drvPath)
|
, drvPath(drvPath)
|
||||||
|
, wantedOutputs(wantedOutputs)
|
||||||
, buildMode(buildMode)
|
, buildMode(buildMode)
|
||||||
{
|
{
|
||||||
this->drv = std::make_unique<BasicDerivation>(BasicDerivation(drv));
|
this->drv = std::make_unique<BasicDerivation>(BasicDerivation(drv));
|
||||||
state = &DerivationGoal::haveDerivation;
|
state = &DerivationGoal::haveDerivation;
|
||||||
name = fmt("building of %s", StorePathWithOutputs { drvPath, drv.outputNames() }.to_string(worker.store));
|
name = fmt(
|
||||||
|
"building of '%s' from in-memory derivation",
|
||||||
|
StorePathWithOutputs { drvPath, drv.outputNames() }.to_string(worker.store));
|
||||||
trace("created");
|
trace("created");
|
||||||
|
|
||||||
mcExpectedBuilds = std::make_unique<MaintainCount<uint64_t>>(worker.expectedBuilds);
|
mcExpectedBuilds = std::make_unique<MaintainCount<uint64_t>>(worker.expectedBuilds);
|
||||||
|
@ -5060,35 +5079,52 @@ Worker::~Worker()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GoalPtr Worker::makeDerivationGoal(const StorePath & path,
|
std::shared_ptr<DerivationGoal> Worker::makeDerivationGoalCommon(
|
||||||
const StringSet & wantedOutputs, BuildMode buildMode)
|
const StorePath & drvPath,
|
||||||
|
const StringSet & wantedOutputs,
|
||||||
|
std::function<std::shared_ptr<DerivationGoal>()> mkDrvGoal)
|
||||||
{
|
{
|
||||||
GoalPtr goal = derivationGoals[path].lock(); // FIXME
|
WeakGoalPtr & abstract_goal_weak = derivationGoals[drvPath];
|
||||||
if (!goal) {
|
GoalPtr abstract_goal = abstract_goal_weak.lock(); // FIXME
|
||||||
goal = std::make_shared<DerivationGoal>(path, wantedOutputs, *this, buildMode);
|
std::shared_ptr<DerivationGoal> goal;
|
||||||
derivationGoals.insert_or_assign(path, goal);
|
if (!abstract_goal) {
|
||||||
|
goal = mkDrvGoal();
|
||||||
|
abstract_goal_weak = goal;
|
||||||
wakeUp(goal);
|
wakeUp(goal);
|
||||||
} else
|
} else {
|
||||||
(dynamic_cast<DerivationGoal *>(goal.get()))->addWantedOutputs(wantedOutputs);
|
goal = std::dynamic_pointer_cast<DerivationGoal>(abstract_goal);
|
||||||
|
assert(goal);
|
||||||
|
goal->addWantedOutputs(wantedOutputs);
|
||||||
|
}
|
||||||
return goal;
|
return goal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<DerivationGoal> Worker::makeBasicDerivationGoal(const StorePath & drvPath,
|
std::shared_ptr<DerivationGoal> Worker::makeDerivationGoal(const StorePath & drvPath,
|
||||||
const BasicDerivation & drv, BuildMode buildMode)
|
const StringSet & wantedOutputs, BuildMode buildMode)
|
||||||
{
|
{
|
||||||
auto goal = std::make_shared<DerivationGoal>(drvPath, drv, *this, buildMode);
|
return makeDerivationGoalCommon(drvPath, wantedOutputs, [&]() {
|
||||||
wakeUp(goal);
|
return std::make_shared<DerivationGoal>(drvPath, wantedOutputs, *this, buildMode);
|
||||||
return goal;
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<DerivationGoal> Worker::makeBasicDerivationGoal(const StorePath & drvPath,
|
||||||
|
const BasicDerivation & drv, const StringSet & wantedOutputs, BuildMode buildMode)
|
||||||
|
{
|
||||||
|
return makeDerivationGoalCommon(drvPath, wantedOutputs, [&]() {
|
||||||
|
return std::make_shared<DerivationGoal>(drvPath, drv, wantedOutputs, *this, buildMode);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GoalPtr Worker::makeSubstitutionGoal(const StorePath & path, RepairFlag repair, std::optional<ContentAddress> ca)
|
GoalPtr Worker::makeSubstitutionGoal(const StorePath & path, RepairFlag repair, std::optional<ContentAddress> ca)
|
||||||
{
|
{
|
||||||
GoalPtr goal = substitutionGoals[path].lock(); // FIXME
|
WeakGoalPtr & goal_weak = substitutionGoals[path];
|
||||||
|
GoalPtr 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);
|
||||||
substitutionGoals.insert_or_assign(path, goal);
|
goal_weak = goal;
|
||||||
wakeUp(goal);
|
wakeUp(goal);
|
||||||
}
|
}
|
||||||
return goal;
|
return goal;
|
||||||
|
@ -5519,7 +5555,7 @@ BuildResult LocalStore::buildDerivation(const StorePath & drvPath, const BasicDe
|
||||||
BuildMode buildMode)
|
BuildMode buildMode)
|
||||||
{
|
{
|
||||||
Worker worker(*this);
|
Worker worker(*this);
|
||||||
auto goal = worker.makeBasicDerivationGoal(drvPath, drv, buildMode);
|
auto goal = worker.makeBasicDerivationGoal(drvPath, drv, {}, buildMode);
|
||||||
|
|
||||||
BuildResult result;
|
BuildResult result;
|
||||||
|
|
||||||
|
|
|
@ -546,6 +546,20 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
are in fact content-addressed if we don't trust them. */
|
are in fact content-addressed if we don't trust them. */
|
||||||
assert(derivationIsCA(drv.type()) || trusted);
|
assert(derivationIsCA(drv.type()) || trusted);
|
||||||
|
|
||||||
|
/* Recompute the derivation path when we cannot trust the original. */
|
||||||
|
if (!trusted) {
|
||||||
|
/* Recomputing the derivation path for input-address derivations
|
||||||
|
makes it harder to audit them after the fact, since we need the
|
||||||
|
original not-necessarily-resolved derivation to verify the drv
|
||||||
|
derivation as adequate claim to the input-addressed output
|
||||||
|
paths. */
|
||||||
|
assert(derivationIsCA(drv.type()));
|
||||||
|
|
||||||
|
Derivation drv2;
|
||||||
|
static_cast<BasicDerivation &>(drv2) = drv;
|
||||||
|
drvPath = writeDerivation(*store, Derivation { drv2 });
|
||||||
|
}
|
||||||
|
|
||||||
auto res = store->buildDerivation(drvPath, drv, buildMode);
|
auto res = store->buildDerivation(drvPath, drv, buildMode);
|
||||||
logger->stopWork();
|
logger->stopWork();
|
||||||
to << res.status << res.errorMsg;
|
to << res.status << res.errorMsg;
|
||||||
|
|
|
@ -479,8 +479,38 @@ public:
|
||||||
BuildMode buildMode = bmNormal);
|
BuildMode buildMode = bmNormal);
|
||||||
|
|
||||||
/* Build a single non-materialized derivation (i.e. not from an
|
/* Build a single non-materialized derivation (i.e. not from an
|
||||||
on-disk .drv file). Note that ‘drvPath’ is only used for
|
on-disk .drv file).
|
||||||
informational purposes. */
|
|
||||||
|
‘drvPath’ is used to deduplicate worker goals so it is imperative that
|
||||||
|
is correct. That said, it doesn't literally need to be store path that
|
||||||
|
would be calculated from writing this derivation to the store: it is OK
|
||||||
|
if it instead is that of a Derivation which would resolve to this (by
|
||||||
|
taking the outputs of it's input derivations and adding them as input
|
||||||
|
sources) such that the build time referenceable-paths are the same.
|
||||||
|
|
||||||
|
In the input-addressed case, we usually *do* use an "original"
|
||||||
|
unresolved derivations's path, as that is what will be used in the
|
||||||
|
`buildPaths` case. Also, the input-addressed output paths are verified
|
||||||
|
only by that contents of that specific unresolved derivation, so it is
|
||||||
|
nice to keep that information around so if the original derivation is
|
||||||
|
ever obtained later, it can be verified whether the trusted user in fact
|
||||||
|
used the proper output path.
|
||||||
|
|
||||||
|
In the content-addressed case, we want to always use the
|
||||||
|
resolved drv path calculated from the provided derivation. This serves
|
||||||
|
two purposes:
|
||||||
|
|
||||||
|
- It keeps the operation trustless, by ruling out a maliciously
|
||||||
|
invalid drv path corresponding to a non-resolution-equivalent
|
||||||
|
derivation.
|
||||||
|
|
||||||
|
- For the floating case in particular, it ensures that the derivation
|
||||||
|
to output mapping respects the resolution equivalence relation, so
|
||||||
|
one cannot choose different resolution-equivalent derivations to
|
||||||
|
subvert dependency coherence (i.e. the property that one doesn't end
|
||||||
|
up with multiple different versions of dependencies without
|
||||||
|
explicitly choosing to allow it).
|
||||||
|
*/
|
||||||
virtual BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
|
virtual BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
|
||||||
BuildMode buildMode = bmNormal) = 0;
|
BuildMode buildMode = bmNormal) = 0;
|
||||||
|
|
||||||
|
@ -517,7 +547,7 @@ public:
|
||||||
- The collector isn't running, or it's just started but hasn't
|
- The collector isn't running, or it's just started but hasn't
|
||||||
acquired the GC lock yet. In that case we get and release
|
acquired the GC lock yet. In that case we get and release
|
||||||
the lock right away, then exit. The collector scans the
|
the lock right away, then exit. The collector scans the
|
||||||
permanent root and sees our's.
|
permanent root and sees ours.
|
||||||
|
|
||||||
In either case the permanent root is seen by the collector. */
|
In either case the permanent root is seen by the collector. */
|
||||||
virtual void syncWithGC() { };
|
virtual void syncWithGC() { };
|
||||||
|
|
Loading…
Reference in a new issue