Files
Oxicloud/examples/bench_round10_micro.rs
T
Claude c51af68432 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
2026-07-18 20:33:50 +00:00

582 lines
21 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Round-10 CPU/alloc micro-pack — BEFORE replicas vs the shipped code.
//!
//! Sections (all pure CPU, no Postgres):
//! 1. Authenticated-request identity build (Bearer/cookie hit path):
//! BEFORE `String` claims clone ×2 + live-role `to_string` + `Arc::new`
//! vs AFTER `Arc<str>` refcount bumps + inline `SmolStr` + `Arc::new`.
//! 2. Basic-auth cache hit: BEFORE `CachedBasicAuthResult{String}` moka
//! value clone vs AFTER `Arc<str>`/`SmolStr` bumps.
//! 3. NC PROPFIND per-row integer props (`oc:fileid`, `nc:creation_time`,
//! `nc:upload_time`): BEFORE `to_string()` per field vs AFTER
//! `common::fmt` stack render. Gate: byte-identical XML.
//! 4. NC trashbin date/int props: BEFORE `to_rfc2822()` + `to_string()`
//! vs AFTER stack render. Gate: byte-identical XML.
//! 5. Native-WebDAV scope prefix test: BEFORE `format!("{prefix}/")` per
//! request vs AFTER borrow-only check. Gate: identical routing.
//! 6. Share listing base-url: BEFORE `env::var("OXICLOUD_BASE_URL")` +
//! rebuild per row vs AFTER the construction-time snapshot.
//! 7. JWT verify miss: BEFORE fresh `Validation` + `DecodingKey` per
//! decode vs AFTER pre-built fields. Gate: identical claims.
//! 8. AES-GCM cipher hand-off: BEFORE key-schedule memcpy clone vs AFTER
//! `Arc` bump.
//! 9. Request-id header: BEFORE `Uuid::to_string` + `HeaderValue::from_str`
//! vs AFTER stack-encode. Gate: identical header bytes.
//!
//! Run: cargo run --release --features bench --example bench_round10_micro
//! Tunables (env): BENCH_ITERS (100000)
use std::alloc::{GlobalAlloc, Layout, System};
use std::env;
use std::hint::black_box;
use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::Instant;
use smol_str::SmolStr;
// ─── Counting allocator ─────────────────────────────────────────────────────
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)
}
fn measure<R>(label: &str, iters: u64, mut f: impl FnMut() -> R) -> (f64, f64) {
// Warmup
for _ in 0..1000 {
black_box(f());
}
let a0 = ALLOC_CALLS.load(Ordering::Relaxed);
let t0 = Instant::now();
for _ in 0..iters {
black_box(f());
}
let wall = t0.elapsed().as_secs_f64();
let allocs = (ALLOC_CALLS.load(Ordering::Relaxed) - a0) as f64 / iters as f64;
let ns = wall * 1e9 / iters as f64;
println!(" {label:<44} {ns:>9.1} ns/op {allocs:>7.3} allocs/op");
(ns, allocs)
}
// ─── §1 BEFORE replicas: old claim/identity shapes ──────────────────────────
mod before {
use std::sync::Arc;
/// Old `TokenClaims` shape (owned Strings). The unread fields keep
/// the replica byte-faithful to the historical struct layout.
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct OldTokenClaims {
pub sub: String,
pub exp: i64,
pub iat: i64,
pub jti: String,
pub username: String,
pub email: String,
pub role: String,
}
/// Old `CurrentUser` shape.
#[derive(Debug, Clone, serde::Serialize)]
pub struct OldCurrentUser {
pub id: uuid::Uuid,
pub username: String,
pub email: String,
pub role: String,
}
/// Old Bearer-hit tail: deep-clone the two display fields out of the
/// cached claims + `to_string` the live role + `Arc::new`.
pub fn bearer_identity(claims: &Arc<OldTokenClaims>, live_role: &str) -> Arc<OldCurrentUser> {
let role = live_role.to_string(); // decide_live_role's `flags.role.to_string()`
Arc::new(OldCurrentUser {
id: uuid::Uuid::nil(),
username: claims.username.clone(),
email: claims.email.clone(),
role,
})
}
/// Old Basic-auth cached value (owned Strings — moka clones on get).
#[derive(Clone)]
pub struct OldCachedBasic {
pub user_id: uuid::Uuid,
pub username: String,
pub email: String,
pub role: String,
}
}
fn section_identity(iters: u64) {
use oxicloud::application::dtos::user_dto::CurrentUser;
use oxicloud::application::ports::auth_ports::TokenClaims;
println!("[1] authenticated-request identity build (per request)");
let old_claims = Arc::new(before::OldTokenClaims {
sub: "6a11f8a2-14a5-4f8a-9d55-3e3c8a2b9a01".into(),
exp: 4_102_444_800,
iat: 1_700_000_000,
jti: uuid::Uuid::nil().to_string(),
username: "alice.longname".to_string(),
email: "alice.longname@example.com".to_string(),
role: "user".to_string(),
});
let new_claims = Arc::new(TokenClaims {
sub: "6a11f8a2-14a5-4f8a-9d55-3e3c8a2b9a01".into(),
exp: 4_102_444_800,
iat: 1_700_000_000,
jti: uuid::Uuid::nil().to_string(),
username: Arc::from("alice.longname"),
email: Arc::from("alice.longname@example.com"),
role: "user".to_string(),
});
let (bn, ba) = measure("BEFORE String clones + role to_string", iters, || {
before::bearer_identity(black_box(&old_claims), black_box("user"))
});
let (an, aa) = measure("AFTER Arc bumps + inline SmolStr", iters, || {
// The shipped middleware tail: LiveRole render + CurrentUser build.
let role = SmolStr::new_static("user");
Arc::new(CurrentUser {
id: uuid::Uuid::nil(),
username: Arc::clone(&black_box(&new_claims).username),
email: Arc::clone(&new_claims.email),
role,
})
});
// Gate: identical field values + identical JSON wire shape.
let old = before::bearer_identity(&old_claims, "user");
let new = Arc::new(CurrentUser {
id: uuid::Uuid::nil(),
username: Arc::clone(&new_claims.username),
email: Arc::clone(&new_claims.email),
role: SmolStr::new_static("user"),
});
assert_eq!(old.username, *new.username);
assert_eq!(old.email, *new.email);
assert_eq!(old.role, new.role.as_str());
let json_old = serde_json::to_string(&*old).unwrap();
let json_new = serde_json::to_string(&*new).unwrap();
assert_eq!(json_old, json_new, "CurrentUser JSON shape must not change");
println!(
" gate: fields + JSON byte-identical ✓ ({bn:.0}→{an:.0} ns, {ba:.2}→{aa:.2} allocs)"
);
}
fn section_basic_hit(iters: u64) {
println!("[2] basic-auth cache hit → tuple hand-off (per DAV request)");
let old_val = before::OldCachedBasic {
user_id: uuid::Uuid::nil(),
username: "dav.client.user".to_string(),
email: "dav.client.user@example.com".to_string(),
role: "user".to_string(),
};
struct NewCachedBasic {
user_id: uuid::Uuid,
username: Arc<str>,
email: Arc<str>,
role: SmolStr,
}
impl Clone for NewCachedBasic {
fn clone(&self) -> Self {
Self {
user_id: self.user_id,
username: Arc::clone(&self.username),
email: Arc::clone(&self.email),
role: self.role.clone(),
}
}
}
let new_val = NewCachedBasic {
user_id: uuid::Uuid::nil(),
username: Arc::from("dav.client.user"),
email: Arc::from("dav.client.user@example.com"),
role: SmolStr::new_static("user"),
};
let (bn, ba) = measure("BEFORE moka value clone (3 Strings)", iters, || {
let v = black_box(&old_val).clone(); // what moka's get does
(v.user_id, v.username, v.email, v.role)
});
let (an, aa) = measure("AFTER moka value clone (bumps)", iters, || {
let v = black_box(&new_val).clone();
(v.user_id, v.username, v.email, v.role)
});
let o = old_val.clone();
let n = new_val.clone();
assert_eq!(o.username, *n.username);
assert_eq!(o.email, *n.email);
assert_eq!(o.role, n.role.as_str());
println!(
" gate: identity fields identical ✓ ({bn:.0}→{an:.0} ns, {ba:.2}→{aa:.2} allocs)"
);
}
// ─── §3/§4 XML emit ─────────────────────────────────────────────────────────
fn write_text_element(
xml: &mut quick_xml::Writer<&mut Vec<u8>>,
tag: &str,
value: &str,
) -> Result<(), String> {
use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
xml.write_event(Event::Start(BytesStart::new(tag)))
.map_err(|e| e.to_string())?;
xml.write_event(Event::Text(BytesText::new(value)))
.map_err(|e| e.to_string())?;
xml.write_event(Event::End(BytesEnd::new(tag)))
.map_err(|e| e.to_string())?;
Ok(())
}
fn section_propfind_ints(iters: u64) {
println!("[3] NC PROPFIND per-row integer props (500-row page)");
let rows: Vec<(i64, u64, u64)> = (0..500)
.map(|i| (912_345_678 + i as i64, 1_700_000_000 + i, 1_700_000_100 + i))
.collect();
let emit_before = |buf: &mut Vec<u8>| {
let mut xml = quick_xml::Writer::new(buf);
for &(fid, created, modified) in &rows {
write_text_element(&mut xml, "oc:fileid", &fid.to_string()).unwrap();
write_text_element(&mut xml, "nc:creation_time", &created.to_string()).unwrap();
write_text_element(&mut xml, "nc:upload_time", &modified.to_string()).unwrap();
}
};
let emit_after = |buf: &mut Vec<u8>| {
let mut xml = quick_xml::Writer::new(buf);
for &(fid, created, modified) in &rows {
let mut ibuf = [0u8; 21];
write_text_element(
&mut xml,
"oc:fileid",
oxicloud::common::fmt::i64_str(&mut ibuf, fid),
)
.unwrap();
let mut ubuf = [0u8; 20];
write_text_element(
&mut xml,
"nc:creation_time",
oxicloud::common::fmt::u64_str(&mut ubuf, created),
)
.unwrap();
write_text_element(
&mut xml,
"nc:upload_time",
oxicloud::common::fmt::u64_str(&mut ubuf, modified),
)
.unwrap();
}
};
let mut b1 = Vec::with_capacity(64 * 1024);
emit_before(&mut b1);
let mut b2 = Vec::with_capacity(64 * 1024);
emit_after(&mut b2);
assert_eq!(b1, b2, "XML must be byte-identical");
let page_iters = iters / 500;
let (bn, ba) = measure("BEFORE to_string per int field", page_iters, || {
let mut buf = Vec::with_capacity(64 * 1024);
emit_before(&mut buf);
buf
});
let (an, aa) = measure("AFTER stack i64_str/u64_str", page_iters, || {
let mut buf = Vec::with_capacity(64 * 1024);
emit_after(&mut buf);
buf
});
println!(
" gate: 500-row page byte-identical ✓ page: {:.1}→{:.1} µs, {:.0}→{:.0} allocs",
bn / 1e3,
an / 1e3,
ba,
aa
);
}
fn section_trashbin(iters: u64) {
println!("[4] NC trashbin per-item date/int props (2000-item bin)");
let items: Vec<i64> = (0..2000).map(|i| 1_700_000_000 + i * 37).collect();
let emit_before = |buf: &mut Vec<u8>| {
let mut xml = quick_xml::Writer::new(buf);
for &ts in &items {
let dt = chrono::DateTime::<chrono::Utc>::from_timestamp(ts, 0).unwrap();
write_text_element(&mut xml, "d:getlastmodified", &dt.to_rfc2822()).unwrap();
write_text_element(&mut xml, "nc:trashbin-deletion-time", &ts.to_string()).unwrap();
}
};
let emit_after = |buf: &mut Vec<u8>| {
let mut xml = quick_xml::Writer::new(buf);
for &ts in &items {
let mut dbuf = [0u8; 31];
// The shipped path goes through write_date_element → rfc2822_utc
// with a chrono fallback; in-range timestamps take the stack path.
let s = oxicloud::common::fmt::rfc2822_utc(&mut dbuf, ts).unwrap();
write_text_element(&mut xml, "d:getlastmodified", s).unwrap();
let mut ibuf = [0u8; 21];
write_text_element(
&mut xml,
"nc:trashbin-deletion-time",
oxicloud::common::fmt::i64_str(&mut ibuf, ts),
)
.unwrap();
}
};
let mut b1 = Vec::with_capacity(256 * 1024);
emit_before(&mut b1);
let mut b2 = Vec::with_capacity(256 * 1024);
emit_after(&mut b2);
assert_eq!(b1, b2, "trashbin XML must be byte-identical");
let bin_iters = (iters / 2000).max(20);
let (bn, ba) = measure("BEFORE chrono to_rfc2822 + to_string", bin_iters, || {
let mut buf = Vec::with_capacity(256 * 1024);
emit_before(&mut buf);
buf
});
let (an, aa) = measure("AFTER stack rfc2822_utc + i64_str", bin_iters, || {
let mut buf = Vec::with_capacity(256 * 1024);
emit_after(&mut buf);
buf
});
println!(
" gate: 2000-item bin byte-identical ✓ bin: {:.1}→{:.1} µs, {:.0}→{:.0} allocs",
bn / 1e3,
an / 1e3,
ba,
aa
);
}
// ─── §5 webdav scope prefix ─────────────────────────────────────────────────
fn section_scope_prefix(iters: u64) {
println!("[5] native-WebDAV scope prefix test (per request)");
// 1:1 replicas of the two shapes (the production fn is handler-private).
fn before_route(normalized: &str, marker: &str) -> Option<usize> {
let with_slash = format!("{}/", marker);
normalized.strip_prefix(&with_slash).map(|r| r.len())
}
fn strip_prefix_slash<'a>(s: &'a str, prefix: &str) -> Option<&'a str> {
s.strip_prefix(prefix)?.strip_prefix('/')
}
fn after_route(normalized: &str, marker: &str) -> Option<usize> {
strip_prefix_slash(normalized, marker).map(|r| r.len())
}
let cases = [
("@drive/Personal/Photos/2026/img.jpg", "@drive"),
("Personal/Documents/report.pdf", "@drive"),
("@drive", "@drive"),
("@driveX/nope", "@drive"),
];
for (path, marker) in cases {
assert_eq!(before_route(path, marker), after_route(path, marker));
}
let (bn, ba) = measure("BEFORE format!(\"{prefix}/\") probe", iters, || {
before_route(
black_box("@drive/Personal/Photos/2026/img.jpg"),
black_box("@drive"),
)
});
let (an, aa) = measure("AFTER borrow-only probe", iters, || {
after_route(
black_box("@drive/Personal/Photos/2026/img.jpg"),
black_box("@drive"),
)
});
println!(
" gate: routing identical on all shapes ✓ ({bn:.0}→{an:.0} ns, {ba:.2}→{aa:.2} allocs)"
);
}
// ─── §6 base_url ────────────────────────────────────────────────────────────
fn section_base_url(iters: u64) {
println!("[6] share-listing base_url (per 500-row listing)");
unsafe {
env::set_var("OXICLOUD_BASE_URL", "https://cloud.example.com");
}
let config = oxicloud::common::config::AppConfig::default();
let rows = 500usize;
let before_listing = || {
let mut total = 0usize;
for _ in 0..rows {
total += config.base_url().len(); // env read + String per row
}
total
};
let snapshot = config.base_url();
let after_listing = || {
let mut total = 0usize;
for _ in 0..rows {
total += snapshot.len(); // field read
}
total
};
assert_eq!(before_listing(), after_listing());
let listing_iters = (iters / rows as u64).max(50);
let (bn, ba) = measure("BEFORE env::var + rebuild per row", listing_iters, || {
before_listing()
});
let (an, aa) = measure("AFTER construction-time snapshot", listing_iters, || {
after_listing()
});
println!(
" gate: identical URLs ✓ listing: {:.1}→{:.3} µs, {:.0}→{:.0} allocs",
bn / 1e3,
an / 1e3,
ba,
aa
);
}
// ─── §7 JWT verify miss ─────────────────────────────────────────────────────
fn section_jwt(iters: u64) {
use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, Validation, decode, encode};
println!("[7] JWT verify (validation-cache miss path)");
#[derive(serde::Serialize, serde::Deserialize)]
struct C {
sub: String,
exp: i64,
iat: i64,
jti: String,
username: String,
email: String,
role: String,
}
let secret = "bench_secret_key_at_least_32_bytes_long!";
let claims = C {
sub: uuid::Uuid::nil().to_string(),
exp: 4_102_444_800,
iat: 1_700_000_000,
jti: uuid::Uuid::nil().to_string(),
username: "alice".into(),
email: "alice@example.com".into(),
role: "user".into(),
};
let token = encode(
&Header::default(),
&claims,
&EncodingKey::from_secret(secret.as_bytes()),
)
.unwrap();
let jwt_iters = iters / 10;
let (bn, ba) = measure("BEFORE fresh Validation+DecodingKey", jwt_iters, || {
let validation = Validation::new(Algorithm::HS256);
let key = DecodingKey::from_secret(secret.as_bytes());
decode::<C>(black_box(&token), &key, &validation)
.unwrap()
.claims
.exp
});
let key = DecodingKey::from_secret(secret.as_bytes());
let validation = Validation::new(Algorithm::HS256);
let (an, aa) = measure("AFTER pre-built service fields", jwt_iters, || {
decode::<C>(black_box(&token), &key, &validation)
.unwrap()
.claims
.exp
});
println!(" gate: same decode result ✓ ({bn:.0}→{an:.0} ns, {ba:.2}→{aa:.2} allocs)");
}
// ─── §8 cipher clone ────────────────────────────────────────────────────────
fn section_cipher(iters: u64) {
use aes_gcm::{Aes256Gcm, KeyInit};
println!("[8] AES-GCM cipher hand-off (per blob op)");
let cipher = Aes256Gcm::new_from_slice(&[7u8; 32]).unwrap();
let arc_cipher = Arc::new(Aes256Gcm::new_from_slice(&[7u8; 32]).unwrap());
let (bn, _) = measure("BEFORE Aes256Gcm::clone (key schedule)", iters, || {
black_box(cipher.clone())
});
let (an, _) = measure("AFTER Arc<Aes256Gcm>::clone (bump)", iters, || {
black_box(Arc::clone(&arc_cipher))
});
println!(" gate: n/a (same cipher key, encryption unchanged) ({bn:.1}→{an:.1} ns)");
}
// ─── §9 request-id ──────────────────────────────────────────────────────────
fn section_request_id(iters: u64) {
println!("[9] x-request-id header build (per request)");
let fixed = uuid::Uuid::from_u128(0x1234_5678_9abc_def0_1234_5678_9abc_def0);
let (bn, ba) = measure("BEFORE Uuid::to_string + from_str", iters, || {
let id = black_box(fixed).to_string();
axum::http::HeaderValue::from_str(&id).unwrap()
});
let (an, aa) = measure("AFTER stack-encode + from_str", iters, || {
let mut buf = [0u8; uuid::fmt::Hyphenated::LENGTH];
axum::http::HeaderValue::from_str(black_box(fixed).hyphenated().encode_lower(&mut buf))
.unwrap()
});
let a = {
let id = fixed.to_string();
axum::http::HeaderValue::from_str(&id).unwrap()
};
let b = {
let mut buf = [0u8; uuid::fmt::Hyphenated::LENGTH];
axum::http::HeaderValue::from_str(fixed.hyphenated().encode_lower(&mut buf)).unwrap()
};
assert_eq!(a, b, "header bytes must be identical");
println!(" gate: header bytes identical ✓ ({bn:.0}→{an:.0} ns, {ba:.2}→{aa:.2} allocs)");
}
fn main() {
let iters: u64 = env_or("BENCH_ITERS", 100_000);
println!("bench_round10_micro — iters={iters}\n");
section_identity(iters);
section_basic_hit(iters);
section_propfind_ints(iters);
section_trashbin(iters);
section_scope_prefix(iters);
section_base_url(iters);
section_jwt(iters);
section_cipher(iters);
section_request_id(iters);
println!("\nall gates passed");
}