Why
The read path is anonymous and every page render shells out to git. On a repository with 40 files and 30 change requests, one page load cost 38 to 114 git process invocations:
| page | before | after |
|---|---|---|
| overview | 114 calls, 98 ms | 21 calls, 21 ms |
| code | 45 calls, 57 ms | 13 calls, 19 ms |
| issues | 38 calls, 48 ms | 7 calls, 12 ms |
| changes | 72 calls, 90 ms | 8 calls, 13 ms |
| releases | 38 calls, 45 ms | 7 calls, 12 ms |
The worst of it scaled with the repository’s contents: the metadata branch was
read one git cat-file per file, so every page paid for every issue and
comment. The rest was repeated work inside one request — the repository opened
two or three times, and the change-request list read once for the header and
again for the page.
What changed
metadata: the loaders and the push validators read every listed blob in onecat-file --batchinstead of one process per file.core/git:Refslists branches and tags in onefor-each-ref, with creation times so the tag picker stays newest-first.server/web: one memo per read request holds the opened repository, the open counts, and the change-request list. Write requests get no memo, so the cache dies with the request and a push is visible on the next page load without a TTL or an invalidation protocol.- The repository header takes the page it renders (
nav .Page "issues") instead of six arguments the view already carries. Output is unchanged.
Checks
./vole workflow checkgo vet ./...,gofmtCGO_ENABLED=1 go test -race ./...(thelibsqlite3-tagged build could not run here: nosqlite3.hon this machine)- New tests:
TestLoadRequestsReadsEveryFile(batched read, including two paths that share one object) andTestRefsListsBranchesAndTagsTogether.
Further read-path work (memoising the index checks, ETags on immutable views) follows on this branch, so the measurements above are a floor, not the final numbers.