Skip to content

Support REAPI content-defined chunking (SplitBlob/SpliceBlob) for Bazel's --experimental_remote_cache_chunking #2496

Description

@erneestoc

Summary

Bazel 8.7.0 / 9.1.0+ ship --experimental_remote_cache_chunking (bazelbuild/bazel#28437), which uses content-defined chunking (FastCDC 2020) to upload/download only the chunks of a large blob that changed, instead of re-transferring the whole blob whenever its digest changes. The protocol surface — SplitBlob / SpliceBlob RPCs on ContentAddressableStorage, plus ChunkingFunction negotiation and capability advertisement — is standardized upstream in remote-apis (bazelbuild/remote-apis#282, follow-up in #357). BuildBuddy is currently the only server implementation (see their write-up); they report ~85% of written bytes deduplicated for eligible files, and Bazel's benchmarks showed ~40% less data uploaded and ~40% smaller local disk cache.

This issue proposes implementing the server side in NativeLink.

Why NativeLink is well positioned

NativeLink already has production CDC machinery at the storage layer:

  • DedupStore (nativelink-store/src/dedup_store.rs) chunks blobs with a vendored FastCDC implementation (nativelink-util/src/fastcdc.rs, 64k/256k/512k min/avg/max defaults), stores chunks individually, and persists a serialized chunk-digest index keyed by the original blob digest.

That is almost exactly the data model SplitBlob/SpliceBlob expose over the wire — but today it is invisible to REAPI, so it saves storage without saving network transfer. Wire-level chunking is where most of the user-visible win is (large linked binaries, archives, container layers re-transferred after one-line source changes).

Current gaps

  • The vendored nativelink-proto/build/bazel/remote/execution/v2/remote_execution.proto predates the extension: no SplitBlob/SpliceBlob RPCs, no ChunkingFunction, no split_blob_support/splice_blob_support in CacheCapabilities.
  • cas_server.rs implements only the classic four CAS RPCs; capabilities_server.rs advertises nothing chunking-related.
  • DedupStore's chunk digests are internal BLAKE3 hashes regardless of the outer digest function, so its index can't be returned to clients as-is — the protocol requires chunks to be ordinary, client-addressable CAS blobs under the negotiated digest function.

Proposed phased plan

  1. Proto + capabilities. Vendor the updated remote_execution.proto; add split_blob_support / splice_blob_support and supported ChunkingFunction values to GetCapabilities, gated behind config and off by default. Bazel only activates chunking when the server advertises it, so this is safe to ship incrementally.
  2. SpliceBlob (write path). Accept an ordered chunk-digest list for a blob, verify all chunks exist, verify the concatenation actually hashes to blob_digest before registering the mapping (otherwise this is a cache-poisoning vector), and store the blob→chunks index.
  3. SplitBlob (read path). Return the stored layout when a splice was registered; optionally chunk on demand server-side using the existing FastCDC util for blobs that were uploaded whole — this benefits mixed fleets where some clients upload without chunking.
  4. (Optional) DedupStore unification. Evaluate sharing chunking/index machinery between DedupStore and the wire protocol so a chunk-uploaded blob is stored deduplicated without re-chunking.

Open design questions

  • Chunk lifetime / eviction coupling. Chunks must not be evicted while an index referencing them is alive. This needs a design that works across NativeLink's composable store topologies (evicting memory stores, S3 backends, sharded stores) — similar in spirit to the ActionResult→blob existence dependency, but inside the CAS.
  • Where the blob→chunks index lives. A dedicated keyspace/store vs. a CAS blob keyed off the original digest; interaction with FindMissingBlobs semantics (does a registered splice make the blob "exist"?).
  • Chunking parameters. Server-advertised FastCDC 2020 parameters must match what Bazel uses, or cross-client dedup silently degrades; DedupStore's current defaults may differ from Bazel's.
  • Digest functions. Chunk digests must use the request's digest function (SHA256/BLAKE3), unlike DedupStore's internal fixed-BLAKE3 hashing.

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions