Skip to content

feat(ingest): add opt-in streamed file preparation - #464

Merged
beinan merged 2 commits into
mainfrom
codex/wal-streamed-preparation-public
Oct 22, 2026
Merged

beinan merged 2 commits into
mainfrom
codex/wal-streamed-preparation-public

Conversation

@beinan

@beinan beinan commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Materializers currently fetch and decode an entire pinned publication before starting Lance file writers. Add an experimental, default-off worker.publication.pipeline_preparation option that feeds bounded Arrow streams into Lance 13 writers as records become available, without payload reserialization.

Both paths preserve the same immutable plan, whole-record partitioning and complete descriptor aggregation. Writers share fetch/decode permits; blocking decode retains its permit and source reservation through cancellation, and all admitted writers finish before a failure is returned. No partial descriptor set can be prepared or published.

This distributes preparation within one worker only. Lance encoder workspace remains outside the source reservation, streamed blob_write timing includes source waiting, and no throughput improvement or end-to-end zero-copy is claimed. A matched short cloud comparison completed full payload and aggregate checks before and after restart in both modes. In the common 60–150 second window, buffered publication was 60.17–60.63 MiB/s and streamed publication 57.23–57.87 MiB/s. Including drain, the respective rates were 52.62–54.15 and 57.33–59.05 MiB/s. These are one-run sampling/clock bounds, not statistical confidence or sustained capacity; initial leaders differed and the streamed run experienced term changes. The results do not establish a steady-window throughput improvement or support enabling the option by default.

Testing

  • Workspace formatting, all-target Clippy and Rust tests.
  • Python pytest: 229 passed, 2 skipped, 1 xfailed; Ruff formatting/lint and Pyright. The server executable was rebuilt from this source; the unchanged Python native extension was reused after checking its source inputs.
  • Service/http-client all-target Clippy and 10 feature tests, including real WAL/Lance recovery in both modes and injected stream failure with observer cancellation.
  • Both modes passed release-process qualification: 192 MiB ACKed but unpublished, all nine WAL processes killed, original directories reopened, then one Lance publication with complete payload, aggregate-row, read-only and negative-verifier checks; no producer replay.
  • A separate streaming-mode process test replaced one replica directory with an empty directory after the crash. Its group payloads were fetched exclusively from the rebuilt replica and all data checks passed. This is local directory-loss simulation, not a Kubernetes volume-loss qualification.

Refs #378. Built on merged #463 and #465. The streamed materializer implementation matches the qualified candidate; the base additionally contains the engine directory-lock fix #465. A test helper is additionally gated to the features that use it; materializer-only and service/http-client all-target Clippy pass with that correction.

Validation follow-up: the HTTP test publisher helper is compiled only with http-client, matching its callers. Local all-target Clippy passes with worker, materializer, and http-client,materializer separately; production code is unchanged by this test fix. Final-head CI must pass before merge.

@beinan
beinan changed the base branch from codex/wal-materializer-phase-metrics to main October 22, 2026 08:36
@beinan
beinan force-pushed the codex/wal-streamed-preparation-public branch from befea08 to a28e13e Compare October 22, 2026 08:36
@beinan
beinan merged commit 856143d into main Oct 22, 2026
14 checks passed
beinan added a commit that referenced this pull request Oct 22, 2026
## Summary

A single managed table currently prepares all of its files inside one
publishing worker, so adding workers does not parallelize that table's
data preparation. Add an opt-in Rust `preparer` role that divides one
immutable, pinned publication plan across bounded remote services. Each
service reads its assigned records directly from WAL and passes Arrow
handles into the existing Lance writers. The publisher exchanges only
plan references and fragment metadata, joins every partition and records
the complete aggregate through the existing durable Prepare and fenced
publication protocol.

The services resolve the deployment-authorized table registry, verify
the exact plan and source pins through quorum reads, and use
authenticated bounded requests, job slots, memory reservations and a
volatile result cache. Admitted jobs survive disconnected observers. A
missing or failed partition cannot publish a partial result; after
durable Prepare, recovery needs no preparer cache. Losing a cache
earlier may redo unpublished immutable files under the existing
orphan-cleanup contract.

The option is disabled when `preparation` is absent. This changes no WAL
wire format or Lance OSS code. It does not provide orphan deletion, a
hard bound on Lance encoder RSS, or a demonstrated throughput
improvement.

## Testing

- Integration coverage uses two authenticated HTTP services over real
TLS WAL and Lance files: missing-service failure, healthy-partition
cache reuse, disjoint source reads, complete aggregate recovery after
both caches disappear, and full payload verification.
- Independent release-process qualification passed: two producers
acknowledge 192 MiB before publication, all nine WAL processes are
killed and reopened, one preparer is missing, and its completed sibling
is killed to lose its cache. Restarting both preparers publishes all 64
original records exactly once with complete payload, aggregate-count,
read-only and negative-verifier checks and no producer replay. All
source reads, decodes and file writes occur in preparers; publisher
counters remain zero. This is local process recovery, not Kubernetes
volume-loss qualification.
- Materializer-only and service/http-client all-target Clippy passed.
Feature tests: 11 passed, 3 external-process fixtures ignored by the
ordinary run. Workspace formatting, all-target Clippy and Rust tests
passed, as did Python pytest (229 passed, 2 skipped, 1 xfailed), Ruff
and Pyright. Unchanged native/server artifacts were reused after
verifying source inputs and hashes. Final-head CI and prerequisite
merges are still required.
- Kubernetes 1/2/4-preparer scaling is queued behind the current
qualified-control experiment. No distributed throughput result or
sustained-capacity claim yet.

Refs #378. Built on merged #464 and #465. The distributed preparation
implementation matches the independently qualified release; the base
additionally contains the engine directory-lock fix #465 and
prerequisite test-helper feature gate. Final-head CI validates that
combined source.

Feature-only validation also covers the test fixtures with `worker` and
`service` enabled independently, including the actual preparer recovery
test.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant