perf: round 13 — grouped-view virtualization, notification/login query narrowing, HTTP dedup, locale precompute

Benchmark-gated (BEFORE/AFTER + equivalence/safety gate per change), same
discipline as rounds 2-12. Full write-up in benches/ROUND13.md.

Shipped:
- V1 Grouped views windowed (files route + ResourceList). The grid arm was
  the last unwindowed path (trash is grouped-by-default in grid): each
  swimlane now feeds its own VirtualList, outer container a flex stack.
  vitest gate: 800-item grouped grid mounts <120 .file-item (was 800).
- Q1 get_users_by_ids drops the <=512 KiB avatar image + ui_preferences
  JSONB (notification path never reads them). 30-member fan-out 8.60 ->
  0.25 ms (34.3x), ~7.7 MB off the wire.
- Q2 Login provisioning is_empty() -> SELECT EXISTS for calendar + address
  book (every login). 0.193 -> 0.170 ms, widens with owned-row count.
- Q3 Recent-access prunes only when the upsert inserted (RETURNING xmax=0)
  — a re-access can't grow the set. 0.567 -> 0.324 ms (1.75x).
- L1 Locale supported-codes precomputed once vs rebuilt per anonymous
  request. 616 -> 17.3 ns (35.7x), 18 -> 1 allocs.
- H1 Duplicate /api TraceLayer removed (global stack already wraps it).
  1.86 -> 1.42 us/request, -6 allocs.
- H2 client_ip span field: borrow-only ClientIpDisplay vs owned String.
  187 -> 173 ns, -1 alloc.

