Skip to content

DDIR: run the examples and tests through the server; retire the ddir harness - #858

Merged
frankmcsherry merged 5 commits into
master-nextfrom
server-examples
Sep 5, 2026
Merged

DDIR: run the examples and tests through the server; retire the ddir harness#858
frankmcsherry merged 5 commits into
master-nextfrom
server-examples

Conversation

@frankmcsherry

@frankmcsherry frankmcsherry commented Sep 5, 2026

Copy link
Copy Markdown
Member

The single-program harness (interactive/examples/ddir.rs) duplicated the server's job: build one dataflow, fill its inputs, close epochs. This retargets the examples, the test suites and the AoC suite onto the server, and — since the repo had grown two server front ends, both building a binary named ddir_server — ends with exactly one: the live ddir-server crate. Net −451 lines with the example driver gone.

What the server gained

  • feed <prog> <in#> from <recipe-or-file> — fills a positional input from a source the server reads itself, sharded across the workers (each worker feeds row % peers == index through its own handle), so no row crosses the wire. The source is a recipe an import already accepts (random:nodes=N,edges=E[,arity=A][,seed=S][,churn=C], iota:N) or a text file of whitespace-separated integer rows. A churn=C recipe keeps changing the input on every tick — the harness's batch/rounds loop — through the same per-input generator that drives generated sources (now one map per program, not one slot).
  • load <name> from <path> [explain=<arity>[,debug]] [name=binding …] — installs a program file (.ddp pipe syntax, else applicative), read on the session thread like an inline body. explain= applies the explanation rewrite before optimization and replaces the reserved --explain; the query input is the one after the program's own, the demand sets are peekable exports.
  • peek <trace> [key] and tick [n] reporting wall-clock time alongside the epoch.
  • server::evaluate(backend, timely::Config, program, inputs) — the data-in/data-out entry point the test suites use: install, feed, tick, snapshot, the path a live install takes. It replaces the vec and corgi backends' private evaluate harnesses, so the corgi gate (1–4 workers and over serializing channels) and the explanation tests all run against the server on both backends.
  • The session scripts, the AoC suite (run.sh [vec|corgi], 33/33 on both) and the READMEs pipe into cargo run -p ddir-server with DDIR_WORKERS / DDIR_BACKEND. install is spelled load throughout, the crate's word. The crate now runs on the same global allocator the example driver did.
  • The corgi typer accepts the if(1, $1, 0) idiom (a literal condition compiles only its live branch), which was the one AoC part corgi could not run.

Deleted: the harness, the example driver, survey_sources, the diagnostics dev-dependency on interactive, and the harness's --sync=K. The last one cannot be reproduced yet: several epochs in flight make leave_dynamic see a two-element stamp, and it asks for a singleton.

What other workloads will need from the server

Opening the discussion, from what this migration ran into:

  1. Input formats. feed … from reads integer rows only. Anything with strings, decimals or dates needs a transcription step (as AoC does) or a richer loader.
  2. Output capture. Results come back via peek (one data line per row) or tail (a standing change stream), both as text on the session. A client that wants an export as data — a file, a typed channel — has nothing yet.
  3. The open-loop regime. tick n sync=k is a dozen lines in the server but blocked in DD's dynamic scope as above.
  4. Sharded loading of large files. Every worker reads the whole file and keeps its shard; fine at 2M rows, not at 200M.
  5. Programs over several inputs fill them one feed … from at a time; multi-input round-robin from one file (what EDGES_FILE did) is gone on purpose.
  6. Timely's own flags. The crate is configured by environment (DDIR_WORKERS, DDIR_BACKEND, bind addresses); anything execute_from_args used to take (-w, -n, -p, hosts) is not reachable, so multi-process runs are not either.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QDsLC46QQW9aBrksaWad6T

frankmcsherry and others added 2 commits September 4, 2026 09:22
…harness

The single-program harness (`examples/ddir.rs`) duplicated the server's job:
build one dataflow, fill its inputs, close epochs. The server now covers what
the harness did, and the harness is gone.

