Commit Graph
100 Commits
Author SHA1 Message Date
eldritch horrors cb96940042 libstore: pass a log pipe into build-hook
this way we don't have to duplicate build log parsing in the hook.

Change-Id: I1c96b75aea3b4bb747aa0f0cc76c00eace8911c4
2025-07-22 12:33:49 +00:00
eldritch horrors 6ddd3045f0 testing: remove obsolete daemon tests
remove all daemon version checks targeting daemons we no longer support.

Change-Id: If722024c3d66c73fa1b3cdd63134a09389ac6ea5
2025-07-22 10:39:32 +00:00
eldritch horrors d8dfffbe37 daemon: use kj for splicing stdio connections
drop our reimplementation of splice for non-linux in favor of using kj
pumpTo. this avoids select() for its O(maxfd) behavior, and if kj ever
uses something more efficient than read/write loops we'll benefit too.

Change-Id: Id01ba84bf8831455af2d9755bf1a3039d215bb47
2025-07-22 10:39:32 +00:00
eldritch horrors 2fc47b65b8 libstore: weaken tmpdir root access mode
libarchive *should* not break with 0710 on the tmpdir root on darwin,
just like it doesn't break on linux, but for some reason it does. the
restriction to 0710 can be weakened to 0750 with causing any trouble.

fixes #921

