Skip to content

worldtree: multiplex per-zone source reads over a bounded connection pool#41

Merged
sonkehahn-shopify merged 5 commits into
worldtreefrom
river-worldtree-connection-pool
Jul 11, 2026
Merged

worldtree: multiplex per-zone source reads over a bounded connection pool#41
sonkehahn-shopify merged 5 commits into
worldtreefrom
river-worldtree-connection-pool

Conversation

@sonkehahn-shopify

Copy link
Copy Markdown
Collaborator

The socket-served source path (Mode B, tec --sha) opened one worldtree control-socket connection per clean zone in getZoneStorePath. A broad evaluation — the Tartarus planning bundle over a large changeset, run with parallel-eval + eval-cores 0 — fans out to hundreds of zones at once, so it opened >512 connections in a burst and tripped worldtreed's per-listener connection cap (ServeConfig::max_connections, 512). Past the cap the daemon accepts-then-drops, which the C++ client sees as
worldtree: read(): Connection reset by peer, aborting the eval.

A hard cap on concurrent connections cannot fix this: the planner needs more zones mounted simultaneously than any safe per-listener cap allows. The daemon already supports many ephemeral RO sessions per connection (its owned-ephemeral set is per-connection and is drained on disconnect), so instead multiplex the per-zone scoped sessions over a bounded pool of connections.

  • WorldtreeConn gains a ws-parametric API (openScopedSession, closeSessionOn, readTreeOn, readBlobOn) so one physical connection can host many independent per-zone sessions; the existing single-session methods (used by the control connection) are unchanged.
  • New WorldtreeZoneSession handle owns one zone's scoped session on a shared carrier connection and releases it (close_ro) when the zone's WorldtreeSourceAccessor — its sole owner — drops.
  • EvalState::acquireWorldtreeZoneSession draws a carrier round-robin from a lazily-grown pool bounded by the new tectonix-worldtree-max-connections setting (default 64, well under the daemon's 512 cap), and opens the zone's scoped session on it. getZoneStorePath uses it instead of one connection per zone.

Per-zone confinement is unchanged: each zone still gets its own scoped session (the daemon enforces the cone per session), just hosted on a shared connection. Reads that land on the same carrier serialize on it; cross-zone parallelism now comes from the pool holding several carriers rather than one connection per zone.

…pool

The socket-served source path (Mode B, `tec --sha`) opened one worldtree
control-socket connection per clean zone in `getZoneStorePath`. A broad
evaluation — the Tartarus planning bundle over a large changeset, run with
parallel-eval + `eval-cores 0` — fans out to hundreds of zones at once, so it
opened >512 connections in a burst and tripped worldtreed's per-listener
connection cap (`ServeConfig::max_connections`, 512). Past the cap the daemon
accepts-then-drops, which the C++ client sees as
`worldtree: read(): Connection reset by peer`, aborting the eval.

A hard cap on concurrent connections cannot fix this: the planner needs more
zones mounted simultaneously than any safe per-listener cap allows. The daemon
already supports many ephemeral RO sessions per connection (its owned-ephemeral
set is per-connection and is drained on disconnect), so instead multiplex the
per-zone scoped sessions over a bounded pool of connections.

- `WorldtreeConn` gains a ws-parametric API (`openScopedSession`,
  `closeSessionOn`, `readTreeOn`, `readBlobOn`) so one physical connection can
  host many independent per-zone sessions; the existing single-session methods
  (used by the control connection) are unchanged.
- New `WorldtreeZoneSession` handle owns one zone's scoped session on a shared
  carrier connection and releases it (`close_ro`) when the zone's
  `WorldtreeSourceAccessor` — its sole owner — drops.
- `EvalState::acquireWorldtreeZoneSession` draws a carrier round-robin from a
  lazily-grown pool bounded by the new `tectonix-worldtree-max-connections`
  setting (default 64, well under the daemon's 512 cap), and opens the zone's
  scoped session on it. `getZoneStorePath` uses it instead of one connection
  per zone.

Per-zone confinement is unchanged: each zone still gets its own `scoped`
session (the daemon enforces the cone per session), just hosted on a shared
connection. Reads that land on the same carrier serialize on it; cross-zone
parallelism now comes from the pool holding several carriers rather than one
connection per zone.

Co-authored-by: Sonke Hahn <sonke.hahn@shopify.com>
@sonkehahn-shopify sonkehahn-shopify force-pushed the river-worldtree-connection-pool branch from 7daf343 to cdcf61c Compare July 8, 2026 15:36
@sonkehahn-shopify sonkehahn-shopify marked this pull request as ready for review July 9, 2026 16:10
Cover the client pool in EvalState::acquireWorldtreeZoneSession, the logic
most likely to silently regress to one connection per zone: bounded lazy
growth, round-robin reuse past the cap, and close_ro on accessor drop.

A minimal in-process fake worldtreed over a real AF_UNIX socket answers
scoped.open_ro/close_ro on the actual control-socket wire, so the real
Client codec, pool, and session RAII all run unstubbed. A narrow
`friend class WorldtreePoolTest` exposes the private pool seam to the test.
@sonkehahn-shopify sonkehahn-shopify requested a review from burke July 10, 2026 18:38
The accessor pool test relied on transitive includes for
fetchers::Settings and openStore, which the darwin/source-tree include
graph provides but the installed x86_64-linux -dev headers do not
(eval.hh only forward-declares fetchers::Settings). Include the
headers directly, matching the other libexpr-tests.
@sonkehahn-shopify sonkehahn-shopify merged commit aa80add into worldtree Jul 11, 2026
12 checks passed
@sonkehahn-shopify sonkehahn-shopify deleted the river-worldtree-connection-pool branch July 11, 2026 00:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants