Item 3 of 15 of #168, as changed by sneak's ruling (#168 (comment)), which replaces the item's own text (reading the database row on a hit):
> no db needed, reads or writes, for cache hits! the writes should be spun off and are best effort and should never add latency or failure to a cache hit when serving. this also means no db reads for serving a cache hit! we need highest performance when serving cache hits, as it may be doing thousands per second in parallel. the path to getting bytes to a client needs to be MINIMAL. do whatever housekeeping you need to do in a separate go routine that doesn't block or delay anything for serving.
A hit (Service.Get, then Cache.Lookup and Cache.GetVariant in internal/imgcache) checks that the variant file exists, runs touchVariant (an UPDATE of variant_content.last_accessed_at) and IncrementStats (an UPDATE of cache_stats) on the request's goroutine, then takes the content type from Cache.metaCache, a 10,000-entry in-memory list (#70), or else from the .meta file beside the variant.
Decision, recorded here
A variant's content type is read from the first bytes of the variant file itself: pixa wrote that file in one of the formats it encodes, each recognisable from its first bytes, so a hit opens one file and nothing else. That removes the .meta file, VariantMeta, LoadWithMeta, variantContentTypeFromSidecar, metaCache and the golang-lru dependency. The alternatives were keeping the .meta file and the in-memory list (a second open whenever the list misses) or naming each file by its format (several opens for orig).
Definition of done
From the moment the handler receives the request to the last byte written, a cache hit on either image route makes no database call, read or write, and opens one file. A hit is a successful open; there is no separate existence check.
What a hit records, its access time for eviction and its hit count, is handed to a goroutine off the request path without waiting. A hit never blocks on it and never fails because of it; when that goroutine falls behind, records are dropped, not queued without bound. Access times are written in batches. At shutdown what is still pending is written once, best effort, as the pending counts are today.
The other housekeeping on the serving path goes the same way: the miss, upstream fetch and transform counts, and the deletion of an expired row in checkNegativeCache, run off the request goroutine. Database work a miss needs to answer (the negative cache check, finding a cached source, storing the source and the variant) stays where it is.
A hit's content type comes from the variant file's first bytes. A variant file whose first bytes match no format pixa writes is not served: the request continues as a miss and the variant is made again.
The .meta files, VariantMeta, LoadWithMeta, variantContentTypeFromSidecar, metaCache and golang-lru are gone, with their tests.
A test serves hits on both image routes through the HTTP handler with a database that counts its calls, and asserts that serving them made none.
A Go benchmark in internal/handlers serves cache hits in parallel (b.RunParallel) through the image handler, fails if its loop makes any database call, and reports hits per second; sneak's target is thousands per second in parallel. It runs with a make target, not in make check, and README.md names that target beside the load test.
README.md's paragraph about the 10,000 content types kept in memory is replaced by what a hit does now.
Approval and tests
sneak asked for each main recommendation of #168 to be its own issue, built before 1.0, one at a time in the order listed (#168 (comment)), and ruled how this one is built. That is his approval of this item, including its reversal of the in-memory list chosen under #70, the deletion of the tests of the code it removes, and changing existing tests that expect an access time or count to be written before Get returns so that they wait for the background write instead. No other assertion is weakened or dropped.
Model: opus-5-5
Item 3 of 15 of https://git.eeqj.de/sneak/pixa/issues/168, as changed by sneak's ruling (https://git.eeqj.de/sneak/pixa/issues/168#issuecomment-153512), which replaces the item's own text (reading the database row on a hit):
> no db needed, reads or writes, for cache hits! the writes should be spun off and are best effort and should never add latency or failure to a cache hit when serving. this also means no db reads for serving a cache hit! we need highest performance when serving cache hits, as it may be doing thousands per second in parallel. the path to getting bytes to a client needs to be MINIMAL. do whatever housekeeping you need to do in a separate go routine that doesn't block or delay anything for serving.
Starts when https://git.eeqj.de/sneak/pixa/issues/308 is squash-merged to `next`.
## Today (`next` at `989da78`)
A hit (`Service.Get`, then `Cache.Lookup` and `Cache.GetVariant` in `internal/imgcache`) checks that the variant file exists, runs `touchVariant` (an `UPDATE` of `variant_content.last_accessed_at`) and `IncrementStats` (an `UPDATE` of `cache_stats`) on the request's goroutine, then takes the content type from `Cache.metaCache`, a 10,000-entry in-memory list (https://git.eeqj.de/sneak/pixa/issues/70), or else from the `.meta` file beside the variant.
## Decision, recorded here
A variant's content type is read from the first bytes of the variant file itself: pixa wrote that file in one of the formats it encodes, each recognisable from its first bytes, so a hit opens one file and nothing else. That removes the `.meta` file, `VariantMeta`, `LoadWithMeta`, `variantContentTypeFromSidecar`, `metaCache` and the `golang-lru` dependency. The alternatives were keeping the `.meta` file and the in-memory list (a second open whenever the list misses) or naming each file by its format (several opens for `orig`).
## Definition of done
- From the moment the handler receives the request to the last byte written, a cache hit on either image route makes no database call, read or write, and opens one file. A hit is a successful open; there is no separate existence check.
- What a hit records, its access time for eviction and its hit count, is handed to a goroutine off the request path without waiting. A hit never blocks on it and never fails because of it; when that goroutine falls behind, records are dropped, not queued without bound. Access times are written in batches. At shutdown what is still pending is written once, best effort, as the pending counts are today.
- The other housekeeping on the serving path goes the same way: the miss, upstream fetch and transform counts, and the deletion of an expired row in `checkNegativeCache`, run off the request goroutine. Database work a miss needs to answer (the negative cache check, finding a cached source, storing the source and the variant) stays where it is.
- A hit's content type comes from the variant file's first bytes. A variant file whose first bytes match no format pixa writes is not served: the request continues as a miss and the variant is made again.
- The `.meta` files, `VariantMeta`, `LoadWithMeta`, `variantContentTypeFromSidecar`, `metaCache` and `golang-lru` are gone, with their tests.
- A test serves hits on both image routes through the HTTP handler with a database that counts its calls, and asserts that serving them made none.
- A Go benchmark in `internal/handlers` serves cache hits in parallel (`b.RunParallel`) through the image handler, fails if its loop makes any database call, and reports hits per second; sneak's target is thousands per second in parallel. It runs with a make target, not in `make check`, and `README.md` names that target beside the load test.
- `README.md`'s paragraph about the 10,000 content types kept in memory is replaced by what a hit does now.
## Approval and tests
sneak asked for each main recommendation of https://git.eeqj.de/sneak/pixa/issues/168 to be its own issue, built before 1.0, one at a time in the order listed (https://git.eeqj.de/sneak/pixa/issues/168#issuecomment-153513), and ruled how this one is built. That is his approval of this item, including its reversal of the in-memory list chosen under https://git.eeqj.de/sneak/pixa/issues/70, the deletion of the tests of the code it removes, and changing existing tests that expect an access time or count to be written before `Get` returns so that they wait for the background write instead. No other assertion is weakened or dropped.
Model: opus-5-5
clawbot
added this to the 1.0.0 milestone 2026-10-21 12:49:18 +02:00
clawbot
self-assigned this 2026-10-21 12:49:19 +02:00
Built in #325: a cache hit opens the variant file and makes no database call, taking its content type from the file's first bytes; its access time and hit count are written by a background goroutine once a second. The PR body lists the judgement calls and the one deviation.
Model: opus-5-5
Built in https://git.eeqj.de/sneak/pixa/pulls/325: a cache hit opens the variant file and makes no database call, taking its content type from the file's first bytes; its access time and hit count are written by a background goroutine once a second. The PR body lists the judgement calls and the one deviation.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Item 3 of 15 of #168, as changed by sneak's ruling (#168 (comment)), which replaces the item's own text (reading the database row on a hit):
> no db needed, reads or writes, for cache hits! the writes should be spun off and are best effort and should never add latency or failure to a cache hit when serving. this also means no db reads for serving a cache hit! we need highest performance when serving cache hits, as it may be doing thousands per second in parallel. the path to getting bytes to a client needs to be MINIMAL. do whatever housekeeping you need to do in a separate go routine that doesn't block or delay anything for serving.
Starts when #308 is squash-merged to
next.Today (
nextat989da78)A hit (
Service.Get, thenCache.LookupandCache.GetVariantininternal/imgcache) checks that the variant file exists, runstouchVariant(anUPDATEofvariant_content.last_accessed_at) andIncrementStats(anUPDATEofcache_stats) on the request's goroutine, then takes the content type fromCache.metaCache, a 10,000-entry in-memory list (#70), or else from the.metafile beside the variant.Decision, recorded here
A variant's content type is read from the first bytes of the variant file itself: pixa wrote that file in one of the formats it encodes, each recognisable from its first bytes, so a hit opens one file and nothing else. That removes the
.metafile,VariantMeta,LoadWithMeta,variantContentTypeFromSidecar,metaCacheand thegolang-lrudependency. The alternatives were keeping the.metafile and the in-memory list (a second open whenever the list misses) or naming each file by its format (several opens fororig).Definition of done
checkNegativeCache, run off the request goroutine. Database work a miss needs to answer (the negative cache check, finding a cached source, storing the source and the variant) stays where it is..metafiles,VariantMeta,LoadWithMeta,variantContentTypeFromSidecar,metaCacheandgolang-lruare gone, with their tests.internal/handlersserves cache hits in parallel (b.RunParallel) through the image handler, fails if its loop makes any database call, and reports hits per second; sneak's target is thousands per second in parallel. It runs with a make target, not inmake check, andREADME.mdnames that target beside the load test.README.md's paragraph about the 10,000 content types kept in memory is replaced by what a hit does now.Approval and tests
sneak asked for each main recommendation of #168 to be its own issue, built before 1.0, one at a time in the order listed (#168 (comment)), and ruled how this one is built. That is his approval of this item, including its reversal of the in-memory list chosen under #70, the deletion of the tests of the code it removes, and changing existing tests that expect an access time or count to be written before
Getreturns so that they wait for the background write instead. No other assertion is weakened or dropped.Model: opus-5-5
Built in #325: a cache hit opens the variant file and makes no database call, taking its content type from the file's first bytes; its access time and hit count are written by a background goroutine once a second. The PR body lists the judgement calls and the one deviation.
Model: opus-5-5