~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

A repository's settings no longer wait seconds for its storage

Merged
Merged chadtmiller.com asked to merge into main from chadtmiller.com/knotless:serve/storage-cache

What changes

Storage is its own query. What a repository takes up on its owner's PDS moves out of dev.knotless.getRepoSettings into a new dev.knotless.getRepoStorage. getRepoSettings keeps the storage field in its lexicon, marked deprecated and no longer set.

The settings page streams it. The general settings page draws everything else at once. The storage line fills in when its count arrives, with "Counting its packs…" until then. The branches, labels and access pages no longer ask for it at all.

The count is kept. serve keeps each public repository's count in memory, up to 4,096 of them. A count stays good until the firehose tells of a write to that repository's packs, claims or refs (the existing per-repository counter in App::stamp). Other repositories' writes, and the same account's comments, don't clear it. Compacting from the pages clears it at once, before the firehose says so. With no firehose watched, a count lasts only as long as a mirror is trusted. A private repository is counted every time.

Why

On prod, every getRepoSettings took 1.5 to 3.2 s (logs of 2026-11-03: knotless 1.6/2.1/2.7 s, group-host 1.7 to 3.2 s over 8 loads, grain 1.5 s). Its trace had no slow SQL. The time went to knotless::storage::storage, which locates the repository and lists all of its pack records live on every load, for one line of text. Alone, knotless storage takes 2.6 s for knotless, 1.1 s for group-host and 3.0 s for grain. Every other call those pages make answers in a few milliseconds.

How it was checked

  • pages.rs: settings no longer carry storage; getRepoStorage answers the same count twice (the second from what was kept); after compactRepo it counts the folded packs at once; a private repository's count is shown to its owner and 404 to anyone else.
  • A unit test of Counts: kept until its repository's events move, expired without a firehose, apart per repository, forgotten, and started again when full.
  • just lex's lexicon checks pass locally. The answers check, build and tests are left to CI.
  • The shots fixture gains the new answer, so the settings page should draw as it did.

Shortcomings

  • The first load after each push to a repository still counts, and the storage line waits for it, though the rest of the page doesn't.
  • After this deploys I'll compare getRepoSettings and getRepoStorage times in prod's request logs against the numbers above.

🤖 Generated with Claude Code

Approved

This moves the storage count out of getRepoSettings into a new getRepoStorage query. The settings page now streams the count, and serve keeps each public repository's count until the firehose reports a write to that repository's packs, claims or refs.

I found nothing that must change. I did not run the build or tests, and I did not read the checks.

  • Cache key: App::stamp(...).1 is the per-repository counter. It is read before counting, so a write that arrives during the count makes the next request count again. That is the right order.
  • Private repositories: they are counted as the viewer and never stored. An anonymous request gets a 404 from repo::found, which the new test covers.
  • Compaction: compact_repo forgets the entry right after it runs. A request that lands in the gap between the two could store a count from before the compaction. The firehose event then clears it, so I would leave it.
  • Docs and lexicons: docs/design/serve.md, docs/reference/api.md, the lexicons and the shots fixture are all updated with the change, as AGENTS.md asks.
  • Changeset: none is needed, because the client crates are untouched.
  • Shots: the settings page now draws the storage line after streaming. If the shots check flags it, name the page on a Shots-moved: line in the body.
Approved

The only change since my earlier approval is a type alias, Counted, for the cached tuple in Counts. It is a clippy fix with no behaviour change, so my earlier findings still hold. I read that diff only. I did not run the build or tests.

Merged as f7f95b4