Not shipped (discipline): the "media hooks read the blob 3x" lead was a
correctness bug, not a perf dup — the raw-path metadata/faces readers
resolve only for local+unencrypted+single-chunk blobs and silently produce
nothing otherwise. Flagged for maintainers; routing through read_blob_bytes
is a correctness fix (perf-neutral-to-negative), not a benchmark-gated
perf change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BfidAJD5AHw23jtvBUNamB
This commit is contained in:
Claude
2026-07-19 08:17:48 +00:00
parent 50eca0627f
commit f58d72a780
22 changed files with 1411 additions and 61 deletions
+320
View File
@@ -0,0 +1,320 @@
//! Round-13 HTTP micro-pack (no Postgres).
//!
//! Two sections, each BEFORE (verbatim replica of the shipped shape) vs
//! AFTER (proposed shape), with byte-identity / equivalence gates:
//!
//! [H1] Duplicate `TraceLayer` on `/api` — the inner
//! `TraceLayer::new_for_http()` in `routes.rs` sat under the global
//! `TraceLayer + ClientIpMakeSpan` stack in `main.rs`, so every
//! `/api` request was wrapped in TWO span/response-future layers.
//! Measured end-to-end through real axum routers, one stack vs two.
//! [H2] Per-request `client_ip` `String` in the span factory —
//! `ClientIpMakeSpan::make_span` allocated an owned `String` on every
//! request purely to feed the span's `%client_ip` Display, vs a
//! borrow-only `ClientIpDisplay` that renders into the span storage.
//!
//! Run:
//! cargo run --release --features bench --example bench_round13_micro
//! Tunables (env): BENCH_ITERS (200000)
use std::alloc::{GlobalAlloc, Layout, System};
use std::env;
use std::hint::black_box;
use std::net::SocketAddr;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::Instant;
use axum::http::HeaderMap;
use oxicloud::interfaces::middleware::trusted_proxy::{
ClientIpDisplay, client_ip_display_from_parts, client_ip_from_parts,
};
static ALLOC_CALLS: AtomicU64 = AtomicU64::new(0);
struct CountingAlloc;
unsafe impl GlobalAlloc for CountingAlloc {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
ALLOC_CALLS.fetch_add(1, Ordering::Relaxed);
unsafe { System.alloc(layout) }
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
unsafe { System.dealloc(ptr, layout) }
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
ALLOC_CALLS.fetch_add(1, Ordering::Relaxed);
unsafe { System.realloc(ptr, layout, new_size) }
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
ALLOC_CALLS.fetch_add(1, Ordering::Relaxed);
unsafe { System.alloc_zeroed(layout) }
}
}
#[global_allocator]
static GLOBAL: CountingAlloc = CountingAlloc;
fn env_or<T: std::str::FromStr>(key: &str, default: T) -> T {
env::var(key)
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(default)
}
struct Measured {
wall_ns_per_op: f64,
allocs_per_op: f64,
}
fn measure<F: FnMut()>(iters: usize, mut f: F) -> Measured {
let a0 = ALLOC_CALLS.load(Ordering::Relaxed);
let t = Instant::now();
for _ in 0..iters {
f();
}
let wall = t.elapsed().as_nanos() as f64 / iters as f64;
let allocs = (ALLOC_CALLS.load(Ordering::Relaxed) - a0) as f64 / iters as f64;
Measured {
wall_ns_per_op: wall,
allocs_per_op: allocs,
}
}
fn print_row(label: &str, m: &Measured) {
println!(
"| {:<40} | {:>12.1} | {:>10.2} |",
label, m.wall_ns_per_op, m.allocs_per_op
);
}
// ────────────────────────────────────────────────────────────────────────────
// [H1] Duplicate TraceLayer on /api — one stack vs two, end-to-end
// ────────────────────────────────────────────────────────────────────────────
fn section_trace_dedup() {
use axum::Router;
use axum::routing::get;
use oxicloud::interfaces::middleware::trace_span::ClientIpMakeSpan;
use tower::ServiceExt;
use tower_http::trace::TraceLayer;
let iters: usize = env_or("BENCH_ITERS", 200_000) / 20;
let rt = tokio::runtime::Builder::new_current_thread()
.build()
.expect("rt");
async fn handler() -> &'static str {
"{\"ok\":true}"
}
// AFTER: the global stack only (one TraceLayer + ClientIpMakeSpan).
let after_app = Router::new()
.route("/api/x", get(handler))
.layer(TraceLayer::new_for_http().make_span_with(ClientIpMakeSpan));
// BEFORE: the inner per-router TraceLayer, then the global stack on top.
let before_app = Router::new()
.route("/api/x", get(handler))
.layer(TraceLayer::new_for_http())
.layer(TraceLayer::new_for_http().make_span_with(ClientIpMakeSpan));
let call = |app: &axum::Router| {
let app = app.clone();
rt.block_on(async move {
let res = app
.oneshot(
axum::http::Request::builder()
.uri("/api/x")
.body(axum::body::Body::empty())
.unwrap(),
)
.await
.unwrap();
res.status()
})
};
// Gate: identical status through both stacks.
assert_eq!(call(&before_app), call(&after_app), "status differs");
println!("# [H1] gate: /api response status identical with 1 vs 2 trace layers — OK");
let m_before = measure(iters, || {
black_box(call(&before_app));
});
let m_after = measure(iters, || {
black_box(call(&after_app));
});
println!("\n## [H1] Duplicate TraceLayer on /api (per request, incl. router)");
println!("| arm | ns/op | allocs/op |");
print_row("BEFORE 2 trace layers", &m_before);
print_row("AFTER 1 (global only)", &m_after);
println!(
"# {:.2}x wall, {:.1} fewer allocs/request",
m_before.wall_ns_per_op / m_after.wall_ns_per_op,
m_before.allocs_per_op - m_after.allocs_per_op
);
if m_after.wall_ns_per_op >= m_before.wall_ns_per_op {
eprintln!("GATE FAIL [H1]: dedup not faster — rollback");
std::process::exit(1);
}
}
// ────────────────────────────────────────────────────────────────────────────
// [H2] client_ip String vs borrow-only Display
// ────────────────────────────────────────────────────────────────────────────
fn section_client_ip() {
let iters: usize = env_or("BENCH_ITERS", 200_000);
// Three realistic request shapes.
let direct_peer: Option<SocketAddr> = Some("203.0.113.7:54321".parse().unwrap());
let empty_headers = HeaderMap::new();
let proxy_peer: Option<SocketAddr> = Some("10.0.0.1:443".parse().unwrap());
let mut xff_headers = HeaderMap::new();
xff_headers.insert(
"x-forwarded-for",
"198.51.100.23, 10.0.0.1".parse().unwrap(),
);
// Equivalence gate: Display output identical to the owned String for all
// shapes (note: the trusted-proxy branch only forwards when the peer is
// an actually-configured trusted CIDR; with none configured both peers
// render as the direct address — so the gate compares the SAME resolver
// logic on both sides, which is what matters for byte-identity).
for (headers, peer) in [
(&empty_headers, direct_peer),
(&xff_headers, proxy_peer),
(&empty_headers, None),
] {
let owned = client_ip_from_parts(headers, peer, true);
let borrowed = format!("{}", client_ip_display_from_parts(headers, peer, true));
assert_eq!(owned, borrowed, "client_ip bytes differ");
}
// Directly exercise every ClientIpDisplay variant's Display.
assert_eq!(
format!("{}", ClientIpDisplay::Forwarded("1.2.3.4")),
"1.2.3.4"
);
assert_eq!(
format!(
"{}",
ClientIpDisplay::PeerWithPort("5.6.7.8:9".parse().unwrap())
),
"5.6.7.8:9"
);
assert_eq!(
format!("{}", ClientIpDisplay::PeerIp("5.6.7.8".parse().unwrap())),
"5.6.7.8"
);
assert_eq!(format!("{}", ClientIpDisplay::Unknown), "unknown");
println!("# [H2] gate: borrow-only Display renders byte-identical to owned String — OK");
// The span records `client_ip = %ip`; emulate that terminal render into a
// reusable String (the span's field storage) for BOTH arms so we isolate
// the ONE allocation the owned resolver adds on top.
use std::fmt::Write as _;
let m_before = measure(iters, || {
let ip = client_ip_from_parts(black_box(&empty_headers), black_box(direct_peer), true);
let mut sink = String::new();
let _ = write!(sink, "{ip}");
black_box(sink);
});
let m_after = measure(iters, || {
let ip =
client_ip_display_from_parts(black_box(&empty_headers), black_box(direct_peer), true);
let mut sink = String::new();
let _ = write!(sink, "{ip}");
black_box(sink);
});
println!("\n## [H2] client_ip resolution for the span factory (direct peer)");
println!("| arm | ns/op | allocs/op |");
print_row("BEFORE owned String + render", &m_before);
print_row("AFTER borrow Display + render", &m_after);
println!(
"# {:.2}x wall, {:.1} fewer allocs/request",
m_before.wall_ns_per_op / m_after.wall_ns_per_op,
m_before.allocs_per_op - m_after.allocs_per_op
);
if m_after.allocs_per_op >= m_before.allocs_per_op {
eprintln!("GATE FAIL [H2]: borrow arm did not remove an allocation — rollback");
std::process::exit(1);
}
}
// ────────────────────────────────────────────────────────────────────────────
// [L1] Locale supported-codes: per-request rebuild vs precomputed borrow
// ────────────────────────────────────────────────────────────────────────────
fn section_locale() {
use oxicloud::common::locale::LocaleRegistry;
use std::path::Path;
let iters: usize = env_or("BENCH_ITERS", 200_000) / 2;
// Real registry over the shipped locales (16 JSON files).
let dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("frontend/static/locales");
let registry = match LocaleRegistry::discover(&dir, "en") {
Ok(r) => r,
Err(e) => {
println!("# [L1] skipped — locale registry unavailable: {e}");
return;
}
};
let n = registry.supported_codes().len();
// Equivalence gate: same code SET both ways (order differs — the
// Accept-Language crate ranks by header q-values, not list order).
let mut before_set: Vec<String> = registry.iter().map(|l| l.as_str().to_string()).collect();
let mut after_set: Vec<String> = registry.supported_codes().to_vec();
before_set.sort();
after_set.sort();
assert_eq!(before_set, after_set, "supported-code sets differ");
println!("# [L1] gate: rebuilt and precomputed supported-code sets identical ({n} codes) — OK");
// BEFORE, verbatim old extractor: N owned Strings + the &str view.
let m_before = measure(iters, || {
let owned: Vec<String> = registry.iter().map(|l| l.as_str().to_string()).collect();
let view: Vec<&str> = owned.iter().map(String::as_str).collect();
black_box(&view);
black_box(owned);
});
// AFTER: borrow the precomputed list; build only the &str view.
let m_after = measure(iters, || {
let view: Vec<&str> = registry
.supported_codes()
.iter()
.map(String::as_str)
.collect();
black_box(view);
});
println!("\n## [L1] Locale supported-codes for Accept-Language ({n} locales)");
println!("| arm | ns/op | allocs/op |");
print_row("BEFORE rebuild N Strings + view", &m_before);
print_row("AFTER borrow precomputed + view", &m_after);
println!(
"# {:.2}x wall, {:.1} fewer allocs per anonymous request",
m_before.wall_ns_per_op / m_after.wall_ns_per_op,
m_before.allocs_per_op - m_after.allocs_per_op
);
if m_after.wall_ns_per_op >= m_before.wall_ns_per_op {
eprintln!("GATE FAIL [L1]: precomputed borrow not faster — rollback");
std::process::exit(1);
}
}
fn main() {
println!("#################################################################");
println!("# Round-13 HTTP micro-pack");
println!("#################################################################\n");
section_trace_dedup();
section_client_ip();
section_locale();
println!("\nGATE PASS (all sections)");
}
+421
View File
@@ -0,0 +1,421 @@
//! Round-13 query-shape pack (needs the dev Postgres up; reads DATABASE_URL
//! from `.env`).
//!
//! Three sections, each BEFORE (verbatim replica of the shipped query shape)
//! vs AFTER (proposed shape), with equivalence/safety gates:
//!
//! [Q1] Group-notification recipient expansion — `get_users_by_ids`'s
//! 21-column row (incl. the ≤512 KiB avatar `image` + `ui_preferences`
//! JSONB) hydrated per member vs the notification-only projection
//! (drops both heavy columns; the caller reads only email/eligibility
//! fields).
//! [Q2] Login provisioning idempotency — `list_calendars_by_owner(..)
//! .is_empty()` / `get_address_books_by_owner(..).is_empty()` (hydrate
//! every owned row) vs `SELECT EXISTS(...)`.
//! [Q3] Recent-access recording — unconditional upsert + prune (2
//! round-trips) vs upsert-`RETURNING (xmax=0)` + prune-only-on-insert.
//!
//! Run:
//! cargo run --release --features bench --example bench_round13_queries
//! Tunables (env): BENCH_PASSES (200), BENCH_GROUP (30), BENCH_CALS (4),
//! BENCH_RECENT_CAP (50)
use std::env;
use std::sync::Arc;
use std::time::Instant;
use sqlx::postgres::PgPoolOptions;
use sqlx::{PgPool, Row};
use uuid::Uuid;
fn env_or<T: std::str::FromStr>(key: &str, default: T) -> T {
env::var(key)
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(default)
}
fn stats(mut s: Vec<f64>) -> (f64, f64, f64) {
s.sort_by(|a, b| a.partial_cmp(b).unwrap());
let n = s.len();
(
s.iter().sum::<f64>() / n as f64,
s[n / 2],
s[((n as f64 * 0.95) as usize).min(n - 1)],
)
}
// ────────────────────────────────────────────────────────────────────────────
// [Q1] Notification recipient expansion — wide row vs narrow projection
// ────────────────────────────────────────────────────────────────────────────
/// BEFORE, verbatim `get_users_by_ids` projection: 21 columns incl. `image`
/// and `ui_preferences`. Touch the heavy columns like `User::from_data_full`
/// does (materialize them) so the detoast/parse cost is counted.
async fn recipients_before(pool: &PgPool, ids: &[Uuid]) -> Vec<(Uuid, String, bool)> {
let rows = sqlx::query(
r#"
SELECT
id, username, email, password_hash, role::text as role_text,
storage_quota_bytes, storage_used_bytes,
created_at, updated_at, last_login_at, active,
oidc_provider, oidc_subject, image, is_external,
given_name, family_name, email_verified_at, preferred_locale, notify_on_share,
ui_preferences
FROM auth.users
WHERE id = ANY($1)
"#,
)
.bind(ids)
.fetch_all(pool)
.await
.expect("recipients wide");
rows.into_iter()
.map(|r| {
let _image: Option<String> = r.get("image");
let _prefs: serde_json::Value = r.get("ui_preferences");
(r.get("id"), r.get("email"), r.get("notify_on_share"))
})
.collect()
}
/// AFTER: the shipped narrow projection (image + ui_preferences dropped).
async fn recipients_after(pool: &PgPool, ids: &[Uuid]) -> Vec<(Uuid, String, bool)> {
let rows = sqlx::query(
r#"
SELECT
id, username, email, password_hash, role::text as role_text,
storage_quota_bytes, storage_used_bytes,
created_at, updated_at, last_login_at, active,
oidc_provider, oidc_subject, is_external,
given_name, family_name, email_verified_at, preferred_locale, notify_on_share
FROM auth.users
WHERE id = ANY($1)
"#,
)
.bind(ids)
.fetch_all(pool)
.await
.expect("recipients narrow");
rows.into_iter()
.map(|r| (r.get("id"), r.get("email"), r.get("notify_on_share")))
.collect()
}
async fn section_recipients(pool: &PgPool) {
let group: usize = env_or("BENCH_GROUP", 30);
let passes: usize = env_or("BENCH_PASSES", 200);
// Seed a group of avatared users (256 KiB data-URI each).
let mut ids = Vec::with_capacity(group);
for i in 0..group {
let id: Uuid = sqlx::query_scalar(
"INSERT INTO auth.users (username, email, role, image, notify_on_share)
VALUES ($1, $2, 'user', $3, true) RETURNING id",
)
.bind(format!("bench13_rcpt_{i:04}"))
.bind(format!("bench13_rcpt_{i:04}@bench.invalid"))
.bind(format!(
"data:image/png;base64,{}",
"QUJDRA==".repeat(32 * 1024)
))
.fetch_one(pool)
.await
.expect("seed recipient");
ids.push(id);
}
// Equivalence gate: same (id, email, notify) set either way.
let mut b = recipients_before(pool, &ids).await;
let mut a = recipients_after(pool, &ids).await;
b.sort();
a.sort();
assert_eq!(b, a, "recipient projections differ");
assert_eq!(a.len(), group, "expected all members");
println!("# [Q1] gate: wide/narrow recipient sets identical ({group} members) — OK");
let mut wide = Vec::with_capacity(passes);
for _ in 0..passes {
let t = Instant::now();
std::hint::black_box(recipients_before(pool, &ids).await);
wide.push(t.elapsed().as_secs_f64() * 1e3);
}
let mut narrow = Vec::with_capacity(passes);
for _ in 0..passes {
let t = Instant::now();
std::hint::black_box(recipients_after(pool, &ids).await);
narrow.push(t.elapsed().as_secs_f64() * 1e3);
}
let (wm, wp50, wp95) = stats(wide);
let (nm, np50, np95) = stats(narrow);
println!("\n## [Q1] Group-notification recipient expansion ({group} avatared members)");
println!("| arm | mean ms | p50 ms | p95 ms |");
println!("| BEFORE wide row (incl. image) | {wm:>8.3} | {wp50:>7.3} | {wp95:>7.3} |");
println!("| AFTER narrow (email fields) | {nm:>8.3} | {np50:>7.3} | {np95:>7.3} |");
println!(
"# {:.2}x faster, ~{} KiB avatar/ui_prefs off the wire per fan-out",
wm / nm,
group * 256
);
sqlx::query("DELETE FROM auth.users WHERE username LIKE 'bench13\\_rcpt\\_%'")
.execute(pool)
.await
.expect("cleanup recipients");
if nm >= wm {
eprintln!("GATE FAIL [Q1]: narrow not faster — rollback");
std::process::exit(1);
}
}
// ────────────────────────────────────────────────────────────────────────────
// [Q2] Login provisioning idempotency — hydrate-all vs EXISTS
// ────────────────────────────────────────────────────────────────────────────
async fn section_provisioning(pool: &PgPool) {
let cals: usize = env_or("BENCH_CALS", 4);
let passes: usize = env_or("BENCH_PASSES", 200);
let owner: Uuid = sqlx::query_scalar(
"INSERT INTO auth.users (username, email, role)
VALUES ('bench13_prov', 'bench13_prov@bench.invalid', 'user') RETURNING id",
)
.fetch_one(pool)
.await
.expect("seed owner");
for i in 0..cals {
sqlx::query(
"INSERT INTO caldav.calendars (id, name, owner_id, description, color)
VALUES (gen_random_uuid(), $1, $2, $3, '#3b82f6')",
)
.bind(format!("Cal {i}"))
.bind(owner)
.bind("A reasonably long calendar description to make the hydrated row wider")
.execute(pool)
.await
.expect("seed calendar");
}
async fn before_is_empty(pool: &PgPool, owner: Uuid) -> bool {
// Verbatim: hydrate every owned calendar row, then `.is_empty()`.
let rows = sqlx::query(
"SELECT id, name, owner_id, description, color, is_public, created_at, updated_at
FROM caldav.calendars WHERE owner_id = $1 ORDER BY name",
)
.bind(owner)
.fetch_all(pool)
.await
.expect("list calendars");
!rows.is_empty()
}
async fn after_exists(pool: &PgPool, owner: Uuid) -> bool {
sqlx::query_scalar("SELECT EXISTS(SELECT 1 FROM caldav.calendars WHERE owner_id = $1)")
.bind(owner)
.fetch_one(pool)
.await
.expect("exists")
}
// Gate: identical verdict, present and absent.
assert!(before_is_empty(pool, owner).await);
assert!(after_exists(pool, owner).await);
let ghost = Uuid::new_v4();
assert_eq!(
before_is_empty(pool, ghost).await,
after_exists(pool, ghost).await
);
println!("# [Q2] gate: hydrate-all and EXISTS agree (present + absent) — OK");
let mut before = Vec::with_capacity(passes);
for _ in 0..passes {
let t = Instant::now();
std::hint::black_box(before_is_empty(pool, owner).await);
before.push(t.elapsed().as_secs_f64() * 1e3);
}
let mut after = Vec::with_capacity(passes);
for _ in 0..passes {
let t = Instant::now();
std::hint::black_box(after_exists(pool, owner).await);
after.push(t.elapsed().as_secs_f64() * 1e3);
}
let (bm, bp50, bp95) = stats(before);
let (am, ap50, ap95) = stats(after);
println!("\n## [Q2] Login provisioning idempotency probe ({cals} owned calendars)");
println!("| arm | mean ms | p50 ms | p95 ms |");
println!("| BEFORE list+hydrate .is_empty() | {bm:>7.3} | {bp50:>7.3} | {bp95:>7.3} |");
println!("| AFTER SELECT EXISTS | {am:>7.3} | {ap50:>7.3} | {ap95:>7.3} |");
println!(
"# {:.2}x faster per login probe (×2: calendar + address book)",
bm / am
);
sqlx::query("DELETE FROM caldav.calendars WHERE owner_id = $1")
.bind(owner)
.execute(pool)
.await
.ok();
sqlx::query("DELETE FROM auth.users WHERE id = $1")
.bind(owner)
.execute(pool)
.await
.ok();
if am >= bm {
eprintln!("GATE FAIL [Q2]: EXISTS not faster — rollback");
std::process::exit(1);
}
}
// ────────────────────────────────────────────────────────────────────────────
// [Q3] Recent-access recording — upsert+prune (2 RTT) vs prune-on-insert
// ────────────────────────────────────────────────────────────────────────────
async fn section_recent(pool: &PgPool) {
let cap: i32 = env_or("BENCH_RECENT_CAP", 50);
let passes: usize = env_or("BENCH_PASSES", 200);
let user: Uuid = sqlx::query_scalar(
"INSERT INTO auth.users (username, email, role)
VALUES ('bench13_recent', 'bench13_recent@bench.invalid', 'user') RETURNING id",
)
.fetch_one(pool)
.await
.expect("seed recent user");
async fn upsert_before(pool: &PgPool, user: Uuid, item: &str) {
sqlx::query(
"INSERT INTO auth.user_recent_files (user_id, item_id, item_type, accessed_at)
VALUES ($1, $2, 'file', CURRENT_TIMESTAMP)
ON CONFLICT (user_id, item_id, item_type)
DO UPDATE SET accessed_at = CURRENT_TIMESTAMP",
)
.bind(user)
.bind(item)
.execute(pool)
.await
.expect("upsert");
}
async fn prune(pool: &PgPool, user: Uuid, cap: i32) {
sqlx::query(
"DELETE FROM auth.user_recent_files
WHERE id IN (SELECT id FROM auth.user_recent_files
WHERE user_id = $1 ORDER BY accessed_at DESC OFFSET $2)",
)
.bind(user)
.bind(cap)
.execute(pool)
.await
.expect("prune");
}
async fn upsert_after(pool: &PgPool, user: Uuid, item: &str) -> bool {
sqlx::query_scalar(
"INSERT INTO auth.user_recent_files (user_id, item_id, item_type, accessed_at)
VALUES ($1, $2, 'file', CURRENT_TIMESTAMP)
ON CONFLICT (user_id, item_id, item_type)
DO UPDATE SET accessed_at = CURRENT_TIMESTAMP
RETURNING (xmax = 0)",
)
.bind(user)
.bind(item)
.fetch_one(pool)
.await
.expect("upsert returning")
}
// Fill to the cap so the set is at steady state.
for i in 0..cap {
upsert_before(pool, user, &format!("seed-{i:04}")).await;
}
// Gate: the AFTER path must keep the row count at the cap AND flag
// insert-vs-update correctly. Re-access an existing item → update (no
// prune); a brand-new item → insert (prune keeps count == cap).
let existing = "seed-0000";
assert!(
!upsert_after(pool, user, existing).await,
"re-access must be an UPDATE"
);
let fresh = "gate-new-item";
assert!(
upsert_after(pool, user, fresh).await,
"new item must be an INSERT"
);
prune(pool, user, cap).await;
let count: i64 =
sqlx::query_scalar("SELECT COUNT(*) FROM auth.user_recent_files WHERE user_id = $1")
.bind(user)
.fetch_one(pool)
.await
.unwrap();
assert_eq!(count, cap as i64, "prune-on-insert keeps the cap");
println!("# [Q3] gate: xmax flags insert/update, count stays at cap — OK");
// BEFORE: every record = upsert + prune (2 round-trips). Model the
// common case — re-accessing items already in the set (all UPDATEs).
let mut before = Vec::with_capacity(passes);
for i in 0..passes {
let item = format!("seed-{:04}", i % cap as usize);
let t = Instant::now();
upsert_before(pool, user, &item).await;
prune(pool, user, cap).await;
before.push(t.elapsed().as_secs_f64() * 1e3);
}
// AFTER: upsert RETURNING; prune only when inserted (never, here).
let mut after = Vec::with_capacity(passes);
for i in 0..passes {
let item = format!("seed-{:04}", i % cap as usize);
let t = Instant::now();
let inserted = upsert_after(pool, user, &item).await;
if inserted {
prune(pool, user, cap).await;
}
after.push(t.elapsed().as_secs_f64() * 1e3);
}
let (bm, bp50, bp95) = stats(before);
let (am, ap50, ap95) = stats(after);
println!("\n## [Q3] Recent-access recording (re-access = UPDATE, common path)");
println!("| arm | mean ms | p50 ms | p95 ms |");
println!("| BEFORE upsert + prune (2 RTT) | {bm:>7.3} | {bp50:>7.3} | {bp95:>7.3} |");
println!("| AFTER upsert; prune-on-insert | {am:>7.3} | {ap50:>7.3} | {ap95:>7.3} |");
println!(
"# {:.2}x faster on re-access; prune round-trip skipped",
bm / am
);
sqlx::query("DELETE FROM auth.user_recent_files WHERE user_id = $1")
.bind(user)
.execute(pool)
.await
.ok();
sqlx::query("DELETE FROM auth.users WHERE id = $1")
.bind(user)
.execute(pool)
.await
.ok();
if am >= bm {
eprintln!("GATE FAIL [Q3]: prune-on-insert not faster — rollback");
std::process::exit(1);
}
}
#[tokio::main(flavor = "multi_thread", worker_threads = 4)]
async fn main() {
let _ = dotenvy::dotenv();
let url = std::env::var("DATABASE_URL").expect("DATABASE_URL required (see .env)");
let pool = Arc::new(
PgPoolOptions::new()
.max_connections(8)
.connect(&url)
.await
.expect("connect"),
);
println!("#################################################################");
println!("# Round-13 query-shape pack");
println!("#################################################################");
section_recipients(&pool).await;
section_provisioning(&pool).await;
section_recent(&pool).await;
println!("\nGATE PASS (all sections)");
}