Add REAPI content-defined chunking (SplitBlob/SpliceBlob) support#2497
Draft
erneestoc wants to merge 3 commits into
Draft
Add REAPI content-defined chunking (SplitBlob/SpliceBlob) support#2497erneestoc wants to merge 3 commits into
erneestoc wants to merge 3 commits into
Conversation
Implements the server side of the remote-apis blob split/splice extension used by Bazel's --experimental_remote_cache_chunking (Bazel 8.7.0+/9.1.0+), fixes TraceMachina#2496. - Vendor SplitBlob/SpliceBlob RPCs, ChunkingFunction, FastCdc2020Params and CacheCapabilities fields 8-12 from upstream remote-apis. - SpliceBlob re-assembles chunked uploads: verifies chunk existence and the spliced digest before committing, materializes the blob so non-chunking clients stay correct, and persists the chunk layout in a configurable index store. Chunk reads are pipelined while hashing stays in chunk order. - SplitBlob serves stored layouts (validated against the blob size so corrupt or truncated index entries are never served), or chunks blobs on demand with FastCDC 2020 (fastcdc crate, normalization level 2) so outputs uploaded whole by remote execution workers also get chunked downloads. Unusable layouts fall back to re-chunking. - Capabilities advertise split/splice support and FastCDC 2020 parameters per instance, collected across all server blocks, gated behind the new opt-in experimental_chunking CAS service config (off by default; zero behavior change when unset). - Reject foot-gun configs at startup: index_store == cas_store (chunk layouts stored under blob digests would overwrite blob content) and chunking on grpc proxy stores (would download/re-upload entire blobs instead of forwarding RPCs). - Conformance-test the chunker against the official REAPI fastcdc2020_test_vectors.txt (offsets, lengths, sha256s and gear fingerprints, seeds 0 and 666, in-memory and streaming). - Add ChunkingMetrics (splice/split totals, hit/miss/on-demand rates, byte counters, digest verification failures). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
For grpc-store-backed CAS instances the chunking RPCs are now forwarded verbatim to the backend (with instance-name rewriting and the store's usual retry handling) instead of being rejected at startup. This makes NativeLink relays transparent for content-defined chunking: one RPC in, one RPC out, the backend owns chunking and the layout index. - Add GrpcStore::split_blob/splice_blob following the existing find_missing_blobs/batch_*/get_tree forwarding pattern. - Shortcut to the proxy in the CAS handlers before any local chunking machinery is consulted, mirroring the other four CAS RPCs. - Make experimental_chunking.index_store optional: required for locally chunked instances, rejected for grpc-store instances where the backend owns the chunk layouts. The capabilities service still advertises split/splice + FastCDC params from the same config block, so relay operators set avg_chunk_size_bytes to match their backend. - Test forwarding against a fake CAS backend over a real gRPC round trip (verifies passthrough and instance-name rewriting) and the new constructor rules. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
- Reuse the FastCDC test fixture already vendored at nativelink-util/tests/data/SekienAkashita.jpg (and already excluded from the forbid-binary-files hook) instead of adding a duplicate binary copy; export it from nativelink-util for the conformance test. - Format nativelink-service/Cargo.toml per taplo. - Replace the hardcoded 50k chunk cap with a per-instance experimental_chunking.max_chunk_count knob (default 50000). Blobs above the cap are served without chunking; the layout read cap is derived from the configured count so the two can never disagree. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the server side of the REAPI blob split/splice extension (remote-apis#282) used by Bazel's
--experimental_remote_cache_chunking(Bazel 8.7.0+ / 9.1.0+).Fixes #2496.
What this adds
SplitBlob/SpliceBlobRPCs,ChunkingFunction,FastCdc2020Params,RepMaxCdcParams, andCacheCapabilitiesfields 8–12, verbatim from upstream remote-apis.SpliceBlobre-assembles chunked uploads: validates chunk sizes/counts, checks all chunks exist (touching them), streams them through an incremental hasher into the CAS with reads pipelined 10-at-a-time — the digest is verified before EOF so a mismatch aborts the upload uncommitted — then persists the chunk layout in a configurable index store. The blob is fully materialized so ByteStream/FindMissingBlobsstay correct for non-chunking clients.SplitBlobserves stored layouts (validated to sum to the blob size, so corrupt or truncated index entries are never served), and otherwise chunks blobs on demand with FastCDC 2020 — this is the path that matters for RBE, since worker-uploaded action outputs are never spliced by a client. Unusable layouts (evicted chunks, decode failures, transient existence-check errors) fall back to re-chunking.split_blob_support/splice_blob_supportand FastCDC 2020 params per instance (collected across all server blocks, so split-listener deployments work), gated behind the new opt-inexperimental_chunkingCAS service config.ChunkingMetrics— splice/split request totals, split hit/miss/on-demand counters, byte totals, and digest verification failures (tracked precisely via an explicit flag, not error-code inference).Conformance
The chunker is the
fastcdccrate at 3.2.1 — the exact version the REAPI spec names as a compliant implementation — used with the spec-mandated normalization level 2 (the crate default level 1 does not match).fastcdc_conformance_test.rsvalidates chunk offsets, lengths, SHA-256s, and gear-hash fingerprints against the officialfastcdc2020_test_vectors.txtfrom remote-apis, for both seed 0 and seed 666, in both in-memory and streaming form. This is the guarantee that server-produced chunks dedupe byte-for-byte against Bazel-produced chunks. The canonical fixture image is the one already vendored atnativelink-util/tests/data/SekienAkashita.jpgfor the existing FastCDC tests (its SHA-256 is asserted in the test).Note: the vendored
nativelink-util/src/fastcdc.rsused byDedupStoreis not FastCDC-2020-compliant and is deliberately untouched — deployed dedup indexes depend on its exact boundaries; the two implementations coexist.Safety / hardening
index_store == cas_storeis rejected at startup (layouts stored under blob digests would overwrite blob content).index_storeon a grpc-store instance is rejected (the backend owns layouts there).max_chunk_count(default 50k) bound memory, layout size, and response size; layout reads are capped consistently with the configured count and truncation is detected by the size-consistency check.experimental_chunkingunset, behavior is byte-for-byte identical to before (new RPCs returnUnimplemented, capabilities advertisefalse).Design decisions worth reviewer attention
cas_storeis aDedupStore; the cost is chunks + blob both stored. AChunkingStorethat serves reads from layouts is a possible future direction.CompletenessCheckingStore-style wrapper is the analogous future fix.ChunkingMetricsfollows theByteStreamMetricspattern (not yet wired into a metrics root — same as existing service metrics).Testing
NotFound, on-demand chunking (single- and multi-chunk with reassembly verification), layout reuse, unusable-layout fallback, absent-blobNotFound, disabled-instanceUnimplemented, config rejection cases, and metric assertions throughout.bazel testgreen acrossnativelink-service,nativelink-store,nativelink-config,nativelink-util(63 tests) with clippy + rustfmt aspects;cargo fmt --checkclean;bazel build //:nativelinksucceeds.Notes
max_chunk_count(default 50k, ~25 GiB at the default 512 KiB average) are served without chunking:SplitBlobreturnsNOT_FOUNDand clients fall back to a regular download. Raise the knob for larger blobs, keeping client gRPC message limits in mind.🤖 Generated with Claude Code
This change is