Change-Id: Ia9fc2f8eb9695fc19cefae9857368d5a4e58c8b9
2025-07-20 16:25:04 +00:00
eldritch horrors 9d8ab80435 libstore: don't wait for empty cgroups to empty
oops. m(

Change-Id: Ia421589e76a9740b3e49133598c893339f92250e
2025-07-18 18:57:19 +02:00
eldritch horrors 6d6cccee75 libstore: restrict build-hook parallelism
previously we only had one build hook in waiting at most because build
hook rpc was synchronous. now that it no longer is we attempt to start
one hook per derivation, which depending on scheduling can be a *very*
large number. restrict the waiting hook count to 4 to some concurrency
without collecting a large number of hooks that may never do anything.

Change-Id: Ic0b1125cec4acd69e8a0d4639c232e71b825e01d
2025-07-18 13:43:02 +02:00
eldritch horrors ae3b8e58c3 libstore: chown build dirs with --keep-failed
although we only chown if the build was requested by a local daemon
user. daemonless invocations will not chown as they do not have to.
remote builds *can* chown to the remote builder user, but that does
not seem to happen (for some reason keep-failed is not propagated).

Change-Id: Ic0ead406b38b4ca0556fec42d84888efa25123bf
2025-07-17 15:05:32 +02:00
eldritch horrors 9d5a5c4dc0 libstore: add intermediate directory to build-dirs
this makes the actual build directories used by builders invisible and
inaccessible to other processes on the system, avoiding another vector
for outside processes to interfere with builds or pass credentials the
build sandbox should not have access to into the build sandbox anyway.

fixes #919

Change-Id: Ifaa4d8e3940cfde1406e925f75c1375d2e86d81a
2025-07-16 23:02:16 +00:00
eldritch horrors 8f325fe436 libstore: convert build-hook protocol to rpc
Change-Id: I8da74acdc965aba5091c089101745f7aa501befa
2025-07-15 20:33:30 +02:00
eldritch horrors 8a5a477ca3 treewide: add first batch of capnp rpc types
this touches both libutil and libstore because with no rpc users it
doesn't make that much sense to separate the two. note that all our
strings are represented as Data (ie, blobs) because capnp Text must
be nul-terminated. while it's technically possible to use Text with
strings containing non-terminating NULs it is a bit of a hassle and
could lead to rpc users erroneously stopping at the first NUL byte.

Change-Id: I4c75e03b79a226ffa8d7cd985e3ac632a0cd7c1c
2025-07-15 20:33:30 +02:00
eldritch horrors ca12657a68 build: add capnp compiler wrapper
we need this to generate dependency information, and it'll be the entry
point for custom codegen once we need it. a wrapper also makes it a lot
easier to generate a whole namespace's worth of rpc definitions at once

Change-Id: Iba7a1c92a8a40bede9ed71aa3ab455477ff5e568
2025-07-15 06:40:48 +00:00
eldritch horrors ea11d075e6 libutil: add low-level provider to AsyncContext
without it we can't wrap socket fds for capnp rpc.

Change-Id: I0d603c82d8574b7b0f6eb07b2dff655d94418ec9
2025-07-15 06:40:48 +00:00
eldritch horrors 4a1d16ebca libstore: asyncify build-remote functions
Change-Id: I9fbee928eb955e03c41dfe8ce74bd8a90f5e26cd
2025-07-15 06:40:48 +00:00
eldritch horrors 6877ae5fb8 libstore: handle the entire hook lifecycle in tryBuildHook
if the hook accepts the build request we can handle the entire request
in tryBuildHook. there is no need to punt a partially handled build to
the caller (we only did this to minimize churn during asyncification).

Change-Id: Iec3e35a8103da4fc5fbef394cc28a134ee62a198
2025-07-15 06:40:48 +00:00
eldritch horrors 07ba511921 libutil: add a type-mapping TRY_AWAIT
mapping the result of an await operation before unpacking it lets us
inject rpc type conversion functions without duplicating all that is
needed for proper exception wrapping and async error traces support.

Change-Id: Ibcba1cc6d2b275757e3475881ef20f95dd4d684f
2025-07-15 06:40:48 +00:00
eldritch horrors e01ae1f453 libutil: add generic unix socketpair wrapper
previously we used this only for SSH, but other uses may appear soon.

Change-Id: Ibe9666d63aaea07525ebad57decda88b11964cc0
2025-07-15 06:40:48 +00:00
eldritch horrors b43d7b8136 libstore: don't use Outcome<void, T> in goals
`Outcome<void, T>` and `Result<std::optional<T>>` can be interpreted as
being the same thing, but the latter is easier to use: not only do they
allow TRY_AWAIT usage for their promises, we also don't have the error/
exception confusion of outcomes (where the T above is the "error" type)

Change-Id: I92c9241481cecc97e2992445b3dced53c82a2524
2025-07-14 17:02:30 +00:00
eldritch horrors 280772583f libutil: remote unsafeLockFileSingleThreaded
while this does require spawning a thread for every contended lock now
we don't expect performance to be impacted. only build-remote used the
synchronous method, and it only used it to serialize uploads to remote
builders. these uploads are expensive enough to dwarf the thread cost.

Change-Id: Iad0aa0cd738bc96fd06a90d655803dadffa09c47
2025-07-14 17:02:30 +00:00
eldritch horrors df45583c7a libutil: add AsyncContext::timeoutAfter
this is just a Result-aware version of kj's Timer::timeoutAfter.

Change-Id: I17ff77d40201996b9dafc32bbff0298db8a4fcc9
2025-07-14 17:02:30 +00:00
eldritch horrors 9c1e7d4d07 libstore: use AsyncInputStream for reading builder output
DerivationGoal::InputStream existed only because we did not have an
error-reporting AsyncInputStream of our own yet. we do have one now
though and can thus delete old code in favor of the generic variant

Change-Id: I01c7c564554f8794bdf54603b239b7a808faeda0
2025-07-14 17:02:30 +00:00
eldritch horrors 334b8e2b20 libstore: add log-fd to ssh-ng as well
this way we can get ssh error message if connection setup fails.

Change-Id: Ifc001f77ec0477fb9786f7767a47f3745d6475ff
2025-07-14 17:02:30 +00:00
eldritch horrors d20c3d3643 libutil: remove ErrorInfo::programName
it's effectively unused. one use is a write and a read immediately after
the write, the other use checks whether it's not equal to itself (..wat)

Change-Id: I5f6ce26e75a6bfa500c2e9ac3fc70e8dafc9bd74
2025-07-14 17:02:30 +00:00
eldritch horrors 1a0d05d852 libstore, build-remote: delete static ssh:// fds
this was a mess. ssh:// remotes used the extra static fds for build
logs, ssh-ng:// remotes did not. ssh-ng remotes did not use them at
all since ssh-ng never redirected them to begin with. we now create
pipes dynamically and only for ssh:// builders, then translate logs
received over these pipes into the same format used by ssh-ng. this
requires a new activity we did not have before, but since we have a
great many activities that rarely show up already this shouldn't be
a problem for external tooling. if anything external tools can tell
what's going on much better now (at least for ssh:// remote builds)

Change-Id: I02010cee45598362a947faa3a5b04800d39daa31
2025-07-09 18:21:20 +00:00
eldritch horrors 11d854281a build-remote: extract connecting to builder
Change-Id: I364f20f1c689f87dd4e6ec98a36b43f34647ff43
2025-07-09 15:48:07 +00:00
eldritch horrors a17771569e build-remote: extract machine selection
Change-Id: Id5abe9a46ee8ba71f00379af31b442c3fa7cda92
2025-07-09 14:20:51 +02:00
eldritch horrors 44895d1ed5 build-remote: extract error message printer
Change-Id: I5eab56be27d6178caa341fb2ff1f52475252aab8
2025-07-09 14:20:51 +02:00
eldritch horrors 487b37291f libutil: optimize Sync<T, AsyncMutex>
async queries easily lead to high contention on the localstore sqlite
lock. optimizing the lock wakeup scheme improves query performance by
a linear factor (with the O(waiters) wakeup replaced by O(1) wakeup).
on 100k drv closures we're now at 55s query, down from >8min in 2.93.

Change-Id: I9b96e792c4518a782c690dea92e61260f08f0bad
2025-07-07 18:13:16 +00:00
eldritch horrors 33784540c4 libutil: fix signaling handling on darwin
this partially reverts commit 0cc021ee15,
which for some reason is completely broken on darwin: there seems to be
no way to receive process-directed signals on a non-main thread. trying
to do it anyway will fail silently. since we only ever used kj for this
to get signal handling timeouts on darwin (which lacks sigtimedwait) to
print a nice message about retrying ^C again we can work around this by
moving the message printing into a fresh, unrelated, non-signal thread.

Change-Id: I5939c6ec62a7e1dc1b3f16067f77277533949fa0
2025-07-06 17:47:42 +02:00
eldritch horrors 29d9a88af6 libutil: handle sigint only once per thread
many a cleanup path has been broken by interruptions being thrown every
time checkInterrupt is called. we should only throw *once* though; more
than one Interrupted exception for the same event is not only confusing
but also breaks all cleanup paths at the first checkInterrupt call site
(e.g. #900, the cgroup cleanup saga, temp dirs not being removed, etc).

Change-Id: Ibfabf7f6af6ac2b78ad93582c254bbc48fcb3073
2025-07-06 10:45:55 +00:00
eldritch horrors b1544582af libutil: quit immediately on second sigint
we must be crash-safe *anyway*, and being unable to interrupt lix if it
gets stuck somewhere that never calls checkInterrupt is really annoying

Change-Id: I7c40271c3da7e69d8735e22b7b7c4751b5306ab6
2025-07-05 16:27:47 +02:00
eldritch horrors 0cc021ee15 libutil: asyncify signal handler thread
macos doesn't have sigtimedwait and we need signal wait timeouts in
order to print a "please hit ^C again" message with a bit of delay.

Change-Id: If574fb1a9de0b19975b34fc63662b089eaedc9d2
2025-07-04 22:59:13 +02:00
eldritch horrors 9dbf46f573 cli: asyncify daemonLoop
another checkInterrupt can be a makeInterruptible wrapper now. this is
also necessary to add a second daemon socket for the new rpc protocol.

Change-Id: I55055f975335a75708f1f73edb75f7bfe77a5938
2025-07-04 21:12:12 +02:00
eldritch horrors 362bfd827f cli: drop extraneous daemon thread
it was only needed because we forked subdaemons and couldn't reuse the
main aio root. we now fork+exec, so the main aio root is always valid.

Change-Id: Ia19e20d52d65fe72721292be091f182a8a77a7cb
2025-07-04 14:16:33 +02:00
eldritch horrors a232d14e9c libutil: remove unused ProcessOptions members
neither are set to non-default values any more.

Change-Id: Iffe0f230c51324530dd1ad865e16e159f97ef827
2025-07-04 14:01:11 +02:00
eldritch horrors ebf665b1c8 libutil: remove unused DoSignalSave
all uses are DoSignalSave::Save now, and introducing new DontSave uses
should be avoided as much as possible. process management is already a
mess, simplifying it somewhat will make our life easier in the future.

Change-Id: I77eecabe45bee9de18fba0dfc948403d3ce46dfe
2025-07-04 14:01:11 +02:00
eldritch horrors 7b37d5ea6a cli: fork+exec subdaemons, don't just fork
this resolves problems with aio roots becoming invalid after fork (which
so far forced us to run the daemon loop in an aio-rootless thread), does
not require restarting the signal handler thread in the subdaemon (since
we no longer lose it), and is a step towards solving #18 (with transient
daemons doing the store manipulation started transparently when needed).

Change-Id: Iad0149cbc807e31964407c9a83d12314702c8122
2025-07-04 14:01:11 +02:00
eldritch horrors dffb8e9865 libutil/runProgram2: add explicit argv0 support
Change-Id: I292aed7f25de1c193f6e2374c1f6a7ba9d272dd4
2025-07-04 14:01:11 +02:00
eldritch horrors 164d23f38d libutil/runProgram2: support posix_spawn-like dup-to-self redirections
posix_spawn unsets CLOEXEC for fds that are dup'd onto their existing fd
number. this is very useful when inheriting fd numbers exceeding stderr.

Change-Id: I6f14585d424ded6741fdd087f0c4d33a05936bcc
2025-07-04 14:01:11 +02:00
eldritch horrors 0f0718422f libutil: rename runProgram redirections to make more sense
the `from`/`to` naming only made sense for unidirectional output fds,
for others (and for the dup2 api in general) it was backwards. rename
them to `dup`/`from` to make this look more like the assignment it is

Change-Id: Iee50d06f9cfcea765ace6cfbe85b192829207e5f
2025-07-04 14:01:08 +02:00
eldritch horrors 897f87e76a libutil: allow non-blocking fds for writeFull
writing to non-blocking fds happens during remote builds due to the way
file descriptions are shared between processes. we can either poll when
writing to non-blocking fds are reset fd flags. polling is just easier.
unfortunately there is no reasonable way to test this that isn't flaky.

fixes #896

Change-Id: I1d8666df57da97199247f0770c547d0180f6ce07
2025-07-03 22:37:40 +02:00
eldritch horrors bfabaa688f libutil: fix segfault in makeInterruptible callback
cancelling the promise returned by makeInterruptible could free the
fulfiller before the interrupt callback handle, and no order of the
attachments made a difference. we must resort to putting fulfillers
into shared_ptrs so we can capture them in interrupt callbacks now.
(alternatively we could add another kind of interrupt callback, but
the complexity of doing that outweighs the cost of one shared_ptr.)

fixes #895

Change-Id: I008b160482fd4d81a29d7e9e452dcda858b090b9
2025-07-01 23:12:49 +02:00
eldritch horrors ed3c202c20 libstore: be more economical about fcntl on RemoteStore
download progress reports send a STDERR_RESULT frame. many concurrent
downloads send many STDERR_RESULT frames. each of these frames has us
run the report loop once. since many frames can happen in very little
time we may receive many frames in a single read from the socket, and
that in turn means we don't have to fcntl that socket on every round.
we must still ensure that the socket is in the correct state for each
part of the loop, and this does mean we may run two unnecessary fcntl
sequences per processStderr call. that's a small price to pay though.

Change-Id: I7af607d8c759b76aff0f6016435955e2f9456923
2025-07-01 17:06:26 +02:00
eldritch horrors ce6eba531e libutil: add makeNonBlocking, resetNonBlocking
these are used often enough that deduplicating them is worth it. we do
lose some error fidelity, but valid fds will never cause an error here

Change-Id: I2b91b4848f546a894a2a6c2d36c32a892fb73c9f
2025-07-01 17:06:26 +02:00
eldritch horrors 6e7c0812c7 libstore: drop checkInterrupt from LocalStore::verifyPath
it's only called by verifyStore, and verifyStore is only called by the
daemon and `nix-store --verify`. both pass the promise to `blockOn()`.

Change-Id: I829c0d189fa913cd8566ddd1a578c50e60fb2ddb
2025-06-30 21:46:29 +00:00
eldritch horrors 32cfbe3959 drop checkInterrupt from ThreadPool items
all of them block on a promise very soon after starting. only
queryValidPaths needs to make sure not to swallow Interrupted
exceptions to exit quickly instead of trying all paths first.

Change-Id: I4f99f5d75d7057bad109dc0131aa58e84275e362
2025-06-30 21:46:29 +00:00
eldritch horrors 96fbc29f09 libutil: checkInterrupt in AsyncIoRoot::blockOn
checkInterrupt is cheap, waiting for a promise isn't. checking for
interruptions before any top-level promise is awaited lets us drop
a bunch of checkInterrupt calls elsewhere, such as in thread pools

Change-Id: Id543edf9411e53b2a5bbec77d3084a8f65aaea46
2025-06-30 21:46:29 +00:00
eldritch horrors 2c00a68624 libutil: explicitly declare and document our reserved signals
Change-Id: Ia27cce0d3577219b7476f7ce6dade4387ba727b2
2025-06-30 21:46:29 +00:00
eldritch horrors 325f937cca remove old commented-out checkInterrupt calls
Change-Id: I843ee341ecfb4cb8be995b9e5ac628f75a4c7e4b
2025-06-30 21:46:29 +00:00
eldritch horrors ac80a11300 packaging: unbreak static builds
Change-Id: I84dbf66d2d4116c531384445a108d1eab7752ffb
2025-06-27 22:53:28 +02:00
eldritch horrors e356d54d7a libstore: don't delete already valid outputs after build
eagerly consider outputs as not needing deletion during output
registration rather than only doing so after registration. not
waiting for registration to succeed may keep store paths alive
in the file system if registration fails for some reason; that
seem preferrable to the possibility of having another instance
of this bug. since we only leave *good* outputs around there's
not much to worry about except maybe bit of wasted disk space.

fixes #883

Change-Id: I8c22c92e39b9e203f1061278f86cde19dc4474a4
2025-06-27 15:38:53 +02:00
eldritch horrors a0a00948df libstore: fix scratch output cleanup
the daemon must use real store paths, not virtual store paths. using
virtual paths may inadvertently delete paths in the system nix store
when a build was run on a redirected store as root, which isn't good

Change-Id: Id048b236bda0e0ab1f3be6ccba0ddc1de2a3e941
2025-06-27 15:38:53 +02:00
eldritch horrors e3caf98a8f libstore: wait for cgroups to die on cleanup
killing a cgroup via `cgroup.kill` is not synchronous, we need to give
the processes in the group some time to wake up and exit. due to a few
historical accidents in the codebase we cannot do this asycnhronously,
e.g. with a kj promise without creating yet more problems. we will, at
some point in the future, have to move cgroup management into the main
daemon rather than doing it with RAII wrappers within every subdaemon.

Change-Id: I03bf9060144b5737729f2b05c25771c674fd154c
2025-06-25 14:59:58 +00:00
eldritch horrorsandRaito Bezarius 749afbbe99 libstore: don't default build-dir to temp-dir
if a build directory is accessible to other users it is possible to
smuggle data in and out of build directories. usually this ins only
a build purity problem, but in combination with other issues it can
be used to break out of a build sandbox. to prevent this we default
to using a subdirectory of nixStateDir (which is more restrictive).

Fixes CVE-2025-52991.

Change-Id: Iacfc9b50534de158618c815f9fb99d7dae1be4d0
2025-06-24 10:49:49 +00:00
a959290f41 libstore: use pasta for FODs if available
This allows using a userspace program, pasta, to handle comms between
the build sandbox, and the outside world; allowing for full isolation
including the network namespace, closing the "fixed-output derivation
talks to the host over an abstract domain socket" hole for good.

Fixes CVE-2025-46416.

Co-Authored-By: Puck Meerburg <puck@puckipedia.com>
Change-Id: Ifd499b7dbb3784600a6e842fede65fc031ff9f15
2025-06-24 10:49:49 +00:00
eldritch horrorsandRaito Bezarius e6b9f714ea libutil: add capability support to runProgram2
launching pasta to not run as root will ambient require capabilities.

Change-Id: I1dd2506a1fa3944a9d9062123ef8a74903c597ea
2025-06-24 10:49:49 +00:00
eldritch horrorsandRaito Bezarius 6f2b810b4a libutil: add generic redirections runProgram2
explicit stderr redirection makes mergeStderrToStdout unnecessary also.

Change-Id: I63de929e6dc53f6c5ceb2d43c2ce288bfc04d872
2025-06-24 10:49:49 +00:00
eldritch horrorsandRaito Bezarius 19930d423d libutil: make RunningProgram more useful
make it moveable, make it killable, and add a stdout fd accessor.

Change-Id: I2387cbe8ac67b899a322cd6c7d306ef9ea7abcd0
2025-06-24 10:49:49 +00:00
eldritch horrors 877b0d7121 libstore: asyncify Store::queryMissing
we no longer use thread pools for querying missing derivations. this
binds queryMissing to a single thread for now, but query performance
is still greatly improved. we may want to optimize the store code in
the near future too though since queryMissing is now fully cpu bound

Change-Id: I08a9c8cc199963ef5981572ca4a32d90dbdec028
2025-06-19 14:59:38 +00:00
eldritch horrors 2bfea5eefe libstore: use async streams in LegacySSHStore
this mirrors what have already done to the more modern wires.

Change-Id: I68b65bb400c889ba822386a9c280297c9ff4f740
2025-06-19 14:59:38 +00:00
eldritch horrors 02f61e7759 libstore: asyncify legacy ssh command/response
we intentionally omit writers for the new types we add for serialization
purposes since we do not plan to asyncify the legacy ssh server side. if
we ever change our mind we can extract these types into a header and add
writers as needed. due to the inevitable network overhead of the old ssh
wires we don't bother to optimize serialization too much and instead opt
to make the code more readable; the performance difference does not show
up in practice since network latency dominates the few nanoseconds spent
on extra promise allocations and awaits by a couple orders of magnitude.

Change-Id: Id3ee9a01f8bfa63fa23082fa07de5c673fd70883
2025-06-19 14:59:38 +00:00
eldritch horrors aae67feb19 libstore: make legacy ssh build settings a generator
that'll make sendCommand-ing the legacy protocol much easier.

Change-Id: I3193b306ab28c203fe50c404a15c45cf598ca7e7
2025-06-19 14:59:38 +00:00
eldritch horrors 508f476c18 libstore: don't crash when talking to old ssh:// remotes
protocol version 0x204 dates back to nix 2.0 in 2017. that's old enough
to not worry and drop the gratuitous assertion crash we see it instead.

Change-Id: I8cf23373d4daabccab61f1cbb670947479f0d2bc
2025-06-19 14:59:38 +00:00
eldritch horrors c3bc0d35dd libstore: use async streams in RemoteStore
this is a large step towards making RemoteStore a proper capnp rpc
interface, and it lets us get rid of the RemoteStore error handler
thread pool. this does mean we make six or more extra syscalls per
operation to set and clear socket non-blocking flags, but they are
pretty cheap compared to cross-thread wakeups and scheduling. once
we have real capnp rpc for store wires we can drop them again too.

Change-Id: I67dfebc8644a407cd4a8221ffcad02a938ac5abe
2025-06-17 15:25:32 +02:00
eldritch horrors 3f62905312 libstore: instantiate RemoteStore FdSources as needed
in the future we will want to instantiate either a sink, a source, both,
or streams, depending on how the fd is used. to do this we need to share
read buffers among sync and async readers. removing the FdSource we kept
in the connection also helps prove that we always use this buffer for io

Change-Id: Ib678e128ed6c4a07d6ce5ec1d3cde9eb3f5fc4ca
2025-06-17 14:34:05 +02:00
eldritch horrors 687ea19e6f libstore: drop pervasive RemoteStore send buffering
we don't need to double-buffer commands. only the subframe protocol
needs a buffered backing, and connection setup is special *anyway*.

Change-Id: I596f2bf8e297c3c5dc2befae674deafcf559d9a9
2025-06-17 14:34:05 +02:00
eldritch horrors b0edb262b2 libutil: add bidirectional async fd streams
this may as well be called AsyncSocketStream since that will be what we
use it for, but hopefully it will not exist for long enough to need any
other socket functions to actually justify such highly specific naming.

Change-Id: Icf2fe88cf345405218e4b1bd440267e7f132f5c7
2025-06-17 14:34:05 +02:00
eldritch horrors 7b65d7c508 libutil: add buffered async streams
these will let us share async stream io buffers with sync sinks and sources.

Change-Id: If3149803a9e1fda62391399177da62f7522a811b
2025-06-17 14:34:05 +02:00
eldritch horrors 81d2d26c3f libutil: add async output stream type
we also extend AsyncInputStream with a drainInto variant to give async
output streams rough feature parity with sync sinks. we still will not
add serialization support to streams though, that's far too expensive.

Change-Id: I60d5ab43610c45a40ea8740470a5eafe68064aea
2025-06-17 14:34:05 +02:00
eldritch horrors fa116c96f7 perl: ensure that stores are destroyed after aio roots
otherwise stores containing async objects will cause crashes during
shutdown. currently there are no such stores, but that will change.

Change-Id: I05d46ba6831c641774edfe6aa99aa7d0de457429
2025-06-17 14:34:05 +02:00
eldritch horrors bc33c21b8a cli: remove static destruction from nix-store
store objects may hold on to network connections. if those connections
are async they're bound to the lifetime of the aio runtime, which ends
long before the static object destructors we need for nix-store today.

Change-Id: I4aa5466681a82f7e5008cc0b952fcba01d5b39d7
2025-06-17 14:34:05 +02:00
eldritch horrors 49e6147f95 libutil: remove unused Source::good
Change-Id: I8dcb725578e27415b60a01a16c10720e96a5371b
2025-06-17 14:34:05 +02:00
eldritch horrors e5c4de34c5 libstore: eagerly mark daemon connections as bad on local errors
do not rely on Source/Sink `good()` or delayed guessing about whether
an exception was thrown by the daemon or not. mark connections as bad
for all local errors happening while communication is ongoing instead,
and leave it valid only when an exception was provided by the remote.

we may drop connections a bit too eagerly now, but all cases in which
that happens were vulnerable to protocol desynchronization. there are
still a few windows for this to happen left, but those are unfixable.

Change-Id: Iefaa66c552092c436b9de77aa3f8e09f847a966e
2025-06-17 14:34:05 +02:00
eldritch horrors 37c17804df libstore: serialize wire messages into temp buffer
once we make our socket fds non-blocking we won't be able to easily use
plain FdSink for serialization. performance impact of using a temporary
buffer should be low since we don't send very many messages and even in
the simple local daemon case networking overhead is already quite high.

Change-Id: I550d73142570b7d2e7b0feb1bcc57d61e9b45178
2025-06-17 14:34:05 +02:00
eldritch horrors 6f64e1b133 libutil: make Fd{Sink,Source} io buffer shareable
we will need this during RemoteStore wire asyncification to be able to
use the old synchronous serializers. alternatively we could define all
serializers on the async types as well, but that'd be slow and far too
much unnecessarily duplicated code (that will be deleted soon anyway).

Change-Id: I6e4f334025844b808a697ddcd8f80ddcd8c3fc9c
2025-06-17 14:34:05 +02:00
eldritch horrors fc18a6d170 libutil: disallow Fd{Sink,Source} copy and move
it was never safe. both discarded the buffer of the source object,
possibly leading to silent data corruption. FdSource discarded the
fancy EOF error string as well, possibly causing bad error reports

Change-Id: Ib5c07986471b5af03d707230cd487259201952e9
2025-06-17 14:34:05 +02:00
eldritch horrors 8835b2f057 libutil: remove unused AsyncFdInputStream
Change-Id: I549e0bc36637161847fde6c50887c917c1c1dadc
2025-06-17 14:34:05 +02:00
eldritch horrors d4d20dfe02 libutil: remove unused FdSink::written
don't know how we missed that when removing FdSource::read

Change-Id: I086587e190460a3cc81163008f961def3cce0576
2025-06-17 14:34:05 +02:00
eldritch horrors ba2432f8fe libutil: add asyncJoin, a Result-based joinPromises
we'll need this to asyncify withFramedSink and remove its thread pool.

Change-Id: I1a099392c094f8441482fde3b2d3843931420ffa
2025-06-17 14:34:05 +02:00
eldritch horrors 5f42f66afa libstore: rpc-ish-ify remaining RemoteStore methods
oops, forgot a few

Change-Id: Ic9ed34c29d26e94109d5f69eb90f334f26170ec3
2025-06-17 14:34:05 +02:00
eldritch horrors 7453e2979f libstore: asyncify S3BinaryCacheStore
this has side-effects for FileTransfer as well since that uses S3Helper
for s3:// urls. the side effects should be entirely positive though: we
can run multiple s3 requests in parallel without explicitly running any
of them from thread pools (the aws s3 client takes care of that for us)

Change-Id: I67232e604ebb12982b63770f1661ea1d56c5087b
2025-06-15 14:08:48 +00:00
eldritch horrors 1729c8ca3e libstore: asyncify curl return streams
making stores and their users fully async requires all data streams to
be async. the most notable data streams in common usage are curl first
and remote stores second. curl is much more contained today and easier
to asyncify (with the preparatory work we've done in the past commits)

Change-Id: I2d6ff4687ee2b47e4efaa6714827b7283bed941d
2025-06-15 13:36:31 +00:00
eldritch horrors 04a2aba00a libstore: explicitly init curl transfer sources
this too will make it easier to make the streams async.

Change-Id: I9a961fc667042e0aed23d2241326f1ea719bc7a4
2025-06-15 13:36:31 +00:00
eldritch horrors 490c4e3694 libstore: extract closures in curl wrapper to methods
turning them into promises will be much less problematic this way.

Change-Id: I055186a6318fb75c67ae5e7f57561b2cd62d874e
2025-06-15 13:36:31 +00:00
eldritch horrors de89c7f7c8 libstore: asyncify curl interface
Change-Id: I3fc93016b8ac5e59d9062d4f4aead19ae051a680
2025-06-15 13:36:31 +00:00
eldritch horrors a0d5900408 libstore: asyncify BinaryCacheStore::upsertFile
Change-Id: I8e72399c5bfdf70b551fff832b3002ef21f1ef58
2025-06-15 13:36:31 +00:00
eldritch horrors c76f0467b2 libstore: asyncify BinaryCacheStore::fileExists
Change-Id: I7574f61bf222389606be87bbaff486b386cdbecd
2025-06-15 13:36:31 +00:00
eldritch horrors c108f339f5 libstore: asyncify BinaryCacheStore::getFile
Change-Id: If3a1f127470fdaffb0bf79e0692c5d6baf21f18e
2025-06-15 13:36:31 +00:00
eldritch horrors 9f32ab85e8 libstore: asyncify BinaryCacheStore::getFileContents
Change-Id: I7972d6da6d0ac535d2d20c85390c6d67242cab35
2025-06-15 13:36:31 +00:00
eldritch horrors 743703ce35 libstore: asyncify Store::narFromPath return stream
Change-Id: I051c58e650109c70021c0e0a745c7342226e295b
2025-06-15 13:36:31 +00:00
eldritch horrors d824753377 libutil: add async decompression support
it's a real mess, but it's also the best we can reasonably do.

Change-Id: I3b84840cede0363396bdf290d6e6b0e03ace513c
2025-06-15 15:35:51 +02:00
eldritch horrors ee06552402 libstore: asyncify RemoteStore::Connection::processStderr
we need a wrapper type for the remote exception because our Result type
does not deal well with its good type being the same as its error type.
we could have also return a `Result<Result<void>>` to fix this, but the
wrapper type clarifies via its name where the exception_ptr originates.

Change-Id: Ia6ce67b962cb8d6528b017f4cb682a55d6918939
2025-06-11 22:59:23 +00:00
eldritch horrors 7a10df6e76 libstore: asyncify RemoteStore connection setup
without this processStderr cannot be turned into a promise.

Change-Id: Ia8ee44e9e2344f61c2c63b787b42f867864c7119
2025-06-11 22:32:49 +02:00
eldritch horrors cc04a433f0 libstore: remove flushing from processStderr
it's part of sending the command and should be treated as such.

Change-Id: I7406ead5cd08c79efe50f3b0fcb522a18d9d7bcf
2025-06-11 22:29:30 +02:00
eldritch horrors 8b3fdbc847 libstore: add framed data support to sendCommand
the subframing layer is ... a bit of challenge. since the old code is
synchronous but wants to handle errors asynchronously anyway it is on
the subframing layer to *spawn a thread* that polls for errors on the
wire, while non-framed commands handle errors synchronously once they
have sent all their data. this encapsulation of the wires is far from
perfect (let alone legible), but hopefully it will be only temporary.

Change-Id: I26d8020549b767794cae121313360c488504995f
2025-06-11 22:29:30 +02:00
eldritch horrors 1a2247560d libstore: encapsulate reading simple command results
much the same as the previous change, but on the receiving side.

Change-Id: I9f8a156a9d8fccaf91347e34a5b6baf301df5800
2025-06-11 22:29:30 +02:00
eldritch horrors 2128a2dbac libstore: encapsulate sending of simple commands
use a new helper method to send simple command data (that is, command
data that doesn't involve nested framing) to the daemon. this wraps a
large chunk of wire io, and once all wire io is wrapped thusly we can
replace the sink/source io model with new async input/output streams.

Change-Id: Ief9f520263c230a98403b8756bde917fd1cb236e
2025-06-11 22:29:30 +02:00
eldritch horrors ec374bc6e2 libstore: deserialize findRoots data as vector-of-tuples
a size_t followed by as many pairs of things is exactly the format of a
vector of two-element tuples. it would also be the format of a map, but
Roots is a map of sets. rather than adding a serialization format fixed
to this map type (or some wrapper) we can deserialize the response as a
vector and convert it to the map-of-sets later as this is not run much.

Change-Id: I3950c0f7cc59661576170ace10b25a6f8af1464b
2025-06-11 22:29:30 +02:00
eldritch horrors ab8f4ae7e3 libstore: add CommonProto code for bool/unsigned/uint64_t
we will need these very soon to make the daemon wires more rpc-like.

Change-Id: Ib54acdff0899d70a4c9b1d00c144932c37fdff91
2025-06-11 22:29:30 +02:00
eldritch horrors 87fbc15938 libutil: make the pool element factory a promise
processStderr of RemoteStore wants to be a promise and it must be used
from connection setup, so the pool factory callback must be a promise.

Change-Id: I9ac742b6048ae6dba0bfa5dcb58971386229690b
2025-06-11 22:28:44 +02:00
eldritch horrors 56847dc10d libutil: make Buffered{Sink,Source} io buffer shareable
async io for remote store connections needs some sync parts still for
serialization purposes, and those will have to reuse async io buffers

Change-Id: I05e066e3bf8c4318dc23306383f6a849d018ef91
2025-06-11 18:11:57 +00:00