PERF: bound Unsplash thumbnail bytes and release expired cache entries (#663) #762

Open
opened 2026-10-02 13:09:53 +00:00 by kayg · 2 comments
Owner

Parent audit: #663. Baseline: c4a61e8cf0; unchanged in round 7a.

M2: Unsplash thumbnail cache lacks a byte budget and idle expiry

Status: source-confirmed performance finding. No crash or security exploit was reproduced.

Evidence: crates/calternal-server/src/appearance.rs:50 allows 5 MiB per
thumbnail. CachedThumbnail owns Vec (:292); cloning a cache hit copies
the payload. The new image is cloned into the cache (:1153).
trim_cache (:1372) runs on search insertion. It removes expired thumbnails
but has no thumbnail byte/count loop. Thumbnail insertion does not trim.
Expired images stay resident while idle. Photo count is limited to 512;
thumbnail TTL is 60 s. A fetch in flight can insert after photo eviction.
The same design remains in round 7a (:1393 for trim_cache).

Impact estimate: 512 images at the allowed 5 MiB size retain 2,560 MiB.
At 100 KiB average they retain 50 MiB. Each hit needs another payload-sized
copy. A completed fetch temporarily has both response and cache copies.
TTL alone does not release an allocation.

Fix: shared immutable bytes; explicit global byte-budget LRU; prune on
insert/read. Release expired bytes during idle with one expiry deadline or
an existing shared maintenance task. Set a per-User allowance within the
global budget. Check photo validity again after a fetch.

Test: local fake image service, bounded synthetic image sizes. Check byte
accounting, replacement, expiry, concurrent fetches and key changes.
A hit must share bytes instead of cloning a vector.

Duplicate search: all-state thumbnail, cache and memory. No matching server
Unsplash byte-budget issue. #665 is the UI revision cache; #449/#510 concern
filesystem thumbnail identity.

Parent audit: #663. Baseline: c4a61e8cf090170f35b1bed3350d9de20c83ecd5; unchanged in round 7a. M2: Unsplash thumbnail cache lacks a byte budget and idle expiry Status: source-confirmed performance finding. No crash or security exploit was reproduced. Evidence: crates/calternal-server/src/appearance.rs:50 allows 5 MiB per thumbnail. CachedThumbnail owns Vec<u8> (:292); cloning a cache hit copies the payload. The new image is cloned into the cache (:1153). trim_cache (:1372) runs on search insertion. It removes expired thumbnails but has no thumbnail byte/count loop. Thumbnail insertion does not trim. Expired images stay resident while idle. Photo count is limited to 512; thumbnail TTL is 60 s. A fetch in flight can insert after photo eviction. The same design remains in round 7a (:1393 for trim_cache). Impact estimate: 512 images at the allowed 5 MiB size retain 2,560 MiB. At 100 KiB average they retain 50 MiB. Each hit needs another payload-sized copy. A completed fetch temporarily has both response and cache copies. TTL alone does not release an allocation. Fix: shared immutable bytes; explicit global byte-budget LRU; prune on insert/read. Release expired bytes during idle with one expiry deadline or an existing shared maintenance task. Set a per-User allowance within the global budget. Check photo validity again after a fetch. Test: local fake image service, bounded synthetic image sizes. Check byte accounting, replacement, expiry, concurrent fetches and key changes. A hit must share bytes instead of cloning a vector. Duplicate search: all-state thumbnail, cache and memory. No matching server Unsplash byte-budget issue. #665 is the UI revision cache; #449/#510 concern filesystem thumbnail identity.
Author
Owner

Starting work on job/webperf, based on 2f4482ded066d9c5d9c59130377907f7fd2916c9 (job/merge-round-7a). I am reading the matching audit evidence and will report the concrete finding, regression coverage, measurements, and gate output here when finished.

Starting work on `job/webperf`, based on `2f4482ded066d9c5d9c59130377907f7fd2916c9` (`job/merge-round-7a`). I am reading the matching audit evidence and will report the concrete finding, regression coverage, measurements, and gate output here when finished.
Author
Owner

Finding: the thumbnail cache retained response bytes independently of the existing entry count, and cache hits copied the full body. The cache now shares immutable bytes and applies a 64 MiB process cap plus a 12 MiB per-User cap with LRU eviction. The regression cases are in the server appearance tests. Rust gates are still in progress; no new performance measurement is recorded yet.

Finding: the thumbnail cache retained response bytes independently of the existing entry count, and cache hits copied the full body. The cache now shares immutable bytes and applies a 64 MiB process cap plus a 12 MiB per-User cap with LRU eviction. The regression cases are in the server appearance tests. Rust gates are still in progress; no new performance measurement is recorded yet.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#762
No description provided.