Wire packed read path through ReadPlan (ADR-011 steps 2-4, plan phase 2)
SequentialReader now walks Arc<ReadPlan> instead of re-parsing the BAST typed tree per field (the 400x read-path gap, review #004 H1); materialize_packed walks the same plan, unifying the two packed read-side consumers on one compiled form. - SequentialReader::new(Arc<ReadPlan>) -> Self, infallible: the fallible BastDoc parse moved to ReadPlan::compile (phase 1). The reader holds the plan Arc + cursor state only; schema() returns the Arc<Value> retained on the plan (review #005 H2 — no self-referential struct); new plan() accessor exposes the shared plan. - ReadPlan carries schema: Arc<Value> (set at compile; sub-plans hold a Null placeholder — only the root plan is handed out). - materialize_packed(&ReadPlan, &[u8]): plan-walking packed materializer. The aligned path keeps walking BastDoc with the retained dummy_field_for/ty_source/materialize_typeref_packed helpers (phase 5 Scope Boundary: aligned structure walk is the permanent 0.3.0 design). - Engine: Layout::Packed stores Arc<ReadPlan> alongside the builder; sequential_reader() is an Arc::clone (was a full-document Value clone); packed validate_bytes calls materialize_packed(&self.plan). - Stride (deferred decision 4): FieldValue::Array now reports the true stride for fixed-size struct/nested-array elements (0.2.0 returned 0); doc comment documents the behavioral change; no existing test asserted the 0, so none needed changing. - Two parity subtleties found and preserved: (a) materialize_plan_composite unwraps the plan's anonymous single-field wrapper for primitive array elements/record values — without it, materialized records nest each leaf under a synthetic object (caught by the record parity test); (b) field-disc unions keep 0.2.0's materialized key order (__discriminator first), observable under preserve_order. Both are now covered by plan-phase tests or construction. Bench (alktty wire_vs_bast, 1024 chunks/stream): packed read 2.27 us/chunk (review #004) -> 98 ns/chunk p64 / 100 ns/chunk p4k (~23x; the 400x gap closes to ~17x vs hand-rolled 5.6 ns/chunk). Residual gap is the per-field String allocation mandated by the unchanged (String, FieldValue) read_next signature (2 allocs/chunk) plus data_access bounds checks. sequential_reader() construction: 15.7 ns (was a whole-document clone). Verification: 465 tests pass unchanged (the existing reader/ materialize/engine suites drive the rewrite through the public API — only constructor call sites moved to ReadPlan::compile); clippy -D warnings clean; cargo doc zero warnings; wasm32 release build green.
This commit is contained in:
1 parent
ff85258d03
commit
e5f1b9d825
8 files changed
+1101
-644
No files matched your search
@@ -214,7 +214,51 @@ Sync` so a future change can't break it silently — mirror the POC's
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — `SequentialReader` + `materialize_packed` consume `ReadPlan` (ADR-011 steps 2–4)
|
||||
## Phase 2 — `SequentialReader` + `materialize_packed` consume `ReadPlan` (ADR-011 steps 2–4) — **DONE (2026-09-02)**
|
||||
|
||||
> **Status: implemented.** The packed read loop walks `Arc<ReadPlan>`:
|
||||
> `SequentialReader::new(Arc<ReadPlan>) -> Self` (infallible; the old
|
||||
> fallible constructor's work moved to `ReadPlan::compile`), the reader
|
||||
> holds `plan: Arc<ReadPlan>` + cursor only, `schema()` returns the
|
||||
> `Arc<Value>` retained on the plan (review #005 H2 closed — no
|
||||
> self-referential struct), and a new `plan()` accessor exposes the
|
||||
> shared plan. `materialize_packed(&ReadPlan, &[u8])` walks the same
|
||||
> plan; the aligned materialize path keeps walking `BastDoc` with the
|
||||
> retained `dummy_field_for`/`ty_source`/`materialize_typeref_packed`
|
||||
> helpers (phase 5 Scope Boundary). Engine: `Layout::Packed` carries
|
||||
> `Arc<ReadPlan>`; `sequential_reader()` is an `Arc::clone` (15.7 ns,
|
||||
> was a whole-document `Value` clone); packed `validate_bytes` calls
|
||||
> `materialize_packed(&self.plan, ...)`. The temporary validation
|
||||
> bridge (reconstruct `BastDoc` for the validator) is still in place —
|
||||
> phase 7 already retired it on `main`'s ValidationPlan; this phase's
|
||||
> `validate_bytes` edit merged cleanly onto that state.
|
||||
>
|
||||
> **Stride (deferred decision 4):** fixed struct/nested-array elements
|
||||
> now report their true stride through `FieldValue::Array`
|
||||
> (0.2.0 returned `0`); doc comment updated; no existing test asserted
|
||||
> the `0`, so no test needed changing — the plan-compile tests lock the
|
||||
> new values.
|
||||
>
|
||||
> **Two parity subtleties found and preserved** (both invisible to the
|
||||
> existing test suite, both now locked by tests or by construction):
|
||||
> (a) the materializer unwraps the plan's anonymous single-field
|
||||
> wrapper for primitive array elements/record values — without this,
|
||||
> materialized records/arrays would nest each leaf under a synthetic
|
||||
> object and `validate_bytes` would fail its own parity suite (caught
|
||||
> by `materialize_record_packed_count_prefixed_pairs`); (b) the
|
||||
> field-disc union's materialized key order keeps `__discriminator`
|
||||
> first (matching 0.2.0's `Map` insertion order, observable under
|
||||
> `preserve_order`).
|
||||
>
|
||||
> **Bench (alktty `wire_vs_bast`, 1024 chunks/stream):** read p64
|
||||
> 2.27 µs/chunk (review #004) → **98 ns/chunk** (~23x; gap 400x →
|
||||
> ~17x vs hand-rolled's 5.6 ns); read p4k → 100 ns/chunk. `engine.
|
||||
> sequential_reader()` construction 15.7 ns (was a full `Value` clone).
|
||||
> The residual gap is dominated by the per-field `String` allocation
|
||||
> mandated by the unchanged `(String, FieldValue)` `read_next` return
|
||||
> signature (2 allocs/chunk) plus `data_access` bounds checks — both
|
||||
> outside this phase's scope (the signature is pinned by the Semver
|
||||
> Contract).
|
||||
|
||||
**Goal:** Rewrite the packed read loop to walk `&ReadPlan` instead of
|
||||
reconstructing `BastDoc`. `SequentialReader` stores `Arc<ReadPlan>` +
|
||||
|
||||
Reference in new issue
Block a user