perf: round 10 — auth alloc purge, parent-herd batching, query-shape pack, NC 304s

Benchmark-gated (benches/ROUND10.md; every change carries a BEFORE/AFTER
harness with equivalence/safety gates — two designs were rejected or
rewritten by their own benches before adoption):

- Auth hot path: TokenClaims/CurrentUser display fields to Arc<str>, role
  to inline SmolStr end-to-end (Bearer, cookie, Basic-auth cache) — 4→1
  allocs per authenticated request, 3→0 per warm DAV request; JWT
  Encoding/Decoding/Validation built once.
- Cold shared-album herd: leader-inline parent batching in PgAclEngine
  (+ cascade try_get_with single-flight) — 100→2 parent queries per
  100-thumb cold herd, herd wall 1.9x, sequential + warm paths unchanged,
  all ROUND8/9 safety gates plus new herd-equivalence gates.
- Query-shape pack: share download double-fetch 2→1 (2.18x), contact-group
  COUNT(*) 14.9x, save_faces UNNEST 3.9x, playlist reorder UNNEST 63.7x
  (now atomic), search files∥folders join! 1.45x, move drive-lookup join!
  2.14x, trash partial (drive_id, trashed_at) indexes, CalDAV event-gate
  narrow read, favorites/recents binary-decode port, dead count_files
  removed.
- NC surface: preview + avatar honour If-None-Match (e2e: 5 KB and 197 KB
  → 0 bytes per revalidation), avatar WebP→PNG transcode memoised,
  PROPFIND/trashbin integer+date emits on stack formatters, folder-header
  enrichment join!, chunk-PUT retry stat folded into create_new open.
- common::fmt integer rendering rewritten on the std 2-digit LUT after the
  round's own bench caught the div-loop losing to to_string (16.1 ns vs
  22.5; speeds every prior-round call site).
- Micro-pack: WebDAV scope probe borrow-only, ShareService base_url
  snapshot, cookie_secure OnceLock, Arc'd AES-GCM cipher, stack request-id,
  tantivy analyzer clone dropped.
- SPA: search stale-guard + AbortController (10→1 completed round-trips,
  stale-clobber gone), getFolder in-flight dedup, gridColumns matchMedia
  hoist (10k→0 style reads).

Backend: cargo fmt + clippy -D warnings clean, 524 tests green.
Frontend: npm run check clean, 301 vitest green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018DdM7V7M3QPW7HEHg3gLov
This commit is contained in:
Claude
2026-07-18 20:33:50 +00:00
parent 4fe429a109
commit c51af68432
64 changed files with 3452 additions and 442 deletions
+9 -2
View File
@@ -26,6 +26,13 @@ pub trait PasswordHasherPort: Send + Sync + 'static {
}
/// Claims contained in a JWT token
///
/// `username` / `email` are `Arc<str>` so the per-request `CurrentUser`
/// build clones them with a refcount bump instead of copying the strings —
/// the validation cache already hands the whole struct out behind an `Arc`,
/// but the two display fields still had to be deep-cloned out of it on
/// EVERY authenticated request (the "2 allocs/request" item deferred since
/// ROUND6).
#[derive(Debug, Clone)]
pub struct TokenClaims {
/// Subject identifier (user ID)
@@ -37,9 +44,9 @@ pub struct TokenClaims {
/// JWT unique ID
pub jti: String,
/// Username
pub username: String,
pub username: Arc<str>,
/// User email
pub email: String,
pub email: Arc<str>,
/// User role
pub role: String,
}
+4
View File
@@ -96,6 +96,10 @@ pub trait CalendarStoragePort: Send + Sync + 'static {
) -> Result<CalendarEventDto, DomainError>;
async fn delete_event(&self, event_id: &str) -> Result<(), DomainError>;
async fn get_event(&self, event_id: &str) -> Result<CalendarEventDto, DomainError>;
/// Narrow projection for authz gates: the owning calendar of an event
/// without hydrating the full event row (notably `ical_data`, the raw
/// iCalendar body, which can run to tens of KB on recurring events).
async fn calendar_id_for_event(&self, event_id: &str) -> Result<String, DomainError>;
/// Indexed single-row lookup by iCalendar UID — the CalDAV
/// object-resource paths must use this instead of listing the whole
/// calendar (every row + its `ical_data`) and filtering client-side.
+3
View File
@@ -106,6 +106,9 @@ pub trait ContactStoragePort: Send + Sync + 'static {
contact_id: &Uuid,
) -> Result<(), DomainError>;
async fn get_contacts_in_group(&self, group_id: &Uuid) -> Result<Vec<Contact>, DomainError>;
/// Membership count without hydrating the contacts (vCard TEXT +
/// 3 JSONB parses per row) — for group summary DTOs.
async fn count_contacts_in_group(&self, group_id: &Uuid) -> Result<i64, DomainError>;
async fn get_groups_for_contact(
&self,
contact_id: &Uuid,
-11
View File
@@ -189,17 +189,6 @@ pub trait FileReadPort: Send + Sync + 'static {
.await
}
/// Count files matching the search criteria (without loading them).
///
/// Used for pagination metadata without fetching the actual files.
/// Same drive-membership scoping as `search_files_paginated`.
async fn count_files(
&self,
folder_id: Option<&str>,
criteria: &SearchCriteriaDto,
caller_id: Uuid,
) -> Result<usize, DomainError>;
/// Return up to `limit` files whose name contains `query` (case-insensitive).
///
/// Results are ordered by relevance (exact > starts-with > contains) so the