You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Related: #17 (bridge / multi-engine strategy), #11 (I0–I7 incremental), #2 (meta). Governed by locked decision D16 (docs/plan/01-DECISIONS.md) and IX-T0 (docs/plan/09-INCREMENTAL.md): no daemon is built on assumption — measure first. This issue proposes the daemon's architecture and tooling stack, and the investigation rounds that must gate it. It does not authorize building the daemon before IX-T0 says a daemon is warranted.
Vision
reld-link (and the ELF/Mach-O driver names) becomes a thin client. All linking logic lives in a persistent linker daemon, spawned and lifecycle-managed via running-process create and versioned through the running-process / soldr broker v2 daemon architecture. The daemon holds the object graph (symbol graph + section-contribution graph) hot between edits, which is the precondition — not the optimization — for millisecond warm incremental relink (see #11's "decisive structural fact": incremental cost tracks binary size, not change size, and that floor is unbeatable with on-disk state).
This is the concrete tooling realization of the I2/IX "daemon + snapshot + build-system-supplied change set" plan already in 09-INCREMENTAL.md.
Proposed architecture
Thin CLI, fat daemon. The reld-link client does the minimum: locate/attach to the broker, hand off argv + cwd + env + a content digest of inputs, stream back stdout/stderr + exit code. No parsing, layout, or I/O logic in the client. A client that can't reach a daemon must degrade to a cold in-process link (a daemon panic/absence is a recoverable event → fresh cold link, per 09-INCREMENTAL.md).
Broker-versioned daemons (running-process / soldr broker v2). Multiple daemon versions coexist; the broker routes a client to the daemon matching its reld version + toolchain, exactly as soldr's broker v2 does. Enables zero-downtime reld upgrades and per-project daemon isolation.
Object-graph serialization. The graph must save to disk and reload as a bulk snapshot (never reconstructed incrementally — 09-INCREMENTAL.md). Serialize with protobuf (prost) for fast, schema-versioned ser/deser — OR evaluate a faster zero-copy option (rkyv, capnproto, bincode+mmap) in the investigation. Every snapshot must be keyed by a content digest (D16 / 09-INCREMENTAL.md: "any daemon state not keyed by a content digest is a latent correctness bug").
All synchronization in the daemon. The daemon owns concurrency, the output mmap (it is a lock-holder and must release/reacquire correctly — 09-INCREMENTAL.md), and the no-global-state / no-exit() invariants that stalled lld-as-a-library (I0-I7: Incremental linking (do not start before P4 is green) #11 I0).
Instrumentation stack — via zccache embedded
The daemon uses the zccache embedded crate for its runtime services, so snapshotting and profiling are uniform with the rest of the toolchain:
async runtime
mimalloc pprof — heap snapshots (the allocator-level view that makes daemon "snapshots" meaningful)
async off-CPU tracing (where the daemon blocks — I/O, lock waits: the I7 "bookkeeping wall" is exactly this)
on-CPU tracing (where cycles go inside a warm link)
symbolization — resolved via running-process (it already has the process/symbol machinery)
All of the above should live behind the zccache embedded crate so the daemon depends on one instrumentation surface. mimalloc pprof may not yet be in zccache embedded — if so, that is filed as a dependency sub-issue (see below).
Investigation rounds (this needs several; each gates the next)
R0 — does IX-T0 even justify a daemon? Per D16, run the per-phase timing split first. If parse/setup is ~5% of link time on our workloads, the parse-caching daemon is not built. This issue's architecture only proceeds past R0 if the measurement says so.
R1 — broker fit. Can running-process create + soldr broker v2 host a long-lived, versioned, per-project daemon with the isolation and hot-swap we need? Map the broker API to the client/daemon lifecycle above.
R2 — engine-as-dynamic-lib. ABI/versioning for loading engines as dylibs; how the object graph survives an engine hot-swap; symbol/panic isolation across the dylib boundary.
R3 — serialization format bake-off. protobuf/prost vs zero-copy alternatives, measured on a real graph: snapshot size, save time, cold-reload time, schema-evolution story. Digest-keying design.
R4 — instrumentation integration. Wire zccache-embedded async/tracing/symbolization; confirm mimalloc-pprof availability (or land the sub-issue); prove a heap+CPU+off-CPU snapshot of a warm link is actually actionable.
A written architecture doc (new docs/plan/ entry) exists answering R1–R5, R0 has been measured, and the daemon scope is recorded as an update to D16a (00-OVERVIEW.md already reserves this). No daemon code merges ahead of that record.
Related: #17 (bridge / multi-engine strategy), #11 (I0–I7 incremental), #2 (meta). Governed by locked decision D16 (
docs/plan/01-DECISIONS.md) and IX-T0 (docs/plan/09-INCREMENTAL.md): no daemon is built on assumption — measure first. This issue proposes the daemon's architecture and tooling stack, and the investigation rounds that must gate it. It does not authorize building the daemon before IX-T0 says a daemon is warranted.Vision
reld-link(and the ELF/Mach-O driver names) becomes a thin client. All linking logic lives in a persistent linker daemon, spawned and lifecycle-managed viarunning-process createand versioned through the running-process / soldr broker v2 daemon architecture. The daemon holds the object graph (symbol graph + section-contribution graph) hot between edits, which is the precondition — not the optimization — for millisecond warm incremental relink (see #11's "decisive structural fact": incremental cost tracks binary size, not change size, and that floor is unbeatable with on-disk state).This is the concrete tooling realization of the I2/IX "daemon + snapshot + build-system-supplied change set" plan already in
09-INCREMENTAL.md.Proposed architecture
reld-linkclient does the minimum: locate/attach to the broker, hand off argv + cwd + env + a content digest of inputs, stream back stdout/stderr + exit code. No parsing, layout, or I/O logic in the client. A client that can't reach a daemon must degrade to a cold in-process link (a daemon panic/absence is a recoverable event → fresh cold link, per09-INCREMENTAL.md).09-INCREMENTAL.md). Serialize with protobuf (prost) for fast, schema-versioned ser/deser — OR evaluate a faster zero-copy option (rkyv, capnproto, bincode+mmap) in the investigation. Every snapshot must be keyed by a content digest (D16 /09-INCREMENTAL.md: "any daemon state not keyed by a content digest is a latent correctness bug").09-INCREMENTAL.md), and the no-global-state / no-exit()invariants that stalled lld-as-a-library (I0-I7: Incremental linking (do not start before P4 is green) #11 I0).Instrumentation stack — via
zccacheembeddedThe daemon uses the
zccacheembedded crate for its runtime services, so snapshotting and profiling are uniform with the rest of the toolchain:All of the above should live behind the
zccacheembedded crate so the daemon depends on one instrumentation surface.mimalloc pprofmay not yet be inzccacheembedded — if so, that is filed as a dependency sub-issue (see below).Investigation rounds (this needs several; each gates the next)
running-process create+ soldr broker v2 host a long-lived, versioned, per-project daemon with the isolation and hot-swap we need? Map the broker API to the client/daemon lifecycle above.Done when
A written architecture doc (new
docs/plan/entry) exists answering R1–R5, R0 has been measured, and the daemon scope is recorded as an update to D16a (00-OVERVIEW.mdalready reserves this). No daemon code merges ahead of that record.Dependency sub-issue
zccacheembedded crate — filed as Add mimalloc pprof (heap snapshots) to the embedded crate zccache#1359. Blocks R4's heap-snapshot capability.