jeffparsons / jeffparsons/git-full-send

Push the code and extra chains concurrently: the second connection is a third of a steady-state sync

Open
#92 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Description

ADR-0005 accepts "two `git push`/`receive-pack` subprocess pairs and two tunnel connections per sync" as the price of the per-chain delta policy (#50). Field data says that price is now about a third of a steady-state sync, and it looks avoidable without touching the policy.

From the Stile `dev` integration (MacBook client → aarch64 EC2 workstation over a Tailscale SSH tunnel; 34.6k-file worktree, 2.5 GB object store, 29,327 refs). Recent steady-state syncs, with #89's advertisement hide in place:

- `code` push ~380 ms, `extra` push ~350 ms, each moving 3–7 KB
- client `encode` ~280 ms
- whole `sync` ~1.0–1.6 s, and the two pushes are ~0.7 s of it
- server-side `receive.duration_ms` is 320–350 ms per connection, within ~50 ms of the client's `push_ms`, so this is per-connection cost, not transfer

The two chains are pushed sequentially, so the sync pays both. They are independent by construction — distinct refs, distinct policies, and ADR-0005 already wants them to fail independently — so running the two exchanges **concurrently** would make the cost `max(code, extra)` instead of `code + extra`, saving roughly 350 ms on every sync while leaving `--thin` for `code` and `--no-thin -c pack.window=0` for `extra` exactly as they are. `listen` already serves concurrent connections (`--max-connections`), and the two `receive-pack` processes touch different refs under `refs/git-full-send/streams//`.

Worth checking before doing it:

- ref-lock or `receive.autogc` interactions between two `receive-pack` processes in the same repo (autogc is already disabled for gfs receives)
- retention (`retain_ms`) currently runs after each push; concurrency needs the two retentions not to race
- error reporting: a partial failure should still be attributable to its chain, not collapsed into one message

Skipping the `extra` push when nothing changed is *not* the win it looks like here: Stile's extra layer is the per-invocation plan file, so it carries new content on every single sync.

Worth doing after #91, since that will say what the ~330 ms of per-connection server cost actually is — if most of it turns out to be `receive-pack` spawn or fsync rather than anything overlappable, concurrency wins less than the arithmetic suggests.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the sync path that launches the two git push/receive-pack subprocess pairs, and read ADR-0005 plus #91 before changing the exchange. Check listen's concurrent-connection behavior, ref-lock and receive.autogc interactions, and ensure retention does not race. Done means independent concurrent pushes with chain-specific errors and measured savings without changing either chain's policy.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, rust
Domain
backend, performance
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.