- `load <prog> <in#> <recipe-or-file>` bulk-loads a positional input, sharded
  across the workers, from a `random:`/`iota:` recipe or a file of integer
  rows. A `churn=C` recipe keeps changing the input on every `tick` — the
  harness's batch/rounds loop — through the same per-input generator that
  drives generated sources (now one map per program, not one slot).
- `tick [n]` closes several epochs and reports the wall-clock time.
- `--backend=vec|corgi` selects the substrate for the whole server.
- `install … explain=<arity>[,debug]` applies the explanation rewrite; the
  query is an ordinary `feed` of the extra input, the demand sets are `peek`s.
- `server::evaluate` is the data-in/data-out entry point the test suites use:
  install, feed, tick, snapshot — the path a live install takes. It replaces
  the vec and corgi backends' private `evaluate` harnesses, so the corgi gate
  (at 1–4 workers and over serializing channels) and the explanation tests all
  run against the server on both backends.
- The AoC suite drives the server: `run.sh [vec|corgi]`. vec 33/33; corgi 32/33
  (day13 part 1 crashes corgi, as it did before).

Also dropped: `survey_sources` (only the harness used it) and the
`diagnostics` dev-dependency (only the harness's `--diag` used it).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QDsLC46QQW9aBrksaWad6T
`if(1, $1, 0)` is the idiom for carrying a collected List as one field (a bare
`$1` would splice it). Corgi's typer demanded that both branches share a
shape, so the dead `0` made the whole program a type error — AoC day 13 part 1
was the one part corgi could not run. With a literal condition the taken
branch is known, so only it is compiled; the vec backend evaluated it that way
already. Pinned by `tests/programs/if_literal.ddp`; AoC is now 33/33 on both
backends.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QDsLC46QQW9aBrksaWad6T
frankmcsherry and others added 2 commits September 5, 2026 17:21
The live server crate (`interactive/server`, the networked `ddir_server`)
matches every server command exhaustively, so the new `Command::Load`
variant broke its build. It now handles it: `feed <prog> <in#> from
<recipe-or-file>` fills an input from a source the server reads itself, each
worker taking its shard, so no row crosses the wire. The example driver's
command is spelled the same way (it was `load`, which in the live server's
protocol means install). A parser test and a four-worker integration step
cover it; the AoC suite passes on both backends with the new spelling.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QDsLC46QQW9aBrksaWad6T
…driver

Two front ends drove `interactive::server`, both building a binary named
`ddir_server`: the stdin/script example driver (a Sequencer and a 1 ms poll)
and the live `ddir-server` crate (stdin, TCP and WebSocket sessions, request
ids, `tail`; parks between commands). The crate is the superset, so the
driver's four remaining abilities move into it and the driver is deleted:

- `load <name> from <path> [explain=<arity>[,debug]] [name=binding ...]`
  installs a program file (`.ddp` pipe syntax, else applicative), read on
  the session thread like an inline body. `explain=` applies the explanation
  rewrite before optimization, replacing the reserved `--explain`; the query
  input is the one after the program's own, the demand sets its exports.
- `peek <trace> [key]` filters to one key (the dispatch already could).
- `tick [n]` reports the wall-clock time alongside the epoch.
- The crate installs the same global allocator the driver ran on.

The session scripts, the AoC suite and the READMEs pipe into
`cargo run -p ddir-server` (`DDIR_WORKERS`, `DDIR_BACKEND`); every session
replays, AoC is 33/33 on both backends, and end of input stops the server.
`install` is spelled `load` throughout, the crate's word.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QDsLC46QQW9aBrksaWad6T
Each worker validated only the lines of its own shard, so a malformed line
failed the load on the worker that held it while the other workers applied
theirs — and worker 0, whose result is the one the client sees, could report
"loaded 4 rows" over partial data (two workers, lines 1 / bad / 3 / 4: only 1
and 3 arrived). Every worker now parses the whole file before it applies
anything, so a malformed line fails the load on every worker and no row of the
file is fed anywhere; the workers agree because they read the same file.
Tested at two and three workers.

Reported by review on #858.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QDsLC46QQW9aBrksaWad6T
@frankmcsherry
frankmcsherry merged commit c33b0fd into master-next Sep 5, 2026
6 checks passed
@frankmcsherry
frankmcsherry deleted the server-examples branch September 5, 2026 22:23
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.

1 participant