server: a query that finds every permit taken waits for one instead of failing, the budget is 64, permit and upstream turns wait on a futex with one thread each, the thread pool has no task limit, and transparent huge pages are off for the process
This commit is contained in:
@@ -56,7 +56,8 @@ Serves a household LAN (≈2–20 devices). Portfolio-grade public repo with ext
|
||||
Zig 0.16 stdlib is built on the `std.Io` interface: `std.Io.net` owns networking (`std.net` in its old form is gone) and `std.http.Client` requires an `io: Io`. Therefore:
|
||||
|
||||
- **`Io` is the injected platform abstraction.** Every component that does I/O takes `io: Io`. No project-owned wrapper interfaces around it — a second abstraction over an abstraction with one consumer is waste.
|
||||
- **Backend: `std.Io.Threaded`** — the mature, debuggable path; at ≤20 devices throughput is a non-issue. The originally planned io_uring config flag was dropped in milestone 11: `std.Io.Evented` at Zig 0.16.0 stubs the networking a server needs — listen, accept, connect, lookup, and stream reads/writes return `error.NetworkDown` (`Uring.zig` netListenIp/netAccept/netConnectIp/netRead/netWrite) — so a selectable backend would boot a dead server. The code stays backend-agnostic by construction; revisit when std ships working evented networking.
|
||||
- **Backend: `std.Io.Threaded`** — the mature, debuggable path; at ≤20 devices throughput is a non-issue. The originally planned io_uring config flag was dropped in milestone 11: `std.Io.Evented` at Zig 0.16.0 stubs the networking a server needs — listen, accept, connect, lookup, and stream reads/writes return `error.NetworkDown` (`Uring.zig` netListenIp/netAccept/netConnectIp/netRead/netWrite), and a receive inside a batch panics with `TODO` — so a selectable backend would boot a dead server. A replacement or hybrid backend of our own would bring runtime-level scheduling, cancellation, timer and transport adapters whose complexity is out of proportion to a household workload, so nxdns stays on `std.Io.Threaded`.
|
||||
- **Work is bounded where it enters, not in the thread pool** (specs/memory-budget.md item 3). Every DNS listener draws from one budget of 64 query permits, and each stream listener accepts at most 16 connections. A query that finds no permit waits for one rather than being dropped or answered SERVFAIL; UDP's backlog stays in the kernel socket buffer, whose drops are exported. The `Threaded` pool has no task limit and grows to the peak the bounds allow; its workers are never retired. Waits for a permit sleep on a futex with a deadline, one thread each.
|
||||
- No hand-written thread pool. `Io` async/concurrent/Group covers task management.
|
||||
- Core domain modules (`dns`, `filter`, `cache`) stay pure: no `Io`, no sockets — bytes in, bytes out. Only servers, upstream clients, and storage touch `Io`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user