perf: round 14 — faces narrow projection, auth per-request allocs, CalDAV emit buffers, frontend set churn
Benchmark-gated (benches/ROUND14.md); every change ships a BEFORE/AFTER
benchmark with an equivalence gate and is rolled back on regression (the
rule is encoded as a GATE FAIL exit / threshold expect).
Backend
- Q1 faces_for_file → narrow face_boxes_for_file(id, person_id, bbox) with the
caller filter pushed into SQL: drops the 2 KiB embedding BYTEA + 6 unused
columns per face. 15-face lightbox open 0.312→0.219 ms, 32 KB→840 B/req.
- A1 cookie auth uses the borrow-only extract_cookie_str (already backs CSRF)
instead of extract_cookie_value's owned String: -1 alloc/cookie request.
- A2 compute_relevance ASCII case-fold fast path vs name.to_lowercase() per
result row (Unicode fallback preserved): 1.40x, 12→3 allocs/page.
- A3 sub pre-parsed to Uuid at decode time (TokenClaims.sub_id) vs re-parsing
the 36-char claim on every request incl. cache hits: 22.7→0.7 ns.
- A4 auth + NextCloud middlewares borrow request.headers() instead of taking
axum's HeaderMap extractor (a full map clone): 2→0 allocs/authed request.
- A5 CalDAV getlastmodified via the stack rfc2822_utc (byte-identical to
chrono) vs a per-event to_rfc2822() heap String: 5→0 allocs.
- A6 CalDAV per-event href + quoted etag written into reused page buffers vs a
fresh format! pair per event: 3.48x, 240→6 allocs/40-event page.
Frontend
- F1 t() shares one frozen EMPTY_PARAMS for the no-interpolation call forms vs
a throwaway {} per call: -1 alloc/call.
- F2 favorites favoriteIds is a persistent SvelteSet with per-page add (clear
on reset) vs a brand-new set over the whole accumulated list each page:
22.3x over a 40-page drain (O(N^2)→O(N)).
Verified: cargo check --all-targets, cargo clippy -D warnings, both bench
packs (GATE PASS), frontend npm run check + vitest (4/4). ROUND14.md also
records the investigated-but-deferred backlog (music N+1, contact vcard
over-fetch, CachedBlobBackend syscalls, ResourceList.sections builder, etc.).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PymgCdK78NzUF3oRAQCJfN
This commit is contained in:
@@ -57,7 +57,14 @@
|
||||
raw.map((it) => [it.resource.id, { date: it.favorited_at } satisfies ItemContext])
|
||||
)
|
||||
);
|
||||
const favoriteIds = $derived(new SvelteSet(items.map((i) => i.id)));
|
||||
// Persistent reactive set, updated in place per page (add the fresh page's
|
||||
// ids; clear on reset) instead of rebuilding a brand-new SvelteSet over the
|
||||
// whole accumulated list on every infinite-scroll page — that was O(N²)
|
||||
// across a drain and, being a new instance each page, invalidated every
|
||||
// mounted star reader. Every item on this page is a favorite, and removed
|
||||
// items are no longer rendered, so the set only needs to be a superset of
|
||||
// the displayed ids (benches/ROUND14.md §F2, mirrors recent's shipped shape).
|
||||
const favoriteIds = new SvelteSet<string>();
|
||||
|
||||
const groupBys: GroupByDef[] = [
|
||||
{ key: '', label: t('files.name', 'Name'), orderBy: 'name', icon: 'arrow-up-a-z' },
|
||||
@@ -106,6 +113,10 @@
|
||||
resourceTypes: ['file', 'folder']
|
||||
});
|
||||
raw = reset ? page.items : [...raw, ...page.items];
|
||||
// Keep the persistent favoriteIds set in sync incrementally: clear on
|
||||
// reset, then add only this page's ids (benches/ROUND14.md §F2).
|
||||
if (reset) favoriteIds.clear();
|
||||
for (const it of page.items) favoriteIds.add(it.resource.id);
|
||||
cursor = page.next_cursor;
|
||||
void owners.resolve(page.items.map((i) => i.resource.created_by));
|
||||
} catch (e) {
|
||||
@@ -148,6 +159,7 @@
|
||||
try {
|
||||
await removeFavorite(kind, item.id);
|
||||
raw = raw.filter((i) => i.resource.id !== item.id);
|
||||
favoriteIds.delete(item.id);
|
||||
} catch (e) {
|
||||
errorToast(e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user