Separate derivation building from the scheduler#12663
Separate derivation building from the scheduler#12663mergify[bot] merged 4 commits intoNixOS:masterfrom
Conversation
ad62a08 to
1e01ec5
Compare
|
CC @rickynils and @elaforge, since you were both interested in this sort of modularity work. |
1e01ec5 to
2497082
Compare
| virtual void killSandbox(bool getStats) = 0; | ||
| }; | ||
|
|
||
| std::unique_ptr<DerivationBuilder> makeDerivationBuilder( |
There was a problem hiding this comment.
Because DerivationBuilder only has one implementation (I assume),
you should perhaps consider making this not a virtual class, but just exposing the symbols.
You could do it as such:
namespace derivation_builder {
struct t;
std::unique_ptr<t> make();
bool prepareBuild(t &);
// etc.
}There is a minor concrete performance benefit I think, in that from my experience
clang and gcc will not inline virtual calls even if the callee is statically known,
but it could inline these with LTO I think, but we don't use that anyway.
Maybe not worth it.
| * rather than incoming call edges that either should be removed, or | ||
| * become (higher order) function parameters. | ||
| */ | ||
| struct DerivationBuilder : RestrictionContext |
There was a problem hiding this comment.
Why not make this a class, if it morally is one?
There was a problem hiding this comment.
I'm not a fan of having RestrictionContext as a superclass. Why not just add it as a field member?
|
|
||
| const BuildMode & buildMode; | ||
|
|
||
| DerivationBuilderParams( |
There was a problem hiding this comment.
Couldn't this be a simple struct without a constructor?
There was a problem hiding this comment.
Not if it has references, unfortunately :(
There was a problem hiding this comment.
You could just use pointers honestly
There was a problem hiding this comment.
We have nonnull or something right?
There was a problem hiding this comment.
I don't know of a non-null, I've generally been using references to get non-null.
There was a problem hiding this comment.
I think I hallucinated it or had a commit where I added it. Might be worth adding, maybe not. References are in general IMO not well designed though, especially since you can't tell that a function is taking something by reference at the caller site without looking at the type.
You could have
template <typename T>
class ptr {
T& t;
explicit ptr(T& t) : t(t) {}
[..]
}Then we could use this everywhere instead of references I think and it would Just Work.
In function calls you would do f(ptr(x)), which would make it clear what's happening too, unless I'm wrong and this doesn't type check.
| /** | ||
| * Callbacks that `DerivationBuilder` needs. | ||
| */ | ||
| struct DerivationBuilderCallbacks |
There was a problem hiding this comment.
Couldn't you merge params and callbacks?
There was a problem hiding this comment.
Well maybe you shouldn't so params can be a simple struct
| */ | ||
| Pid pid; | ||
|
|
||
| DerivationBuilder() = default; |
There was a problem hiding this comment.
What happens again if you omit this?
There was a problem hiding this comment.
I am pretty sure then Impl cannot construct this abstract class. But yes it is funny to need that.
There was a problem hiding this comment.
I feel like you're supposed to mark this as virtual or protected or both.
There was a problem hiding this comment.
There are no virtual constructors, but yes it should be protected.
| * become (higher order) function parameters. | ||
| */ | ||
| class DerivationBuilderImpl : public DerivationBuilder, DerivationBuilderParams | ||
| { |
There was a problem hiding this comment.
There are a lot of fields remaining, many of which aren't used much of the time I imagine.
Couldn't we try to fix this properly by turning it into a sum type of all the possible states?
There was a problem hiding this comment.
Might be better for a future PR though.
There was a problem hiding this comment.
Yeah in this one I wanted to mainly figure out what things are used elsewhere, so we can then clean up the internals more easily.
| } | ||
|
|
||
|
|
||
| void appendLogTailErrorMsg( |
There was a problem hiding this comment.
See the commit message --- the other parameters I think don't belong in the interface but rather in the "closure environment" of the implementation.
Really longer term, this UI-focused thing is a layer violation and should not be in here at all.
|
🎉 All dependencies have been resolved ! |
99f9331 to
380369d
Compare
380369d to
681947c
Compare
|
First commit LGTM |
|
Second (fe915ad) LGTM |
The other parameters it took were somewhat implementation-specific.
681947c to
e21057a
Compare
src/libstore/unix/include/nix/store/build/derivation-builder.hh
Outdated
Show resolved
Hide resolved
| DerivationBuilderParams { | ||
| DerivationGoal::drvPath, | ||
| DerivationGoal::buildMode, | ||
| DerivationGoal::buildResult, | ||
| DerivationGoal::drv, | ||
| DerivationGoal::parsedDrv, | ||
| DerivationGoal::drvOptions, | ||
| DerivationGoal::inputPaths, | ||
| DerivationGoal::initialOutputs, | ||
| })} |
There was a problem hiding this comment.
Use { .drvPath = DerivationGoal::drvPath, etc syntax?
There was a problem hiding this comment.
Doesn't work with references :(
This is unreleated to the other commits in this PR.
Now, most of it is in two new functions:
`LocalDerivationGoal::{,un}repareBuild`.
This might seems like a step backwards from coroutines --- now we have
more functions, and are stuck with class vars --- but I don't think it
needs to be.
There's a few options here:
- (Re)introduce coroutines for the isolated building logic. We could use the
same coroutines types, or simpler ones specialized to this use-case.
The `tryLocalBuild` caller can still use `Goal::Co`, and just will
manually "pump" this inner coroutine.
- Return closures from each step. This is sort of like coroutines by
hand, but it still allows us to stop writing down the local variables
in each type.
Being able to fully-use RAII again would be very nice!
- Keep top-level first-order functions like now, but make more
functional. Instead of having one state object (`DerivationBuilder`)
for all steps (setup, run, teardown), we can have separate structs for
the live variables at each point we consume and return.
This at least avoids "are these variables active at this time?"
questions, but doesn't give us the full benefit of RAII as we must
manually ensure FIFO create/destroy orders still.
One thing to note is that by keeping the `outputLock` unlocking in
`tryLocalBuild`, we are arguably uncovering a rebuild scheduling vs
building distinction, as the output locks are pretty squarely a
scheduling concern. It's nice that the builder doesn't need to know
about them at all.
e21057a to
5fbd6cb
Compare
5fbd6cb to
d31e6c4
Compare
|
@mergify queue |
✅ The pull request has been merged automaticallyDetailsThe pull request has been merged automatically at b509502 |
|
With @roberth's approval, I'll just do the commits he didn't get to yet in a separate PR! |
We have a new `DerivationBuilder` struct, and `DerivationBuilderParams` `DerivationBuilderCallbacks` supporting it. `LocalDerivationGoal` doesn't subclass any of these, so we are ready to now move them out to a new file!
d31e6c4 to
d98c0db
Compare
Motivation
Part 1 of #12628. The logic is finally separate!
The interface between
LocalDerivationGoaland theDerivationBuildercan almost certainly be improved, but such qualitative changes are best kept separate from this sort of mechanical refactoring.(We probably can just get rid of
LocalDerivationGoaltoo, with just aDerivationGoalandDerivationGoalImplwith the latter handling both cases.Context
It's probably good to look through each commit one by one.
Depends on #12658Depends on #12692Depends on #12697Add 👍 to pull requests you find important.
The Nix maintainer team uses a GitHub project board to schedule and track reviews.