chadtmiller.com/knotless
git that lives in your Atmosphere account
A mirror's repack runs aside, not in the way of its reads
MergedThis splits Mirror::sync into refresh and tidy. tidy is the repack, which now runs under its own non-blocking lock, so a second repack skips instead of waiting. knotless-serve calls refresh and then spawns tidy in a task of its own, in both places that sync. The CLI, runner and compaction still call sync, which does both. I found no bugs. The repack no longer holds the refs lock, and git's repack is safe beside readers. try_acquire handles WouldBlock and a missing directory correctly. The lock test covers it. docs/design/storage.md is updated as AGENTS.md asks, and Changeset: none fits a server-side change.
The check and test checks were still running or queued when I read them. I'm approving on the diff alone. test holds the 100% coverage gate, so watch that aside and the skipped-lock path in tidy are covered by a serve test.
The pull still does what my first review described. The only change since then is a merge of main and a new commit, "A tidy another holds the lock for is left to it, tested". That commit adds a test for the skipped-lock path in tidy, which was the coverage gap I flagged last round. I have nothing new to ask for.
check, docs and the skipped workflows passed. test and e2e were still running when I looked. test holds the 100% coverage gate, so make sure it goes green before the merge queue lands this.
9 passed, 1 skipped
What changes
A mirror with more than 50 packs is still repacked into one, but no longer inside the sync that reads it.
Mirror::syncis nowrefresh, which sets the refs, the commit-graph and HEAD, followed bytidy.tidyruns under its own lock file, and a second repack skips it rather than waiting. knotless-serve callsrefresh, then startstidyin a task of its own. It does this both where reads sync a repository and where the gateway syncs for a push. Everything else (the CLI, the runner, compaction) syncs and tidies inline as before.Why
On prod at 17:48:37 a
git repackof the knotless mirror took 4.4s, with no trace, right after a push. During that time every request for the repository (getRepo, listTags, listBranches, getTree, getLastCommits, listItems, getThread) waited, and all of them finished together at 17:48:38 after 5.4 to 6s. Two things caused the wait. The repack ran inside the mirror's refs lock. And serve holds the repository's entry while it syncs, so one sync waiting on that lock held up every reader. git's repack is safe beside readers and fetches: packs land under their own names,-kkeeps whatever no ref reaches, and-ddeletes only the packs it started with.How it was checked
The lock test now covers
try_acquire: it is taken when free, refused while held, and fails on a missing directory. Builds and tests are left to CI. After deploy, the check is whether a repack of a busy mirror still lines up with a wait across that repository's requests in getLogs.Shortcomings
The request that triggers a repack no longer pays for it, but the git process still uses CPU and disk beside the reads. The commit-graph write still runs inside the sync.
Changeset: none
🤖 Generated with Claude Code