Expand description
One mirror sync at a time, for the whole box — the third kind on the one
runner, and the queue behind Mirror.Sync.
One mirror sync at a time, for the whole box.
Mirror.Sync exists so a console button can pull a repository off another
forge. The moment it exists, ten owners can press ten buttons inside one
second, and a sync is the most expensive button on the box: it is a whole
git clone over somebody else’s network, into this box’s storage engine,
with the pack streaming through the whole time.
§Why this is the third queue and not a third caller of one queue
crate::job_queue argues it in full and this is the mirror’s half of that
argument: the line a job waits in is part of what the job costs. A gc
waits holding nothing. A purge waits holding a total lockout on an account.
A mirror waits holding a repository that is not yet usable — somebody
asked for a copy of an upstream and until the sync runs there is nothing
there to clone. Putting it behind a compaction that is only holding the disk
would be the same mistake in a third colour, so it gets its own worker and
its own line.
§What is here and what is not
Not the fetch. That is crate::mirror_fetch, reached through a runner
handed in at construction — the same shape crate::gc_queue uses, and for
the same two reasons: one writer for what a sync is (one implementation), and a queue
that can be tested with no network and no store under it.
What is here is the mirror’s answers to JobKind’s questions: a sync’s
subject is a repository path, a sync’s order carries the upstream as well
(so the worker does not have to re-read a registration that may have been
edited while the job waited), and a sync’s report is objects, bytes and the
references that moved.
§progress, and the honest shape of it
A gc and a purge report none — each is one indivisible act as far as a
caller is concerned, and a fabricated 0/1 would be a progress bar that
lies. A mirror cannot do without one: a fetch of a large repository is
minutes of network with a console watching.
Both halves are real and live, and they are published from opposite sides
of the storage seam. gunnar-wire’s FetchProgress publishes
objects_total the instant the packfile header arrives — twelve bytes, read
before an object is stored — so (0, N) is known at the start of the
transfer. The numerator is the ingest’s, because the only code that can
count objects without inflating them a second time is the code that is
already splitting the pack: gunnar has exactly one pack decoder (one implementation), and
fetch_pack’s module doc refuses to become the second one for this exact
reason.
§🔴 What this used to say, and what closed it
Until 2026-09-08 this paragraph read “the numerator has exactly two
values”, and the pair really did go (0, N) → (N, N) — one publish at the
header and one at the finish, with nothing in between. The reason given was
that znippy “takes a pack in one call and reports what it indexed when it
returns”, which was true of the seam and never true of the engine: znippy
splits the pack entry by entry in pack_walk, and has known the running
count all along. It simply had nobody to tell.
It has now. GitOps::put_pack_observed
is one defaulted method on the storage contract — no existing implementer
changed, and an engine that has no entry loop keeps publishing nothing and
says so by name through publishes_pack_progress(). znippy overrides it and
publishes once per object from the walk it was already doing; nothing
new is decompressed and no second decoder exists.
crate::mirror_fetch passes the sink straight through to the same
Reporter the wire’s two figures go to.
So the pair now steps: (0, N), then a value per object as the engine takes
them in, ending at (N, N) — and fetch_pack’s header-versus-receipt
cross-check at the end is now also the proof that the live count was honest.
MirrorReport::bytes is still the figure that moves while the network
is the bottleneck, and the object count is the one that moves while
storage is; between them a console has something live for both halves of a
sync, and neither is fabricated.
Structs§
- Mirror
- The mirror kind. Everything the shared runner needs to know about a sync, and nothing else.
- Mirror
Order - What a sync was asked for.
- Mirror
Queue - The queue: one worker, one sync at a time, FIFO, deduplicated by repository.
- Mirror
Report - What one sync produced.
Enums§
- Refusal
- Why a sync was REFUSED by the namespace’s plan, as against failing.
Constants§
- FINISHED_
KEPT - Finished syncs kept regardless of age, most recent first.
- FINISHED_
RETENTION - How long a finished sync stays readable. The shared default: ten minutes is far longer than any console poll interval and far shorter than a session.
Type Aliases§
- Mirror
Job - One sync, queued or completed.
- Mirror
Runner - What a sync actually is, handed in so this module does not have to know.
- Mirror
State - Where a sync is. Mirrors
gunnar.v1.MirrorJobState; the mapping to the wire lives ingunnar-grpcso this crate does not depend on the protos.