aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/build/worker.hh
AgeCommit message (Collapse)Author
2024-10-23libstore: turn Worker::run into a promiseeldritch horrors
a first little step into pushing the event loops up, up and away. eventually we will want them to be instantiated only at the roots of every thread (since kj binds loops to threads), but not today. Change-Id: Ic97f1debba382a5a3f46daeaf2d6d434ee42569f
2024-10-23libstore: hide Worker and goals where possibleeldritch horrors
goals should be considered internal to the worker architecture due to the tight coupling of the two, and we can finally do that. doing this is also a prerequisite for turning Worker::run() into a real promise. Change-Id: I7cf273d4a6fdb75b8d192fce1af07c6265ff6980
2024-10-22libstore: move failingExitStatus into worker resultseldritch horrors
we already have a results type for the entire worker call, we may as well put this bit of info in there. we do keep the assumption of the old code that the field will only be read if some goals have failed; fixing that is a very different mess, and not immediately necessary. Change-Id: If3fc32649dcd88e1987cdd1758c6c5743e3b35ac
2024-10-05libstore: remove Worker::{childStarted, goalFinished}eldritch horrors
these two functions are now nearly trivial and much better inline into makeGoalCommon. keeping them separate also separates information about goal completion flows and how failure information ends up in `Worker`. Change-Id: I6af86996e4a2346583371186595e3013c88fb082
2024-10-05libstore: remove Worker::removeGoaleldritch horrors
we can use our newfound powers of Goal::work Is A Real Promise to remove completed goals from continuation promises. apart from being much easier to follow it's also a lot more efficient because we have the iterator to the item we are trying to remove, skipping a linear search of the cache. Change-Id: Ie0190d051c5f4b81304d98db478348b20c209df5
2024-10-05libstore: remove Goal::notifyeldritch horrors
Goal::work() is a fully usable promise that does not rely on the worker to report completion conditions. as such we no longer need the `notify` field that enabled this interplay. we do have to clear goal caches when destroying the worker though, otherwise goal promises may (incorrectly) keep goals alive due to strong shared pointers created by childStarted. Change-Id: Ie607209aafec064dbdf3464fe207d70ba9ee158a
2024-10-05libstore: return goal results from Worker::run()eldritch horrors
this will be needed to move all interesting result fields out of Goal proper and into WorkResult. once that is done we can treat goals as a totally internal construct of the worker mechanism, which also allows us to fully stop exposing unclear intermediate state to Worker users. Change-Id: I98d7778a4b5b2590b7b070bdfc164a22a0ef7190
2024-10-05libstore: remove Worker::topGoalseldritch horrors
since we now propagate goal exceptions properly we no longer need to check topGoals for a reason to abort early. any early abort reasons, whether by exception or a clean top goal failure, can now be handled by inspecting the goal result in the main loop. this greatly reduces goal-to-goal interactions that do not happen at the main loop level. since the underscore-free name is now available for use as variables we'll migrate to that where we currently use `_topGoals` for locals. Change-Id: I5727c5ea7799647c0a69ab76975b1a03a6558aa6
2024-10-05libstore: propagate goal exceptions using promiseseldritch horrors
drop childException since it's no longer needed. also makes waitForInput, childFinished, and childTerminated redundant. Change-Id: I05d88ffd323c5b5c909ac21056162f69ffb0eb9f
2024-10-05libstore: have goals promise WorkResults, not voideldritch horrors
Change-Id: Idd218ec1572eda84dc47accc0dcd8a954d36f098
2024-10-05libstore: remove Goal::StillAliveeldritch horrors
this was a triumph. i'm making a note here: huge success. it's hard to overstate my satisfaction! i'm not even angry. i'm being so sincere ri actually, no. we *are* angry. this was one dumbass odyssey. nobody has asked for this. but not doing it would have locked us into old, broken protocols forever or (possibly worse) forced us to write our own async framework building on the old did-you-mean-continuations in Worker. if we had done that we'd be locked into ever more, and ever more complex, manual state management all over the place. this just could not stand. Change-Id: I43a6de1035febff59d2eff83be9ad52af4659871
2024-10-04libstore: forbid addWantedGoals when finishedeldritch horrors
due to event loop scheduling behavior it's possible for a derivation goal to fully finish (having seen all paths it was asked to create), but to not notify the worker of this in time to prevent another goal asking the recently-finished goal for more outputs. if this happened the finished goal would ignore the request for more outputs since it considered itself fully done, and the delayed result reporting would cause the requesting goal to assume its request had been honored. if the requested goal had finished *properly* the worker would recreate it instead of asking for more outputs, and this would succeed. it is thus safe to always recreate goals once they are done, so we now do. Change-Id: Ifedd69ca153372c623abe9a9b49cd1523588814f
2024-10-01libstore: turn Worker::updateStatistics into a promiseeldritch horrors
we'll now loop to update displayed statistics, and use this loop to limit the update rate to 50 times per second. we could have updated much more frequently before this (once per iteration of `runImpl`), much faster than would ever be useful in practice. aggressive stats updates can even impede progress due to terminal or network delays. Change-Id: Ifba755a2569f73c919b1fbb06a142c0951395d6d
2024-10-01libstore: remove Worker::wakeUp()eldritch horrors
Worker::run() is now entirely based on the kj event loop and promises, so we need not handle awakeness of goals manually any more. every goal can instead, once it has finished a partial work call, defer itself to being called again in the next iteration of the loop. same end effect. Change-Id: I320eee2fa60bcebaabd74d1323fa96d1402c1d15
2024-10-01libstore: turn periodic gc attempt into a promiseeldritch horrors
notably we will check whether we want to do GC at all only once during startup, and we'll only attempt GC every ten seconds rather than every time a goal has finished a partial work call. this shouldn't cause any problems in practice since relying on auto-gc is not deterministic and stores in which builds can fill all remaining free space in merely ten seconds are severely troubled even when gargage collection runs a lot. Change-Id: I1175a56bf7f4e531f8be90157ad88750ff2ddec4
2024-10-01libstore: turn Worker::run() main loop into a promiseeldritch horrors
Change-Id: Ib112ea9a3e67d5cb3d7d0ded30bbd25c96262470
2024-10-01libstore: turn waitForInput into a promiseeldritch horrors
Change-Id: I8355d8d3f6c43a812990c1912b048e5735b07f7b
2024-10-01Revert "libstore: remove worker removeGoal"Raito Bezarius
Revert submission 1946 Reason for revert: regression in building (found via bisection) Reported by users: > error: path '/nix/store/04ca5xwvasz6s3jg0k7njz6rzi0d225w-jq-1.7.1-dev' does not exist in the store Reverted changes: /q/submissionid:1946 Change-Id: I6f1a4b2f7d7ef5ca430e477fc32bca62fd97036b
2024-09-29libstore: remove worker removeGoaleldritch horrors
this was immensely inefficient on large caches, as can exist when many derivations are buildable simultaneously. since we have smart pointers to goals we can do cache maintenance in goal deleters instead, and use the exact iterators instead of doing a linear search. this *does* rely on goals being deleted to remove them from the cache, which isn't true for toplevel goals. those would have previously been removed when done in all cases, removing the cache entry when keep-going is set. this is arguably incorrect since it might result in those goals being retried, although that could only happen with dynamic derivations or the likes. (luckily dynamic derivations not complete enough to allow this at all) Change-Id: I8e750b868393588c33e4829333d370f2c509ce99
2024-09-29libstore: extract a real makeGoalCommoneldritch horrors
makeDerivationGoalCommon had the right idea, but it didn't quite go far enough. let's do the rest and remove the remaining factory duplication. Change-Id: I1fe32446bdfb501e81df56226fd962f85720725b
2024-09-29libstore: make non-cache goal pointers strongeldritch horrors
without circular references we do not need weak goal pointers except for caches, which should not prevent goal destructors running. caches though cannot create circular references even when they keep strong references. if we removed goals from caches when their work() is fully finished, not when their destructors are run, we could keep strong pointers in caches. since we do not gain much from this we keep those pointers weak for now. Change-Id: I1d4a6850ff5e264443c90eb4531da89f5e97a3a0
2024-09-29libstore: have makeLocalDerivationGoal return unique_ptrseldritch horrors
these can be unique rather than shared because shared_ptr has a converting constructor. preparatory refactor for something else and not necessary on its own, and the extra allocations we must do for shared_ptr control blocks isn't usually relevant anyway. Change-Id: I5391715545240c6ec8e83a031206edafdfc6462f
2024-09-27libstore: turn Goal::WaitForGoals into a promiseeldritch horrors
also gets rid of explicit strong references to dependencies of any goal, and weak references to dependers as well. those are now only held within promises representing goal completion and thus independent of the goal's relation to each other. the weak references to dependers was only needed for notifications, and that's much better handled entirely by kj itself. Change-Id: I00d06df9090f8d6336ee4bb0c1313a7052fb016b
2024-09-27libstore: replace Goal::WaitForSlot with semaphoreseldritch horrors
now that we have an event loop in the worker we can use it and its magical execution suspending properties to replace the slot counts we managed explicitly with semaphores and raii tokens. technically this would not have needed an event loop base to be doable, but it is a whole lot easier to wait for a token to be available if there is a callback mechanism ready for use that doesn't require a whole damn dedicated abstract method in Goal to work, and specific calls to that dedicated method strewn all over the worker implementation Change-Id: I1da7cf386d94e2bbf2dba9b53ff51dbce6a0cff7
2024-09-27libstore: make waiting for a while a promiseeldritch horrors
this simplifies waitForInput quite a lot, and at the same time makes polling less thundering-herd-y. it even fixes early polling wakeups! Change-Id: I6dfa62ce91729b8880342117d71af5ae33366414
2024-09-27libstore: turn builder output processing into event loopeldritch horrors
this removes the rather janky did-you-mean-async poll loop we had so far. sadly kj does not play well with pty file descriptors, so we do have to add our own async input stream that does not eat pty EIO and turns it into an exception. that's still a *lot* better than the old code, and using a real even loop makes everything else easier later. Change-Id: Idd7e0428c59758602cc530bcad224cd2fed4c15e
2024-09-08libstore: turn Worker in a kj event loop usereldritch horrors
using a proper event loop basis we no longer have to worry about most of the intricacies of poll(), or platform-dependent replacements for it. we may even be able to use the event loop and its promise system for all of our scheduling in the future. we don't do any real async processing yet, this is just preparation to separate the first such change from the huge api design difference with the async framework we chose (kj from capnp): kj::Promise, unlike std::future, doesn't return exceptions unmangled. it instead wraps any non-kj exception into a kj exception, erasing all type information and preserving mostly the what() string in the process. this makes sense in the capnp rpc use case where unrestricted exception types can't be transferred, and since it moves error handling styles closer to a world we'd actually like there's no harm in doing it only here for now Change-Id: I20f888de74d525fb2db36ca30ebba4bcfe9cc838
2024-08-30libstore: use notifications for stats counterseldritch horrors
updating statistics *immediately* when any counter changes declutters things somewhat and makes useful status reports less dependent on the current worker main loop. using callbacks will make it easier to move the worker loop into kj entirely, using only promises for scheduling. Change-Id: I695dfa83111b1ec09b1a54cff268f3c1d7743ed6
2024-08-30libstore: hide Worker goal factory methodseldritch horrors
this doesn't serve a great purpose yet except to confine construction of goals to the stack frame of Worker::run() and its child frames. we don't need this yet (and the goal constructors remain fully visible), but in a future change that fully removes the current worker loop we'll need some way of knowing which goals are top-level goals without passing the goals themselves around. once that's possible we can remove visible goals as a concept and rely on build result futures and a scheduler built upon them Change-Id: Ia73cdeffcfb9ba1ce9d69b702dc0bc637a4c4ce6
2024-08-30libstore: add "is dependency" info to goaleldritch horrors
whether goal errors are reported via the `ex` member or just printed to the log depends on whether the goal is a toplevel goal or a dependency. if goals are aware of this themselves we can move error printing out of the worker loop, and since a running worker can only be used by running goals it's totally sufficient to keep a `Worker::running` flag for this Change-Id: I6b5cbe6eccee1afa5fde80653c4b968554ddd16f
2024-08-19libstore: make Worker::childStarted privateeldritch horrors
this can be a proper WorkResult now. childTerminated is unfortunately a lot more stubborn and won't be made private for quite a while yet. once we can get rid of the Worker poll loop that *should* be possible though Change-Id: I2218df202da5cb84e852f6a37e4c20367495b617
2024-08-19libstore: move respect-timeoutiness to goal methodeldritch horrors
this is useless to do on the face of it, but it'll make it easier to convert the entire output handling to use async io and promises soon Change-Id: I2d1eb62c4bbf8f57bd558b9599c08710a389b1a8
2024-08-18libstore: add explicit in-build-slot-ness to goalseldritch horrors
we don't need to expose information about how busy a Worker is if the worker can instead tell its work items whether they are in a slot. in the future we might use this to not start items waiting for a slot if no slots are currently available, but that requires more preparation. Change-Id: Ibe01ac536da7e6d6f80520164117c43e772f9bd9
2024-08-18libstore: make Worker::removeGoal privateeldritch horrors
Change-Id: I8583d9ff752f702a10ec52b0330b0d4d4d2614fa
2024-08-08libstore: make Worker::waitForInput privateeldritch horrors
Change-Id: I71a42acd5a4a9a18b55cf754cdf9896614134398
2024-08-08libstore: make Worker status flags privateeldritch horrors
Change-Id: I16ec8994c6448d70b686a2e4c10f19d4e240750d
2024-08-08libstore: make Worker::wakeUp privateeldritch horrors
Change-Id: Iffa55272fe6ef4adaf3e9d4d25e5339792c2e460
2024-08-08libstore: make Worker::waitForAWhile privateeldritch horrors
Change-Id: I0cdcd436ee71124ca992b4f4fe307624a25f11e9
2024-08-08libstore: make Worker::waitForBuildSlot privateeldritch horrors
Change-Id: I02a54846cd65622edbd7a1d6c24a623b4a59e5b3
2024-08-02libstore: move Goal::amDone to Workereldritch horrors
we still mutate goal state to store the results of any given goal run, but now we also have that information in Worker and could in theory do something else with it. we could return a map of goal to goal results, which would also let us better diagnose failures of subgoals (at all). Change-Id: I1df956bbd9fa8cc9485fb6df32918d68dda3ff48
2024-08-02libstore: encapsulate worker build hook stateeldritch horrors
once goals run on multiple threads these fields must by synchronized as one, or we try to run build hooks to often (or worse, not often enough) Change-Id: I47860e46fe5c6db41755b2a3a1d9dbb5701c4ca4
2024-07-30libstore: count all substitutions toward the same limiteldritch horrors
limiting CA substitutions was a rather recent addition, and it used a dedicated counter to not interfere with regular substitutions. though this works fine it somewhat contradicts the documentation; job limits should apply to all kinds of substitutions, or be one limit for each. Change-Id: I1505105b14260ecc1784039b2cc4b7afcf9115c8
2024-07-29libstore: remove Worker::updateProgresseldritch horrors
just update progress every time a goal has returned from work(). there seem to be no performance penalties, and the code is much simpler now. Change-Id: I288ee568b764ee61f40a498d986afda49987cb50
2024-07-22libstore: remove an always-defaulted argumenteldritch horrors
Change-Id: I3c7f17d5492a16bb54480fa1aa384b96fba72d61
2024-07-22libstore: remove unused Worker::waitForAnyGoaleldritch horrors
Change-Id: Ia3ebd434b17052b6760ce74d8e20025a72148613
2024-07-11libstore: remove upcast_goaleldritch horrors
upcast_goal was only ever needed to break circular includes, but the same solution that gave us upcast_goal also lets us fully remove it: just upcast goals without a wrapper function, but only in .cc files. Change-Id: I9c71654b2535121459ba7dcfd6c5da5606904032
2024-05-07libstore: limit CA realisation info substitution concurrencyeldritch horrors
this seems to be an oversight, considering that regular substitutions are concurrency-limited. while not particularly necessary at present, once we've removed the `Callback` based interfaces it will be needed. Change-Id: Ide2d08169fcc24752cbd07a1d33fb8482f7034f5
2023-10-02Revert "Adapt scheduler to work with dynamic derivations"John Ericson
This reverts commit 5e3986f59cb58f48186a49dcec7aa317b4787522. This un-implements RFC 92 but fixes the critical bug #9052 which many people are hitting. This is a decent stop-gap until a minimal reproduction of that bug is found and a proper fix can be made. Mostly fixed #9052, but I would like to leave that issue open until we have a regression test, so I can then properly fix the bug (unbreaking RFC 92) later. (cherry picked from commit 8440afbed756254784d9fea3eaab06649dffd390)
2023-09-07Allow dynamic derivation deps in `inputDrvs`John Ericson
We use the same nested map representation we used for goals, again in order to save space. We might someday want to combine with `inputDrvs`, by doing `V = bool` instead of `V = std::set<OutputName>`, but we are not doing that yet for sake of a smaller diff. The ATerm format for Derivations also needs to be extended, in addition to the in-memory format. To accomodate this, we added a new basic versioning scheme, so old versions of Nix will get nice errors. (And going forward, if the ATerm format changes again the errors will be even better.) `parsedStrings`, an internal function used as part of parsing derivations in A-Term format, used to consume the final `]` but expect the initial `[` to already be consumed. This made for what looked like unbalanced brackets at callsites, which was confusing. Now it consumes both which is hopefully less confusing. As part of testing, we also created a unit test for the A-Term format for regular non-experimental derivations too. Co-authored-by: Robert Hensing <roberth@users.noreply.github.com> Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io> Apply suggestions from code review Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2023-08-25Adapt scheduler to work with dynamic derivationsJohn Ericson
To avoid dealing with an optional `drvPath` (because we might not know it yet) everywhere, make an `CreateDerivationAndRealiseGoal`. This goal just builds/substitutes the derivation file, and then kicks of a build for that obtained derivation; in other words it does the chaining of goals when the drv file is missing (as can already be the case) or computed (new case). This also means the `getDerivation` state can be removed from `DerivationGoal`, which makes the `BasicDerivation` / in memory case and `Derivation` / drv file file case closer together. The map type is factored out for clarity, and because we will soon hvae a second use for it (`Derivation` itself). Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>