OverviewFilesCommitsIssuesDocsReleasesPeers

keet-daemon commits / d001927

design: R4b (rn/: rocksdb-native ported in full; streamx generalized to object mode; parked completions; gate at UV_THREADPOOL_SIZE=1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d001927cc8e43e11c41d77f1eaae91fb6ee066b6
by plankatron <fleeky@gmail.com> · 2026-10-06T16:17:04.000Z

Changed files (1) +57 -0

docs/CPP-PORT-DESIGN.md +57 -0
……@@ -3543,6 +3543,63 @@ injected per layer:
35433543 from that destroy).
35443544 - **Next: R4b** (rn/: rocksdb-native's JS layer over librocksdb's async mode, completions
35453545 inline for now, the drain scaffold for unconverted callers).
3546- **R4b DESIGN (2026-10-06; approved by the user 2026-10-06).** Read in full first: rocksdb-native
3547 3.17.4 (index.js, lib/*, binding.cc), ready-resource 1.2.0, refcounter 1.0.0,
3548 resolve-reject-promise 1.1.0, signal-promise 1.0.3, librocksdb 1a00e82's rocksdb.h.
3549 - **Measured on Bare 1.28 (scratch probe tp1.js):** overlapping read batches complete out of
3550 submission order 277 / 302 times in 1000 adjacent pairs with the default pool, and 0 / 2000
3551 with `UV_THREADPOOL_SIZE=1`. Bare honours the variable; one pool thread is FIFO by
3552 construction. That is the gate's JS reference, unpatched.
3553 - **What gets ported (all of it, the 100 % rule):**
3554 - `rn::RocksDB` (index.js): sessions (`session` / `columnFamily` / `snapshot`, the index-swap
3555 session list), `ready`, `close({ force })`, `suspend` / `resume`, `isIdle` / `idle`,
3556 `iterator`, `keys` (an async generator: an iterator object over `iterator`), `peek`,
3557 `read` / `write` (batches), `flush`, `get` / `put` / `delete` / `deleteRange` (one-op
3558 batches, their exact `async` shapes), `compact`, `compactRange`, `approximateSize`,
3559 `currentWalFile`, `get/setStatsLevel`, `getProperty`, `diagnostics`, `stats`,
3560 `maybeClosed`, key / value encodings (a codec hook: encode / decode over bytes, as M5g-4a).
3561 - `rn::State` (lib/state.js) on literal ports of ready-resource (open / close, `opening` /
3562 `closing`, 'ready' / 'close'), refcounter (`io`, `handles`, `idle()`), signal-promise
3563 and resolve-reject-promise: column-family upsert / lookup, `_open` (the
3564 `await Promise.resolve()`, the lock's `ready` / `transfer` / `close`, deferred snapshot
3565 init), `_close` (updating wait, io / handles idle, sessions, CF destroy), suspend /
3566 resume / `update` / `waitForResume`, flush, compact, compactRange, approximateSize,
3567 currentWalFile, the batch reuse pools (capacity ≤ 16, at most 64).
3568 - Batches (lib/batch.js): ReadBatch / WriteBatch, `_reuse`, `ready`, `flush` / `tryFlush`
3569 (the one-hop submit), `_onread` / `_onwrite` (per-op resolution in index order, then the
3570 flush promise; AggregateError / `Batch was not applied`), `_abort`, `destroy`, `try*`,
3571 `_resize`, stats.
3572 - Iterator (lib/iterator.js): a streamx Readable in object mode, capacity 8, the
3573 `_open` / `_read` / `_destroy` shapes, `limit`, keys-only, ranges.
3574 - Snapshot, ColumnFamily (+ `cloneSettings`), Bloom / Ribbon filter policies, constants.
3575 - binding.cc's glue: librocksdb options and CF descriptors, the lock fd hand-over (closed if
3576 open fails to submit), errors as `Error(message)` with `code = uv_err_name(status)`, a
3577 missing key = null vs an empty value = a zero-length buffer, the idle callback that
3578 destroys the remaining CFs and snapshots on close. Process-exit teardown (`exiting`) has
3579 no keetd equivalent and is not ported.
3580 - **streamx, generalized:** the Iterator is an object-mode Readable, and streamx counts an
3581 entry as `byteLength(entry)`: its length for a typed array, else 1024 (`defaultByteLength`),
3582 after `map` (applied at push). That decides when `_read`, an iterator refill, runs.
3583 `ss::Duplex` becomes `ss::BasicDuplex<T>` with streamx's `byteLength` and `map` options
3584 (`Duplex = BasicDuplex<Buf>`, its API unchanged); `ss::AsyncIterator` likewise. The duplex,
3585 secret-stream and interop gates must stay identical; the duplex gate gains object-mode
3586 scripts. (hypercore-storage sets `_readableState.map` on every stream: R4c needs `map`.)
3587 - **Completions in R4b, both runtimes, as the R4 migration says:** librocksdb runs in SYNC
3588 mode on the loop thread at the moment JS calls the binding (the work is done at submit);
3589 its completion is PARKED in a new rt completion FIFO and delivered in the next poll phase,
3590 one native callback each (`rt::callback`: its own checkpoint), as `uv__work_done` delivers
3591 one JS call per completed work item. Real: a `uv_async_t`; Virtual: the poll phase;
3592 `alive` counts parked completions. R4i swaps Real to librocksdb's async mode on
3593 `rt::uvLoop()` (the real pool) and gives Virtual its scripted order.
3594 - **Gate `tools/rn`:** op scripts (batches, one-op calls, iterators, sessions / snapshots,
3595 suspend / resume, close, errors) run on Bare's rocksdb-native at `UV_THREADPOOL_SIZE=1` and
3596 on rn over rt real AND virtual. Each trace logs every per-op settlement, batch flush, iterator
3597 entry and event, beside a microtask ruler (hops); then the stores are dumped and compared.
3598 Scripts never order a storage completion against a timer or an immediate (pool timing).
3599 Then a drill.
3600 - **Order:** R4b-1 streamx generalized (gates unchanged + object mode) → R4b-2 rt completion
3601 FIFO + State / batches / sessions / snapshots / CFs → R4b-3 Iterator, `keys`, `peek` →
3602 R4b-4 gate + drill. L2 keeps its synchronous Db until R4c.
35463603- **Then 4e-4** (`createProtocolStream` / `replicate`): the first gate that composes the stack
35473604 is a COMPOSED trace against JS (secret-stream + protomux + replicator), now meaningful.
35483605