- README: shipped concurrency/HTTP/WebSockets sat in the roadmap as "not yet available"; "no package manager" contradicted [deps]; the deps example would not have compiled (the key IS the module name) - runtime/README: leads with wovm, wo-rt.c demoted to a historical section; dropped 2 nonexistent recipes, crates/rt, @gc refcounting, 13 suites -> 18 - employee + log-watcher READMEs claimed "does not compile"; both are gates - error catalog: +10 emitted codes incl WO-E250, the only diagnostic the shipped query surface raises; recorded why the sweep rotted - language-surface: group-by parses, then the typechecker refuses it - 00-code-review + 00-link-audit re-run; history kept, not rewritten - 48 dead Rust-era exploration links de-linked rather than re-pointed (their prose names the retired plan by number); successor map -> discarded.md - 08-project-structure: compiler/plan/ never existed; corpus has 9 dirs, 5 empty - releasing.md: dropped a --draft step the workflow never had - new docs/00-doc-audit.md: findings + disposition, incl one row where the audit was wrong and the doc it accused was right - status folders removed: 34 stories flat, status only in frontmatter; 252 links recomputed from resolved paths; board/board-views/structure retaught - story 24 -> in-progress, since frontmatter is now the only truth - new iteration 38: fs mutation verbs + net.connect, the two capability families no iteration owned - new iteration 39: gofiber/fiber v3.5.0 parity study. The ledger called CSRF/sessions unblocked by iteration 34's HMAC, but the runtime has no source of randomness at all - linkcheck skips .dev/.superpowers: 0 broken paths, 0 bad anchors Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
90 lines
7.1 KiB
Markdown
90 lines
7.1 KiB
Markdown
# 02 — The end goal: the writeonce single binary on this runtime environment
|
||
|
||
**Context sources:** [`00-plan.md`](00-plan.md) (the runtime-environment phases, A–B ✅), [`01-architecture.md`](01-architecture.md) (the one-address trace), `../../../runtime/wo-language.md` ("one binary per project; no runtime to install on the target host"; `.wo` has "its own lexer, parser, analyzer, and bytecode"), `../../09-concurrency-scaleout.md`–`12` (the Rust product track this proves out), `../../../runtime/database/02-wo-language.md` (catalog + transaction semantics the payload carries).
|
||
|
||
## The end goal, stated once
|
||
|
||
> A developer writes `.wo` files. `wo build` emits **one static binary**. That binary **is** the runtime environment described in this track — thread-per-core shards, the mlock'd RAM arena, io_uring event loops, WAL dual-write, boot-time recovery — with the application **inside it** as data and bytecode. Deploy = copy one file to a Linux host. Nothing to install; the only "VM" underneath is the Linux kernel.
|
||
|
||
This resolves the phrase "runs **in** this runtime environment": writeonce is the **Go model, not the JVM model**. The environment is not a process you start and feed programs to — it is a **runtime kernel** statically linked into every application binary. What `wo-rt-c` builds phase by phase is that kernel, proven in C, ported to Rust per plans 09–12.
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph BIN["ONE BINARY (output of `wo build`)"]
|
||
subgraph APP["application payload — compiled from .wo"]
|
||
CAT["catalog<br/>types/classes → slot geometry"]
|
||
RT2["route table<br/>service decls → method+path+op"]
|
||
BC["logic bytecode<br/>fn methods, triggers, queries"]
|
||
UIA["UI assets<br/>SSR templates + manifest + CSS"]
|
||
end
|
||
subgraph KERN["runtime kernel — this track"]
|
||
BOOT["boot loader<br/>size arena from catalog, WAL replay"]
|
||
SCHED["shard scheduler<br/>thread-per-core, SO_REUSEPORT"]
|
||
LOOP["event loops<br/>epoll → io_uring"]
|
||
ENG["engine primitives<br/>arena slots, bitmaps, indexes"]
|
||
WAL["commit pipeline<br/>RAM apply → WAL → group fsync → ack"]
|
||
HTTP["HTTP + WS"]
|
||
end
|
||
end
|
||
LINUX["Linux kernel — epoll/io_uring, mmap/mlock, signalfd/eventfd, page cache"]
|
||
APP -->|"consumed at boot<br/>and at dispatch"| KERN
|
||
KERN --> LINUX
|
||
```
|
||
|
||
## The embedding contract
|
||
|
||
The seam between the two halves is narrow and data-shaped — the compiler emits **tables**, the kernel consumes them. Five entries:
|
||
|
||
| Payload artifact | Emitted from | Consumed by | Exists today as |
|
||
| --- | --- | --- | --- |
|
||
| **Catalog** — per type/class: field layout, slot size, unique keys, shard key | `type`/`class` decls (`crates/rt/src/compile.rs`) | boot loader: arena geometry (`arena_hdr` is its miniature); engine: row codecs | `rt::compile::Catalog`, built per `wo run` |
|
||
| **Route table** — `(method, path pattern, operation, type id)` | `service` blocks | HTTP dispatch | `rt::server::router` |
|
||
| **Logic bytecode** — method/trigger/query programs | `fn` bodies, `on` blocks, schema-layer DML | a bytecode interpreter running **inside the owning shard's thread** — serial execution = ACID isolation for free | parse-and-discard (13b lands the executor) |
|
||
| **UI assets** — SSR templates, manifest, flattened CSS, `wo-runtime.js` | `##ui` triplets (plan 14) | HTTP static + SSR renderer | design (plans 13d/14) |
|
||
| **App manifest** — name, version, default port/threads | `wo.toml` | boot banner, env-var defaults | `wo.toml` parsing TBD |
|
||
|
||
Two consequences worth locking:
|
||
|
||
1. **The shard key comes from the catalog, not the kernel.** `wo-rt-c` hashes connections (4-tuple) because it has no catalog; the product routes *operations* by the catalog's shard key (plan 09 decision 5: customer id, author id) — a request landing on any thread sends an in-process message to the owning shard. Phase A's `SO_REUSEPORT` spread is the transport layer of that story, not the final routing.
|
||
2. **Bytecode runs where the data lives.** A `set_price` method executes on the shard that owns the product row — the interpreter is invoked from the event loop, runs to completion, commits through the WAL pipeline. No cross-thread data access; cross-shard transactions escalate to 2PC (plan 09e).
|
||
|
||
## Boot sequence of the single binary
|
||
|
||
What `./myapp` does before serving — each step already prototyped or phased:
|
||
|
||
| # | Step | Proven by |
|
||
| --- | --- | --- |
|
||
| 1 | Read embedded catalog → compute arena geometry (shards × slot families) | `arena_hdr` (phase B ✅) |
|
||
| 2 | `mmap` + `MAP_POPULATE` + `mlock` the arena (hugepages, 4 K fallback) | phase B ✅ |
|
||
| 3 | Replay per-shard WAL/snapshot from disk into the arena, in parallel | phase E |
|
||
| 4 | Spawn `WO_THREADS` pinned shard threads, each with ring + `SO_REUSEPORT` listener | phase A ✅ / phase C |
|
||
| 5 | Install route table + bytecode programs per shard | 13b / this contract |
|
||
| 6 | Listeners open; signalfd→eventfd shutdown armed | phase A ✅ |
|
||
|
||
Steps 1–2 and 4–6 exist in `wo-rt-c` today with the notes store standing in for the catalog. The end state swaps the hard-coded `slot_note` for catalog-driven slot families — the kernel code does not otherwise change shape.
|
||
|
||
## What runs where — `.wo` construct → runtime home
|
||
|
||
| `.wo` construct | At runtime, inside the binary |
|
||
| --- | --- |
|
||
| `type` / `class` fields | a slot family in each shard's arena slice |
|
||
| `class` `fn` methods | bytecode executed serially in the owning shard's thread (`POST /api/<t>/:id/<m>`) |
|
||
| `service rest … expose` | route-table entries dispatched by the HTTP layer |
|
||
| `on <event>` triggers | bytecode hooked into the commit pipeline, same transaction |
|
||
| `LIVE select` / `subscribe` | per-shard subscription registry; deltas fan out one message per shard (09d) |
|
||
| `##ui` screens | SSR render + manifest at GET routes; live patches ride the same deltas |
|
||
| `policy` rules | predicate rewrites applied before the engine touches slots |
|
||
| `main { … }` | bytecode run once at boot step 5½, before listeners open |
|
||
|
||
## Division of labor (locked by the C-vs-Rust decision)
|
||
|
||
- **`wo-rt-c` (C)** — proves each kernel syscall sequence first: threads/arena (✅), io_uring, WAL, recovery, bench. It will never parse `.wo`; its notes store is the stand-in payload.
|
||
- **`crates/rt` (Rust)** — the product: owns the compiler front-end today (lexer→catalog, Stage 2 shipped) and absorbs each proven kernel sequence per plans 09–12, where ownership makes the shard discipline a compile-time guarantee.
|
||
- **Optional phase G** (named in [`00-plan.md`](00-plan.md)): splice the `wo-db` C++ query engine onto `wo-rt-c` as an end-to-end C-family demonstrator of this document — valuable as proof, never the product.
|
||
|
||
## Cross-references
|
||
|
||
- [`00-plan.md`](00-plan.md) — the kernel phases; [`01-architecture.md`](01-architecture.md) — the one-address trace through the same stack.
|
||
- [`README.md`](../../../../README.md) — the user-facing single-binary promise this document implements.
|
||
- `../../13-class-model-live-pricing.md` (13b methods) — the payload-side track.
|
||
- `../../09-concurrency-scaleout.md` — shard-key routing and 2PC the contract defers to.
|