1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
//! **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`](git_storage_trait::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.
use Arc;
use Duration;
use crate;
/// 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.
pub const FINISHED_RETENTION: Duration = FINISHED_RETENTION;
/// Finished syncs kept regardless of age, most recent first.
pub const FINISHED_KEPT: usize = FINISHED_KEPT;
/// 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.
///
/// The four words are [`JobState`]'s, shared with the gc and the purge, so
/// three status RPCs cannot drift apart about what `Done` means.
pub type MirrorState = JobState;
/// One sync, queued or completed.
///
/// A [`Job`] of kind [`Mirror`]: the queue's own fields (`job_id`, `state`,
/// `queue_position`, `progress`, `error`, the timestamps) plus a
/// [`MirrorReport`], which dereferences flat. The repository is `job.key`,
/// exactly as the queue keys on it.
pub type MirrorJob = ;
/// **What a sync was asked for.**
///
/// The upstream travels on the order rather than being re-read by the worker,
/// and that is the rule [`JobKind::Order`] states: a registration can be
/// changed while its job waits, and a job that quietly fetched from a different
/// remote than the one the caller asked about would be a mirror nobody could
/// audit.
/// **What one sync produced.**
///
/// The kind's own fields; the runner never reads them. Nothing here is
/// restated from the order — every number is measured by the fetch.
/// Why a sync was REFUSED by the namespace's plan, as against failing.
/// **What a sync actually is**, handed in so this module does not have to know.
///
/// Takes the order and the job's reporter and either succeeds or returns the
/// sentence a console will show. The real one is
/// [`crate::mirror_fetch::sync_once`].
pub type MirrorRunner =
;
/// **The mirror kind.** Everything the shared runner needs to know about a
/// sync, and nothing else.
/// The queue: one worker, one sync at a time, FIFO, deduplicated by repository.
///
/// A named type over [`JobQueue<Mirror>`] rather than an alias, so `Mirror.Sync`'s
/// door keeps speaking in orders instead of making every caller reach for the
/// generic.
;