Parents and children of check-in [5401ce245f]
|
2026-07-20
| ||
| 04:40 |
Merge h11-serve-socket: a stalled client can no longer wedge the server
zit serve accepts one connection at a time and read its request head and body with no deadline, so a single peer that opened a connection and then dribbled or withheld its request pinned the accept loop and starved every other client -- a real availability gap the in-memory fuzzers could not see, since they never touch the socket. The connection now runs under a whole-connection deadline: the request work races a timed sleep, and a peer that misses the deadline is dropped so the loop moves on. The bind is loopback only and the deadline is generous, so a legitimate request -- even at the reply ceiling -- always finishes far inside it; only a stalled peer is shed. Four end-to-end abuses -- a slow-loris head, a half-sent body, a mid-response disconnect, an idle-connection burst -- each prove the server still answers a fresh request and a real clone still converges, and the fix is shown to be load-bearing by wedging with it removed. A per-read idle timeout and a configurable value are left for later. check-in: 56c17d0675 user: dmestas tags: trunk | |
| 04:37 |
Prove sync liveness under a degraded, never-healed wire
The sync sweep proved convergence only after the network fully healed, so a protocol that converges on a perfect wire but livelocks under sustained loss would still pass. Phase 2b runs a fresh session over a wire held at a fixed drop/dup rate, never healed, asserting the same convergence and termination oracles within a window scaled from the loss rate: expected rounds are the clean window over (1 - p_loss) squared per direction, times a safety factor, recomputed in a comment rather than a magic number. No corruption is injected -- a corrupted body is already a lost round. The protocol converges comfortably: over 200 seeds the worst run took 7, 13, and 18 rounds at 10, 25, and 40 percent loss, against windows of 160, 228, and 356 -- no livelock. The gate joins at 10 percent; the soak sweeps the wider rate set. Pinning the window below the real need trips the liveness oracle, so the check is not vacuous. The liveness-under-faults discipline follows TigerBeetle's VOPR. check-in: 464b82c888 user: dmestas tags: h7-degraded | |
| 04:34 |
serve: bound each connection so a stalled client cannot wedge the server
zit serve accepts one connection to completion before the next (single-threaded, serve.zig), and receiveHead plus the body read blocked with no deadline. A loopback peer that dribbles a request head, half-sends a body, or connects idle and holds could pin the accept loop forever -- the socket read path the exchange fuzzers never reach, covered before only by happy-path interop. Add a whole-connection deadline: the request work runs on its own unit of concurrency raced against a timed sleep, and draining the loser cancels the blocked read, freeing the loop. A per-read SO_RCVTIMEO is unusable here (the Io backend treats a socket-timeout EAGAIN as a bug). serve binds 127.0.0.1 only, so a legitimate same-host request finishes in milliseconds even at the 512 MiB body ceiling; the 5 s bound never fires on a real client and only sheds a stalled one. Four end-to-end scenarios abuse a live server over loopback -- dribbled head, half-sent body, mid-response disconnect, idle-connection burst -- and assert with bounded waits that a fresh request is still answered and a clone still converges (sync 3.7). closed check-in: e87fb840d1 user: dmestas tags: h11-serve-socket | |
| 04:28 |
Merge h2-checkout-dst: crash-test the working tree, and a finding it surfaces
The working tree -- the one place a version-control tool can lose a user's data -- had no crash simulation; only the log store did. A new faulty directory layer tears and freezes writes at a seeded crash point, and a sweep replays an update across every crash cut, reopens, and checks four invariants. Three hold: an untracked file the update must preserve is never touched, a crashed update recovers to its target through the undo journal, and the checkout record never names a check-in whose tree did not finish materializing. The fourth does not, and that is the point of the harness: the payload write lands in place rather than through the write-temp-and-rename the metadata already uses, so a crash mid-write can leave a managed file spliced from old and new bytes -- torn, but recoverable. The gate runs the three that hold; the fourth is pinned by a test asserting the splice IS produced, so it flips the day the write is made atomic. Crash-point enumeration follows TigerBeetle's storage model. check-in: 5401ce245f user: dmestas tags: trunk | |
| 04:21 |
sim: working-tree crash-recovery DST sweep for update
Add sim/faulty_dir.zig, a decorator std.Io that cuts a run at a seeded mutating-op boundary the way a power loss does: the crashing write persists at most a torn prefix and every later mutation is a frozen no-op, so the checkout layer's own recovery moves no byte. Crash-point enumeration follows TigerBeetle's storage-fault-injection lineage, ported to the directory surface update.zig and checkout.zig write through. Add sim/checkout_sweep.zig: it materializes a check-in, replays an A-to-B update.applyCheckin under a crash at every reachable cut, reopens, and asserts unmanaged files are preserved, the checkout record names only a complete target, and the tree recovers to the target via the undo journal. Joins the dst gate per seed at bounded cuts; the soak walks every boundary. Finding: update.writePayload writes working files in place (createFile truncate, write, sync), not through the atomic write-temp+fsync+rename that checkout.write, the managed set, and the undo journal use. A crash mid-write can leave a file matching neither its pre- nor its post-image. The sweep pins this; a working-tree write-journal is the fix. closed check-in: 0cea021cf9 user: dmestas tags: h2-checkout-dst | |
| 04:19 |
Merge h3-crashsync: run a sync over a store that can tear, across crashes
The storage and network simulations ran off the same seed but never intersected, so no simulated exchange ever crossed a store that could lose its tail. This composes them: the sync client's content is backed by a real log over a tearable file, and between rounds -- on a seeded coin -- the store is crash-restarted mid-persist, reopened to its recovered prefix, and the session resumed with a fresh client. The existing safety and liveness oracles must survive the composition: no corrupt content accepted, the recovered set never exceeds what was held before the crash, and once both the network and the disk heal a fresh session still converges within the bounded window. Green across the gate and a deep 120-seed run; a retained switch that makes recovery accept a torn frame trips the oracle, so the check is not vacuous. The fault-composition follows TigerBeetle's VOPR. check-in: 9b689ebafe user: dmestas tags: trunk | |