Skip to main content

Module mirror_queue

Module mirror_queue 

Source
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.
MirrorOrder
What a sync was asked for.
MirrorQueue
The queue: one worker, one sync at a time, FIFO, deduplicated by repository.
MirrorReport
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§

MirrorJob
One sync, queued or completed.
MirrorRunner
What a sync actually is, handed in so this module does not have to know.
MirrorState
Where a sync is. Mirrors gunnar.v1.MirrorJobState; the mapping to the wire lives in gunnar-grpc so this crate does not depend on the protos.