pub fn objects_to_send(
store: &dyn GitServe,
hash_kind: Kind,
want: &[&[u8]],
have: &[&[u8]],
) -> Result<Vec<Vec<u8>>>Expand description
The objects one push must carry: everything reachable from want that
is not reachable from have, in this store’s ids.
§Why replication comes through here rather than calling the store
🔴 MEASURED on the reference appliance 2026-08-31. A resync of 25 repositories left
six failing, every one of them on an annotated tag, every one refused by the
standby’s own receive-pack with
missing necessary objects: <oid> is not in this repository (peeling a tag) — where <oid> is the commit the tag names and the primary holds.
The mirror built its object list from
GitOps::reachable,
handing it the ref tips unpeeled. For an annotated tag that tip is the
tag object, and the shipped storage engine contributes a non-commit tip’s
own id and stops: the tag went into the pack and the commit under it did
not. It only showed where the tagged commit was on no branch — skade’s
v0.9.10, edda’s twenty-five tags on 2c7f9919… — because otherwise a
branch tip in the same push carried it by accident.
A clone of those same repositories has always worked, and this function is
why: [select_objects] peels its tips (step 1) and puts the tag objects it
walked through into the answer, and so does the store-answered fast path in
[crate::reachable::select]. Replication asking the store directly was a
second definition of “what does this ref tip reach”, and the two
definitions disagreed about exactly one edge. There is one now (one implementation).
have is tolerant by construction: a tip the far end advertised and this
store does not hold contributes nothing rather than failing, which is what a
standby whose history diverged looks like. A want this store does not hold
is an error, because that pack cannot be built.
§No object budget and no byte ceiling, deliberately
[Graph::with_budget] and [Graph::with_walk_limit] are what an operator
aims at a client: a fetch that would cost more than this machine will
spend is refused, and the client is told to ask for less. A mirror cannot
ask for less — there is no smaller request that still leaves the standby
holding the repository — so a ceiling here would not bound the work, it
would only make one repository permanently unreplicable. That is what
GitOps::reachable did before this function existed, over the same objects,
so this changes nothing about what the replicator may consume.