Skip to content

Commit

The performance and Artifacts notes record what a push cost before and after the speed-up, step by step, and name the next step: ask git for packs without outside bases, then upload while checking, then keep the receive-pack advertisement.

syntaqxcommitted Parent6c97c24Browse files
2 files+72−00/2 viewed
+38−0
217217 - `wrangler tail g1t-repos` for 75 s: 87 events, all `ok`, no exceptions or error logs. The slowest were a
218218 blame RPC (6.6 s wall, 178 ms CPU) and an `info/refs` miss with a mint (2.6 s).
219219
220+### Pushes (2026-10-09)
221+
222+Five small files pushed to `flagon-io/automation-lab` from Denver, several times each, before and after
223+the push speed-up (Deploy #121; what changed is in docs/PERFORMANCE.md, "Pushes").
224+
225+| `receive-pack` step | Before (#120) | After (#121) | Who |
226+| --- | --- | --- | --- |
227+| Total | 1,123–1,523 ms | 931–1,120 ms | |
228+| `read`: the bases a thin pack's deltas need, read from the store | inside `scan` | 267–318 ms | Artifacts reads |
229+| `rules` and `scan` | 33–131 and 423–623 ms, one after the other | 18–75 and 17–79 ms, side by side | g1t |
230+| `upload`: the store's receive-pack | 467–620 ms | 460–511 ms | Artifacts |
231+| `refs` | ~40 ms | ~45 ms | g1t |
232+| `info/refs` (its own request) | 430–680 ms | 316–765 ms | Artifacts |
233+
234+g1t's own work is now under 100 ms. The rest is Artifacts, and `read` grows with the push: a
235+binding read per base (two when the pack doesn't say whether it is a blob or a tree), all at once,
236+up to three rounds for delta chains. A 437-object push (358 KB, 15 commits) to `flagon-io/g1t`
237+answered 503 twice and took 23 s the third time.
238+
239+**Next step, in this order:**
240+
241+1. **Ask for packs without outside bases.** Add `no-thin` to the receive-pack advertisement g1t
242+ forwards, so git sends every delta's base in the pack (git's `send-pack` turns thin packs off
243+ when it sees it). `read` goes to 0 for every client that honours it, and big pushes no longer
244+ make hundreds of reads. The cost is a larger upload when a push changes a big file a little;
245+ pushes stay capped by `MAX_SCANNED_PUSH`. `supply_bases` stays for clients that send thin packs
246+ anyway.
247+2. **Upload while checking.** Stream the pack to Artifacts while the checks run, holding back the
248+ last 20 bytes (the checksum) until they pass, so a declined push is never stored. A push then
249+ takes about the larger of `checks` and `upload`, not their sum. Whether Artifacts waits for a
250+ held-back trailer without timing out has to be tried first.
251+3. **Keep the receive-pack advertisement.** Serve `info/refs?service=git-receive-pack` from
252+ `refs_cache` by `refs_version`, as for fetches. `refs_cache`'s test forbids it today: with a
253+ stale advertisement git builds its pack against old tips and the push fails its old-value
254+ check. Ref moves through g1t bump `refs_version`, so a kept copy keyed by it is not stale,
255+ with the same rule as fetches: never while a handed-out push credential is live. The test
256+ changes with the code.
257+
220258 ## 4. Where we and the docs disagree
221259
222260 | # | Topic | Documented | What g1t does or assumes | Risk | Fix |
+34−0
455455 characters (lock files) are not highlighted and still cost about 130 ms
456456 for a crawler.
457457
458+## Pushes (2026-10-09)
459+
460+A push is two requests: `info/refs` (the receive-pack advertisement,
461+forwarded to the store) and `receive-pack` (the pack, checked here, then
462+uploaded). `receive-pack`'s `Server-Timing` says `recv`, `checks` (with its
463+parts `read`, `rules`, `scan`, `gate`), `upload` and `refs`. Measured by
464+pushing 5 small files to flagon-io/automation-lab from Denver, several
465+times each.
466+
467+| | Before (Deploy #120) | After (Deploy #121) |
468+| --- | --- | --- |
469+| `git push`, wall clock | 2.0–2.3 s | not timed; the two requests below add up to 1.25–1.9 s |
470+| `info/refs` | 430–680 ms | 316–765 ms (unchanged: the store answers it) |
471+| `receive-pack`, total | 1,123–1,523 ms | 931–1,120 ms |
472+| reading the pack's bases from the store (`read`) | inside `scan` | 267–318 ms |
473+| branch rules (`rules`) | 33–131 ms | 18–75 ms, beside the scan |
474+| secret scan (`scan`) | 423–623 ms | 17–79 ms |
475+| the store's own receive-pack (`upload`) | 467–620 ms | 460–511 ms |
476+| moving refs and recording the push (`refs`) | ~40 ms | ~45 ms |
477+
478+What changed in #121 (`push_checks.rs`): the pack is read once and shared
479+by the rules and the scan, which run side by side; one store handle serves
480+the whole push; branch rules, custom patterns and the email guard are asked
481+while the pack is parsed; cache writes and rule records wait until after
482+the answer (`Deferred`, `store.rs`); the bases a thin pack's deltas need are
483+fetched all at once, and their kinds are read from the pack's own trees
484+when it names them, so most are one read instead of two.
485+
486+What is left is the store: `read` (one store read per base, up to three
487+rounds for delta chains), `upload`, and `info/refs`. `read` grows with the
488+push. A 15-commit push of 437 objects (358 KB) to flagon-io/g1t on
489+2026-10-09 answered 503 twice and took 23 s the third time. The next step
490+is to stop needing bases: see "Pushes" in docs/ARTIFACTS.md.
491+
458492 ## Client navigation
459493
460494 - `<Link prefetch="intent">` on the sidebar, project tabs, breadcrumbs,