Expand description
The substrate’s GitPackGen implement (PackGen) — pack
generation over the real Find front (ObjectFront’s per-session
SessionFind views) and the negotiation ack seam’s real predicate
(the trait’s common_haves, ADR-014 §5) — substrate.md §object
storage “Packs”; ADR-004 is authoritative for the pipeline.
§The pipeline (ADR-004, composed exactly)
run_pipeline (the module’s pipeline function) is the wave-2
doubles’ composition re-landed on the substrate Find (the POC-O
packgen.rs reference shape):
peel wants to commit tips (tag chains walked; peeled tag objects kept)
boundary_haves peeled identically (the closure-subtraction sets)
→ commit-ancestry walk (gix_traverse::commit::Simple, Parents::All,
non-commit tips as-is)
→ count::objects_unthreaded (TreeContents) over the closure inputs
[+ AsIs over the peel-exposed tag chains]
→ counted-object existence pre-check
→ entry::iter_from_counts → InOrderIter
→ bytes::FromEntriesIter (V2, sha1) → the sinkThe two-stage closure is mandatory (ADR-004: TreeContents does
not follow commit parents; feeding tip commits alone produces
incomplete packs — POC-2’s course correction). Missing objects abort
with StorageError::ObjectMissing naming the missing object
(never a broken pack emitted downstream): every counted object is
existence-checked before the byte pipeline opens, and the entry
stage’s own missing_objects statistics remain the abort posture.
Generation is negotiation-agnostic: boundary sets in, pack out. The
limits parameter is accepted and unused for v1 — the doubles’ own
posture; ADR-009 budgets the receive side, and ADR-004 pins no
generation-side size budget (max_pack_size is
GitPackIngest territory).
§Both serving shapes (substrate.md §object storage “Packs”)
The mode selection is the substrate impl’s internal posture — the constructor level (the trade: a per-call selection would surface a mode parameter the frozen trait signature does not carry).
- Direct (
PackGen::direct): the generated pack streams through the sink, no storage round-trip. - Through-store (
PackGen::through_store): the pack is put once into the store (the pack rides the canonical blob family —PACK_ALGORITHMbelow — with the store’s own tier dispatch routing big packs to the large tier), then served throughread_rangewindows into the sink — every window’s out-of-band slice digest is re-derived and verified mid-flight (the store does not verify a range read; the front-line impl re-derives, the same postureObjectFront’s loose reads carry). A request-digestPackCachelets repeat fetches ride the stored pack without regeneration; releases and evictions are pins the next sweep reclaims (PackCache::release_allis thePackHousekeepingconsumer’s release path). Large tier required for through-store serving — a kv-only shape rejects over-threshold packs, the rejection riding the store’s own put-time kv-only overflow (mapped toStorageError::Io).
§Threading and the one bridge
The ADR-004 pipeline runs on tokio::task::spawn_blocking with
owned handles moved in (backend.md §concurrency model: the permit
stays wire-side, the impl’s threading invisible). Every sync→async
hop inside the pipeline goes through ObjectFront::block_on — the
odb-front task’s one-place bridge rule (SessionFind’s sync legs
already own theirs). The through-store put rides the async path
directly (generate’s own async context): the pipeline streams the
pack through a bounded duplex pipe (PACK_PIPE_CAPACITY, the
backpressure boundary) into Store::put_as — no unbounded buffer on
the async path.
§Failure posture on the pack put
A generation that fails after the put began leaves the pack put’s fate to the stream: an early pipeline end closes the pipe and the put commits what it received — a truncated or empty orphan pack that holds its pin only across the call. The error is returned and any put-returned pin is dropped, so the orphan is sweep-eligible: a failed fetch is a failed fetch, not partial repo state (the substrate’s GC-decreed recovery shape). Nothing partial is ever served: the pack never reaches the sink on an error path, and a cached pack is inserted only once both the pipeline and the put succeeded. The put error wins over the pipeline’s pipe-closed noise — the honest cause (a kv-only over-threshold rejection, a backing failure) is what the caller sees.
Structs§
- Pack
Cache - The request-digest pack cache of the through-store shape: repeat
fetches of the same (canonicalized) want/have set ride the stored
pack without regeneration. Evictions (capacity bounded) and
releases (
PackCache::release_all) drop the entry’s pins — the sweep reclaims the pack blobs the next time it runs (substrate.md §object storage: “releases/evictions are pins the next sweep reclaims”). - PackGen
- The substrate’s
GitPackGenimplement: ADR-004’s pipeline over the object front’s real Find, the ADR-014 §5 ack predicate, and one of the two serving shapes (constructor-level posture — through the frozen trait signature runs no mode parameter; the wire layer is unchanged either way).