Files
Oxicloud/Cargo.toml
T
Claude 992bdae898 perf: round 22 — hot-GET HeaderMap borrow, native-WebDAV/CalDAV etag borrowed quotes, FileDto content_hash move, CalendarEvent stamp, ShareItemType case-fold
Benchmark-gated, same rule as ROUND2-21: every change ships with a
BEFORE/AFTER counting-allocator benchmark and a byte/-value equivalence
gate; an AFTER that fails to reduce allocations exits non-zero (rollback).
See benches/ROUND22.md and examples/bench_round22_micro.rs. All arms
no-Postgres.

- H1: the hot GET handlers (get_thumbnail, download_file, list_files_query,
  list_photos, NextCloud preview, public-share download/access) take
  `req: Request` last and read `req.headers()` by borrow instead of axum's
  HeaderMap extractor, whose FromRequestParts impl clones the whole request
  header table just to read 1-3 headers (the ROUND14 §A4 middleware pattern,
  finally propagated to the handlers). 2 -> 0 allocs/req · 9.95x wall.
- W1: native WebDAV write_etag_quoted — the etag emitter for every /webdav/
  PROPFIND row (per file AND per folder, up to 500/page) — emits the quotes
  as borrowed pre-escaped " text events instead of escaping a "{etag}"
  String (the ROUND20 §C1 / ROUND21 §R4 pattern). 3 -> 0 allocs/row.
- C1: CalDAV getetag routed through a shared write_quoted_etag helper across
  all 5 sites (3 per-event + 2 per-calendar); the now-dead etag: &mut String
  buffer threaded through write_event_response/standard/requested props + the
  two per-page buffers removed. 2 -> 0 allocs/row.
- D1: FileDto::from reuses the moved parts.blob_hash instead of cloning it
  via the content_hash() getter (the ROUND19/20 move-not-clone sweep missed
  it — hash/etag are read before into_parts()). Per file row of every
  listing. 1 -> 0 allocs/row.
- E1: CalendarEvent::update_time_range/update_all_day stamp timed
  DTSTART/DTEND via fmt::compact_ical_utc stack render (chrono fallback out
  of range) instead of the %Y%m%dT%H%M%SZ strftime interpreter. 4 -> 0.
- S1: ShareItemType::try_from uses eq_ignore_ascii_case instead of a
  throwaway to_lowercase() String. 1 -> 0 allocs/parse.

Verified: cargo clippy --features bench --all-targets -D warnings clean,
cargo fmt --all --check clean, cargo test --lib --features bench = 529
passed / 0 failed (incl. the OpenAPI-spec-validity test guarding the H1
utoipa-handler signature change).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKyQ4AnYtgp1JtjzweyMeo
2026-07-20 13:48:47 +00:00

772 lines
33 KiB
TOML
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.
[package]
name = "oxicloud"
version = "0.8.2"
edition = "2024"
default-run = "oxicloud"
[dependencies]
mimalloc = { version = "0.1.52", default-features = false }
axum = { version = "0.8.9", features = ["multipart", "http1", "http2", "tokio", "macros"] }
# "process" was previously enabled implicitly through aws-config's feature
# unification; ffmpeg_video_frame_service needs it, so declare it ourselves.
tokio = { version = "1.52.3", features = ["rt-multi-thread", "macros", "io-util", "net", "time", "sync", "fs", "process"] }
tokio-util = { version = "0.7.18", features = ["io", "codec", "compat"] }
tokio-stream = { version = "0.1.18", features = ["fs", "sync"] }
bytes = "1.11.1"
tempfile = "3.27.0"
tower = "0.5.3"
tower-http = { version = "0.6.11", features = ["fs", "compression-gzip", "compression-br", "trace", "cors", "add-extension", "request-id", "set-header", "limit"] }
flate2 = "1.1.9"
tracing = "0.1.44"
tracing-subscriber = { version = "0.3.23", features = ["env-filter"] }
chrono = { version = "0.4.45", features = ["serde"] }
# RFC 5545 iCalendar parser + emitter.
#
# Adopted 2026-07-14 to replace the hand-rolled property-scan in
# `src/domain/entities/calendar_event.rs::extract_ical_property`,
# which used a naive `format!("\n{}:", name)` substring search and
# refused ANY property carrying parameters (`DTSTART;VALUE=DATE:...`,
# `RECURRENCE-ID;VALUE=DATE:...`, `ATTENDEE;CN=…;PARTSTAT=…:mailto:…`).
# That broke all-day events and made the domain unaware of exception
# instances (see AtalayaLabs/OxiCloud#528).
#
# The crate is the widely-used Rust parser (~1500 SLOC, MIT/Apache),
# actively maintained by @Peltoche as `ical-rs` on GitHub. It handles
# line-folding, escaped characters, parameter maps, and every standard
# component. If a spec conformance gap is found, we contribute upstream.
ical = "0.11"
http-body = "1.0.1"
serde = { version = "1.0.228", features = ["derive", "rc"] }
serde_json = "1.0.150"
futures = "0.3.32"
async-stream = "0.3.6"
async-trait = "0.1.89"
mime_guess = "2.0.5"
uuid = { version = "1.23.3", features = ["v4", "v7", "serde"] }
thiserror = "2.0.18"
mockall = { version = "0.14.0", optional = true }
sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio", "tls-rustls", "chrono", "uuid", "json", "migrate"] }
jsonwebtoken = { version = "10.4.0", features = ["rust_crypto"] }
argon2 = "0.5.3"
rand_core = { version = "0.6", features = ["std", "getrandom"] }
quick-xml = "0.41.0"
dotenvy = "0.15.7"
moka = { version = "0.12.15", features = ["future", "sync"] }
http-range-header = "0.4"
image = { version = "0.25.10", default-features = false, features = ["jpeg", "png", "gif", "webp"] }
# Shrink-on-load JPEG decode (DCT 1/2·1/4·1/8 scaling) for thumbnails — pure
# Rust, no C toolchain. The `image` crate's zune-jpeg backend can't scale during
# decode; this can, cutting decode time/RAM ~order-of-magnitude on large photos.
jpeg-decoder = "0.3"
# SIMD (AVX2/SSE4.1/NEON) image resizing for thumbnails — far faster than the
# `image` crate's scalar resampler, and it speeds every format (incl. PNG/WebP).
fast_image_resize = "5"
# Lossy WebP encoding for thumbnails. The `image` crate's webp feature is
# lossless-only; this binds libwebp (vendored + built via `cc`, no system dep)
# for quality-controlled lossy output (~25-30% smaller than JPEG at equal SSIM).
webp = "0.3"
id3 = "1.17"
mp3-duration = "0.1"
kamadak-exif = "0.6.1"
md-5 = "0.11.0"
sha2 = "0.11.0"
unicode-normalization = "0.1.25"
blake3 = { version = "1.8.5", features = ["rayon", "mmap"] }
hex = "0.4.3"
http-body-util = "0.1.3"
percent-encoding = "2.3.2"
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls-webpki-roots","rustls-tls-native-roots"] }
base64 = "0.22.1"
fs2 = "0.4"
rayon = "1.12.0"
infer = "0.19"
async-compression = { version = "0.4.42", features = ["tokio", "gzip"] }
async_zip = { version = "0.0.18", features = ["tokio", "deflate"] }
dashmap = "6.2.1"
socket2 = { version = "0.6.4", features = ["all"] }
urlencoding = "2.1.3"
utoipa = { version = "5.5.0", features = ["axum_extras", "uuid", "chrono"] }
# NOTE: aws-config and aws-smithy-types were removed as direct deps in the
# round-3 perf pass — S3BlobBackend builds its client purely from
# aws_sdk_s3::config with static credentials; nothing referenced either
# crate, and aws-config alone pulled aws-sdk-sso/ssooidc/sts (~90 crates)
# into every build (benches/ROUND3.md).
aws-sdk-s3 = "1.136.0"
azure_core = { version = "0.21", default-features = false, features = ["enable_reqwest_rustls", "hmac_rust"] }
azure_storage = { version = "0.21", default-features = false, features = ["enable_reqwest_rustls", "hmac_rust"] }
azure_storage_blobs = { version = "0.21", default-features = false, features = ["enable_reqwest_rustls", "hmac_rust"] }
aes-gcm = "0.10.3"
lru = "0.16.4"
fastcdc = { version = "4.0.0", features = ["tokio"] }
lettre = { version = "0.11.18", default-features = false, features = ["smtp-transport", "tokio1-rustls-tls", "rustls-native-certs", "builder"] }
idna = "1.1"
smol_str = { version = "0.3.6", features = ["serde"] }
accept-language = "3.1.0"
askama = "0.16.0"
tantivy = "0.26.1"
zip = { version = "8.6.0", default-features = false, features = ["deflate"] }
pdf-extract = "0.12.0"
nom-exif = "3.6.1"
extism = { version = "1.30.0", optional = true }
toml = { version = "1.1.2", optional = true }
file-rotate = { version = "0.7.6", optional = true }
ort = { version = "2.0.0-rc.12", default-features = false, features = ["load-dynamic", "ndarray", "tracing", "api-24"], optional = true }
ndarray = { version = "0.17.2", optional = true }
[features]
default = []
test_utils = ["mockall"]
integration_tests = []
# WASM plugin runtime (Extism). Opt-in: bundles wasmtime, a large engine most
# deployments won't use. Activation also requires OXICLOUD_ENABLE_PLUGINS=true.
plugins = ["dep:extism", "dep:toml", "dep:file-rotate"]
# Empty marker feature that gates the `load-seed` binary so it isn't built
# by default (and skipped in prod Docker builds). Kept separate from
# test_utils so enabling it doesn't change the oxicloud dependency graph —
# this lets one `cargo build` produce both `oxicloud` and `load-seed`
# without recompiling oxicloud with mockall in scope.
load_seed_bin = []
# Real ONNX-backed face analyzer (detector + embedder) for the People feature.
# Opt-in: pulls `ort` (ONNX Runtime, load-dynamic — dlopen's libonnxruntime at
# runtime) + `ndarray`, a heavy stack most deployments won't use. Activation also
# requires OXICLOUD_ENABLE_FACES=true *and* operator-provided ONNX models; without
# this feature the People pipeline falls back to the inert NoopFaceAnalyzer.
faces-onnx = ["dep:ort", "dep:ndarray"]
# Performance benchmark harness (Phase 0). Exposes `bench_support` + thin public
# wrappers over the private thumbnail render functions so `benches/` and
# `examples/` can measure them. Off by default — adds nothing to prod builds.
# Run with: `cargo bench --features bench` / `cargo run --release --features bench --example bench_thumbnails_mem`.
bench = []
[dev-dependencies]
criterion = "0.5"
# Round-11 L1 harness only (bench_log_writer): the non-blocking writer was
# REJECTED for production — slower than sync on fast sinks and can lose
# buffered tail lines at shutdown on slow ones (benches/ROUND11.md).
tracing-appender = "0.2"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(integration_tests)'] }
[[bin]]
name = "generate-openapi"
path = "src/bin/generate-openapi.rs"
[[bin]]
name = "migrate-nfc-filenames"
path = "src/bin/migrate-nfc-filenames.rs"
[[bin]]
name = "load-seed"
path = "src/bin/load-seed.rs"
# Test fixture seeder. Gated behind the empty `load_seed_bin` feature so
# `cargo build --release` (and the prod Dockerfile) skip it. tests/load/run.sh
# and load-nightly.yml build it explicitly with --features load_seed_bin.
required-features = ["load_seed_bin"]
# Phase 0 perf harness — Task 0.2 (criterion latency + output-size bench).
[[bench]]
name = "thumbnails"
path = "benches/thumbnails.rs"
harness = false
required-features = ["bench"]
# Phase 0 perf harness — Task 0.3 (peak-RAM + saturated-throughput baseline).
[[example]]
name = "bench_thumbnails_mem"
path = "examples/bench_thumbnails_mem.rs"
required-features = ["bench"]
# ZIP entry-compression benchmark — Deflate-always vs MIME-aware Stored for
# already-compressed media on the folder/batch ZIP download path. No Postgres.
[[example]]
name = "bench_zip_media"
path = "examples/bench_zip_media.rs"
required-features = ["bench"]
# WebDAV dead-properties fetch benchmark — PROPFIND's per-child N+1 (with a
# non-indexable IS NOT DISTINCT FROM predicate) vs batched = ANY($1) per page
# (needs the dev Postgres up).
[[example]]
name = "bench_dead_props"
path = "examples/bench_dead_props.rs"
required-features = ["bench"]
# NC chroot / default-drive resolution benchmark — the middleware's 2 uncached
# queries per request vs the moka caches (needs the dev Postgres up).
[[example]]
name = "bench_chroot_cache"
path = "examples/bench_chroot_cache.rs"
required-features = ["bench"]
# Quota-path benchmark — full auth.users row (incl. 512 KiB avatar) vs the
# narrow 2-column read, on every upload check / quota PROPFIND (needs Postgres).
[[example]]
name = "bench_quota_path"
path = "examples/bench_quota_path.rs"
required-features = ["bench"]
# People-tab benchmark — full faces scan (2 KiB embedding per row) vs grouped
# COUNT + batched cover lookup (needs Postgres).
[[example]]
name = "bench_people_list"
path = "examples/bench_people_list.rs"
required-features = ["bench"]
# PROPFIND folder-paging benchmark — LIMIT/OFFSET full-folder rescan per page
# vs keyset + (folder_id, name) index (needs Postgres).
[[example]]
name = "bench_propfind_paging"
path = "examples/bench_propfind_paging.rs"
required-features = ["bench"]
# Static-asset compression benchmark — per-request Brotli vs precompressed
# sibling read. No Postgres.
[[example]]
name = "bench_static_precompress"
path = "examples/bench_static_precompress.rs"
required-features = ["bench"]
# Round-2 battery: range-from-cache, NC chunk gate, delta prefetch, ingest
# overlap (real store_from_stream; run with OXICLOUD_INGEST_OVERLAP=0/1),
# ZIP streaming TTFB. Sections 1 and 4 need Postgres.
[[example]]
name = "bench_round2"
path = "examples/bench_round2.rs"
required-features = ["bench"]
# Video thumbnail benchmark — Option B (server-side ffmpeg frame → WebP). Needs
# `ffmpeg` on PATH (libx264/libx265/libvpx-vp9 to synthesize the test corpus).
[[example]]
name = "bench_video_thumbnails"
path = "examples/bench_video_thumbnails.rs"
required-features = ["bench"]
# DB connection-pool tail-latency benchmark (needs the dev Postgres up).
[[example]]
name = "bench_db_pool"
path = "examples/bench_db_pool.rs"
required-features = ["bench"]
# Blob-manifest read round-trip benchmark: OLD 2 queries vs NEW 1 (needs dev Postgres).
[[example]]
name = "bench_blob_manifest"
path = "examples/bench_blob_manifest.rs"
required-features = ["bench"]
# Blob download read-ahead benchmark — sweeps the local backend's chunk prefetch
# depth (read_prefetch / buffered(N)) under disk-bound vs network-bound consumers
# and warm vs cold page cache. No Postgres needed.
[[example]]
name = "bench_blob_prefetch"
path = "examples/bench_blob_prefetch.rs"
required-features = ["bench"]
# Tokio runtime tuning benchmark — worker over-subscription (throughput + p99
# under CPU contention) and blocking-pool RSS blast radius, default vs tuned.
# No Postgres needed; run under `taskset -c 0,1` to model a 2-core quota.
[[example]]
name = "bench_tokio_runtime"
path = "examples/bench_tokio_runtime.rs"
required-features = ["bench"]
# CPU pool concurrency benchmark — thumbnail decode throughput + p99 as the
# decode-permit count is swept, showing the effect of sizing the image pools to
# the CFS quota (effective_parallelism) vs the host core count. No Postgres;
# run under `taskset -c 0,1` to model a 2-core quota.
[[example]]
name = "bench_pool_concurrency"
path = "examples/bench_pool_concurrency.rs"
required-features = ["bench"]
# ACL owner-cache benchmark — owner query vs moka hit (needs the dev Postgres up).
[[example]]
name = "bench_owner_cache"
path = "examples/bench_owner_cache.rs"
required-features = ["bench"]
# Round-4 battery ─────────────────────────────────────────────────────────────
# PG row → entity path materialization — the per-listing-row make_file_path
# split→rejoin + NFC copy chain vs the one-pass builders. No Postgres.
[[example]]
name = "bench_row_path"
path = "examples/bench_row_path.rs"
required-features = ["bench"]
# WebDAV drive-selector resolution — the per-request list_readable_by grants
# join vs the per-user readable_cache (needs the dev Postgres up).
[[example]]
name = "bench_drive_selector"
path = "examples/bench_drive_selector.rs"
required-features = ["bench"]
# CalDAV parse path — from_ical's 8×-reparse vs single parse, per-event
# uppercase copies on REPORT/GET, UID clone churn. No Postgres.
[[example]]
name = "bench_caldav_parse"
path = "examples/bench_caldav_parse.rs"
required-features = ["bench"]
# PROPFIND per-row XML emit — partition Vec churn + chrono format-interpreter
# dates vs single-pass + stack-rendered fields. No Postgres.
[[example]]
name = "bench_propfind_xml"
path = "examples/bench_propfind_xml.rs"
required-features = ["bench"]
# Grant-listing hydration N+1 (calendars / address books / playlists) +
# user-flags cold-cache herd (needs the dev Postgres up).
[[example]]
name = "bench_n1_hydration"
path = "examples/bench_n1_hydration.rs"
required-features = ["bench"]
# Face-indexing fan-out — unbounded per-image spawn vs core-count semaphore;
# peak-live-heap + wall on the bench_support photo corpus. No Postgres.
[[example]]
name = "bench_faces_bound"
path = "examples/bench_faces_bound.rs"
required-features = ["bench"]
# Azure download path — whole-blob collect vs streamed pages, TTFB + peak
# live heap against a local Azure-GET stub (endpoint_url hook). No Postgres.
[[example]]
name = "bench_azure_stream"
path = "examples/bench_azure_stream.rs"
required-features = ["bench"]
# Round-5 battery ─────────────────────────────────────────────────────────────
# CalDAV whole-calendar REPORT/GET — buffered double-residency vs uid-keyset
# streaming; TTFB + peak live heap (needs the dev Postgres up).
[[example]]
name = "bench_caldav_stream"
path = "examples/bench_caldav_stream.rs"
required-features = ["bench"]
# Round-5 micro-allocation pack — suggest clones, readable-cache Arc hit,
# SPA-listing interning, NC href prefix, CardDAV REPORT churn. No Postgres.
[[example]]
name = "bench_micro_allocs"
path = "examples/bench_micro_allocs.rs"
required-features = ["bench"]
# Round-22 battery ────────────────────────────────────────────────────────────
# Round-22 CPU/alloc micro-pack — the deferred hot-GET-handler `HeaderMap`
# extractor clone (thumbnail/list/download/photos/preview/share read 1–3 headers
# out of a full `parts.headers.clone()`), routed through `Request` + borrow (H1);
# native-WebDAV `write_etag_quoted` borrowed pre-escaped quotes, the sweep's last
# per-row DAV site (W1); CalDAV `getetag` shared `write_quoted_etag` helper across
# 5 sites + dead etag-buffer removal (C1); `FileDto::from` reuse of the moved
# `blob_hash` instead of the getter clone the move-not-clone sweep missed (D1);
# `CalendarEvent` timed DTSTART/DTEND via `fmt::compact_ical_utc` (E1);
# `ShareItemType::try_from` `eq_ignore_ascii_case` (S1). No Postgres.
[[example]]
name = "bench_round22_micro"
path = "examples/bench_round22_micro.rs"
required-features = ["bench"]
# Round-21 battery ────────────────────────────────────────────────────────────
# Round-21 CPU/alloc micro-pack — CalDAV/CardDAV row-mapper container pre-size
# (the ROUND20 §I1 sibling the calendar/contact repos deferred); dedup
# `settle_batch` hash bind Vec<String>→Vec<&str> borrow; `store_loose_chunks`
# intra-request dedup set keyed on the raw [u8;32] digest + move-on-dup (the
# ROUND17 §D2 pattern applied to the delta-upload sibling); CardDAV `getetag`
# borrowed pre-escaped quotes (the ROUND20 §C1 NextCloud pattern); `BDAY`
# stamp via fmt::compact_date stack render; NC trashbin folder content-type
# Cow::Borrowed. No Postgres.
[[example]]
name = "bench_round21_micro"
path = "examples/bench_round21_micro.rs"
required-features = ["bench"]
# Round-20 battery ────────────────────────────────────────────────────────────
# Round-20 CPU/alloc micro-pack — CalendarEvent `prop_with_params` throwaway
# HashMap → direct VALUE=DATE scan; `UserDto::from` clone-every-field → move
# (image ≤512 KiB + ui_preferences JSON); `parse_vcard` per-line to_ascii_uppercase
# + lines Vec → direct iterate + `common::text::ascii_ci_contains`; Calendar/
# AddressBook DTO clone → move; listing `collect::<Result<Vec>>()` (size_hint 0)
# → `Vec::with_capacity` + push; `plaintext_stream` eager Vec collect → lazy iter;
# NC `write_etag_element` 3→0 allocs/row (borrowed pre-escaped quote events);
# NC `oc:id` per-row String → reused buffer; favorites REPORT DTO clone → map move.
# No Postgres.
[[example]]
name = "bench_round20_micro"
path = "examples/bench_round20_micro.rs"
required-features = ["bench"]
# Round-19 battery ────────────────────────────────────────────────────────────
# Round-19 CPU/alloc micro-pack — Basic-auth cache-key incremental blake3 (drop
# the per-request `format!("{u}:{p}")` String), WOPI validate/generate prebuilt
# Validation/DecodingKey/EncodingKey (mirrors JwtTokenService), CardDAV vCard
# per-contact emit (FN fallback `to_string` drop, NOTE no-newline borrow, REV via
# new `common::fmt::compact_ical_utc` stack renderer), trash row→DTO move-not-clone,
# search cache-key Uuid stack hyphenated-encode, streaming PROPFIND per-child href
# reused buffer, NC `extract_url_user` Cow (drop `into_owned`). No Postgres.
[[example]]
name = "bench_round19_micro"
path = "examples/bench_round19_micro.rs"
required-features = ["bench"]
# Round-18 battery ────────────────────────────────────────────────────────────
# Round-18 calendar-event edit CPU/alloc micro-pack — `update_ical_property` /
# `remove_ical_property` mutate the `ical_data` body in place (`replace_range` /
# `insert`) instead of re-`format!`ing the whole body per changed property, and
# build the single `\nNAME:` search needle on the stack (dropping the redundant
# `\r\nNAME:` needle). A multi-field REST edit went from one full-body (up to
# ~11 KB) allocation per property to none. No Postgres.
[[example]]
name = "bench_round18_micro"
path = "examples/bench_round18_micro.rs"
required-features = ["bench"]
# Round-17 battery ────────────────────────────────────────────────────────────
# Round-17 dedup + CardDAV CPU/alloc micro-pack — `hash_chunk_sequence` by-value
# (drop the delta-commit verification's 2nd per-chunk hash clone), chunk-ingest
# `session_seen` keyed on the raw 32-byte BLAKE3 digest + branch-split manifest
# push (3 → 2/1 hash-String allocs per ingested chunk), `contact_to_vcard` TYPE
# tokens pushed upper-cased into the buffer (drop the per-token `to_uppercase`
# String). No Postgres.
[[example]]
name = "bench_round17_micro"
path = "examples/bench_round17_micro.rs"
required-features = ["bench"]
# Round-16 battery ────────────────────────────────────────────────────────────
# Round-16 CPU/alloc micro-pack — folder display constants `Arc::from` → interned
# clone (3 sites), `build_content_disposition` 3→1 alloc (every download + Range
# seek), `nc_href` Vec+join → single pre-sized buffer (every NC PROPFIND/REPORT
# href), NC preview `fileId` collect-then-parse → borrowed-slice parse. No Postgres.
[[example]]
name = "bench_round16_micro"
path = "examples/bench_round16_micro.rs"
required-features = ["bench"]
# Round-15 battery ────────────────────────────────────────────────────────────
# Round-15 CPU/alloc micro-pack — exif Make/Model in-place trim (drop the
# throwaway display String), content-index worker single supports() classify
# per file (was called twice per drain batch). No Postgres.
[[example]]
name = "bench_round15_micro"
path = "examples/bench_round15_micro.rs"
required-features = ["bench"]
# Round-15 tantivy zero-hit snippet skip — the SnippetGenerator::create the
# search path builds even when the query matched no documents (pure waste on a
# no-hit content search). Builds a RAM index; no Postgres.
[[example]]
name = "bench_round15_tantivy"
path = "examples/bench_round15_tantivy.rs"
required-features = ["bench"]
# Round-14 battery ────────────────────────────────────────────────────────────
# Round-14 query-shape pack — lightbox face-box narrow projection (drop the
# 2 KiB embedding BYTEA + 6 unused columns; push the caller filter into SQL),
# music public-playlist N+1 fold, contact-listing vcard over-fetch (needs Postgres).
[[example]]
name = "bench_round14_queries"
path = "examples/bench_round14_queries.rs"
required-features = ["bench"]
# Round-14 CPU/alloc micro-pack — cookie borrow-only extract, auth HeaderMap
# clone removal, sub→Uuid pre-parse, CalDAV per-event emit (rfc2822 stack
# render + reused href/etag buffers), search ASCII case-fold. No Postgres.
[[example]]
name = "bench_round14_micro"
path = "examples/bench_round14_micro.rs"
required-features = ["bench"]
# Round-13 battery ────────────────────────────────────────────────────────────
# Round-13 HTTP micro-pack — duplicate /api TraceLayer removal, borrow-only
# client_ip span render, precomputed locale supported-codes. No Postgres.
[[example]]
name = "bench_round13_micro"
path = "examples/bench_round13_micro.rs"
required-features = ["bench"]
# Round-13 query-shape pack — notification recipient narrowing, login-hook
# EXISTS probes, recent prune-on-insert (needs the dev Postgres up).
[[example]]
name = "bench_round13_queries"
path = "examples/bench_round13_queries.rs"
required-features = ["bench"]
# Round-12 battery ────────────────────────────────────────────────────────────
# Round-12 query-shape pack — sharee narrow read + trgm, login/email stamp
# narrowing, session-rotation fused txn, WOPI triple join!, fused quota pair
# (needs the dev Postgres up).
[[example]]
name = "bench_round12_queries"
path = "examples/bench_round12_queries.rs"
required-features = ["bench"]
# Round-12 CPU/alloc micro-pack — sized listing JSON, single-pass compression
# predicate, fused security-header middleware, media single-read extraction,
# chunked-session fused lookups. No Postgres.
[[example]]
name = "bench_round12_micro"
path = "examples/bench_round12_micro.rs"
required-features = ["bench"]
# Blob-cache index — Mutex<LruCache> vs moka byte-weigher (index scaling,
# warm-hit reads, eviction-unlink + single-flight safety gates). No Postgres.
[[example]]
name = "bench_blob_cache_index"
path = "examples/bench_blob_cache_index.rs"
required-features = ["bench"]
# Round-11 battery ────────────────────────────────────────────────────────────
# Round-11 CPU/alloc micro-pack — download DTO hand-off, Last-Modified stack
# render, status.php/openapi.json memoization, upload-session PROPFIND emit,
# rate-limiter single-op, CSRF/ETag/recent-id micro-allocs, 4xx body, vCard
# emit, search page move, cosine norms, encrypted write in-place, StoragePath
# joined-only materialization. No Postgres.
[[example]]
name = "bench_round11_micro"
path = "examples/bench_round11_micro.rs"
required-features = ["bench"]
# Round-11 query-shape pack — deferred-upload 3→1 CTE, Calendar/AddressBook/
# Playlist direct-grant cache, expand_user join!, geo min-cast, recluster
# UNNEST batch (needs the dev Postgres up).
[[example]]
name = "bench_round11_queries"
path = "examples/bench_round11_queries.rs"
required-features = ["bench"]
# Round-11 log-writer benchmark — sync stdout fmt layer vs tracing-appender
# non_blocking(lossy=false) under 4-worker emit contention, fast + slow
# writer profiles. Run once per arm via BENCH_LOG_ARM. No Postgres.
[[example]]
name = "bench_log_writer"
path = "examples/bench_log_writer.rs"
required-features = ["bench"]
# Round-10 battery ────────────────────────────────────────────────────────────
# Round-10 CPU/alloc micro-pack — auth identity build, basic-auth hit,
# PROPFIND/trashbin int+date emits, webdav scope probe, base_url snapshot,
# JWT verify-miss keys, cipher Arc, request-id. No Postgres.
[[example]]
name = "bench_round10_micro"
path = "examples/bench_round10_micro.rs"
required-features = ["bench"]
# Round-10 query-shape pack — share download double-fetch, calendar-id narrow
# read, contact-group COUNT, trash partial indexes, favorites/recents binary
# UUID decode, save_faces UNNEST, playlist reorder UNNEST, search 3-query
# join!, move drive-lookup join! (needs the dev Postgres up).
[[example]]
name = "bench_round10_queries"
path = "examples/bench_round10_queries.rs"
required-features = ["bench"]
# Round-9 battery ─────────────────────────────────────────────────────────────
# Search enrichment — borrow+clone+reclassify vs consume+carry (file/folder
# enrich + the NC REPORT search→FileDto conversion). No Postgres.
[[example]]
name = "bench_search_enrich"
path = "examples/bench_search_enrich.rs"
required-features = ["bench"]
# Storage micro-pack — local chunk write create_new, manifest Vec-clone vs
# Arc-index, manifest miss single-flight, Content-MD5 hex. No Postgres.
[[example]]
name = "bench_storage_micro"
path = "examples/bench_storage_micro.rs"
required-features = ["bench"]
# NC per-request session — extractor deep-clone vs Arc handle, chroot-cache
# value vs Arc, session build double-clone vs shared Arc. No Postgres.
[[example]]
name = "bench_nc_session"
path = "examples/bench_nc_session.rs"
required-features = ["bench"]
# OCS capabilities poll — rebuild+serialize per request vs OnceLock<Bytes>
# memoization. No Postgres.
[[example]]
name = "bench_capabilities_static"
path = "examples/bench_capabilities_static.rs"
required-features = ["bench"]
# Drive::is_empty — full-drive COUNT(*) sum vs short-circuit EXISTS
# (needs the dev Postgres up).
[[example]]
name = "bench_drive_is_empty"
path = "examples/bench_drive_is_empty.rs"
required-features = ["bench"]
# Folder-listing rows — `id::text`/`parent_id::text` casts vs binary UUID
# decode + app-side render, the round-6 file-side port (needs Postgres).
[[example]]
name = "bench_folder_uuid_decode"
path = "examples/bench_folder_uuid_decode.rs"
required-features = ["bench"]
# NC PROPFIND per-page enrichment triple — serial 3×RTT vs tokio::join!,
# with injected-latency arms at 0/0.25/1/5 ms (needs Postgres).
[[example]]
name = "bench_nc_enrich_join"
path = "examples/bench_nc_enrich_join.rs"
required-features = ["bench"]
# Round-8 battery ─────────────────────────────────────────────────────────────
# Shared-album thumbnail authz — folder-grant cascade query per thumbnail vs
# the cascade_grant_cache; includes a revocation safety gate (needs the dev
# Postgres up).
[[example]]
name = "bench_thumbnail_cascade_cache"
path = "examples/bench_thumbnail_cascade_cache.rs"
required-features = ["bench"]
# Round-7 battery ─────────────────────────────────────────────────────────────
# Range-seek per-request authz duplication — the per-seek require the range
# branch used to run (warm CPU + cold drive-resolve query) vs 0 after routing
# through the non-perms range read (needs the dev Postgres up).
[[example]]
name = "bench_range_seek_authz"
path = "examples/bench_range_seek_authz.rs"
required-features = ["bench"]
# `/api/folders/{id}/resources` row→DTO mapping — per-row name clone vs move
# (pure CPU; counting allocator).
[[example]]
name = "bench_resource_row_map"
path = "examples/bench_resource_row_map.rs"
required-features = ["bench"]
# Round-6 battery ─────────────────────────────────────────────────────────────
# CardDAV whole-book REPORT/PROPFIND — buffered double-residency vs cursor
# streaming; TTFB + peak live heap (needs the dev Postgres up).
[[example]]
name = "bench_carddav_stream"
path = "examples/bench_carddav_stream.rs"
required-features = ["bench"]
# Batch-favorites authz pre-check — serial require loop vs try_join_all
# against the real PgAclEngine (needs the dev Postgres up).
[[example]]
name = "bench_favorites_authz"
path = "examples/bench_favorites_authz.rs"
required-features = ["bench"]
# Digest-hex rendering + NC id-batch marshalling micro-allocs (pure CPU).
[[example]]
name = "bench_hex_ids"
path = "examples/bench_hex_ids.rs"
required-features = ["bench"]
# `id::text` server cast vs binary UUID decode + app-side formatting A/B
# (needs the dev Postgres up).
[[example]]
name = "bench_uuid_text_cast"
path = "examples/bench_uuid_text_cast.rs"
required-features = ["bench"]
# Round-3 battery ─────────────────────────────────────────────────────────────
# Web-UI folder listing — whole-folder rescan + top-N sort per page vs keyset
# pushdown into the UNION-ALL branches + (folder_id, LOWER(name), id) indexes
# (needs the dev Postgres up).
[[example]]
name = "bench_listing_keyset"
path = "examples/bench_listing_keyset.rs"
required-features = ["bench"]
# Photos timeline — full-library scan + top-N above the grants join vs
# per-drive LATERAL top-N on the media-timeline index (needs Postgres).
[[example]]
name = "bench_photos_timeline"
path = "examples/bench_photos_timeline.rs"
required-features = ["bench"]
# PROPFIND subfolder paging — LIMIT/OFFSET + COUNT(*) OVER() per page vs
# keyset batch, mirroring the files-side PROPFIND-PAGING fix (needs Postgres).
[[example]]
name = "bench_folder_keyset"
path = "examples/bench_folder_keyset.rs"
required-features = ["bench"]
# Basic-auth thundering herd — K concurrent cache misses each paying Argon2id
# vs single-flight try_get_with (needs Postgres).
[[example]]
name = "bench_auth_herd"
path = "examples/bench_auth_herd.rs"
required-features = ["bench"]
# CachedBlobBackend — miss stampede (N duplicate remote fetches racing on one
# .tmp) vs per-hash single-flight; warm-hit index throughput. No Postgres.
[[example]]
name = "bench_blob_cache"
path = "examples/bench_blob_cache.rs"
required-features = ["bench"]
# Upload spool/assembly I/O — ReaderStream capacity sweep on part-file reads
# and BufWriter vs bare-File frame writes on the chunk spool path. No Postgres.
[[example]]
name = "bench_upload_spool"
path = "examples/bench_upload_spool.rs"
required-features = ["bench"]
# S3 chunk PUT — HEAD-before-PUT vs unconditional PUT against a local axum
# stub with injected latency; Azure Bytes-vs-to_vec copy micro. No Postgres.
[[example]]
name = "bench_s3_put"
path = "examples/bench_s3_put.rs"
required-features = ["bench"]
# File/Folder -> DTO mapping allocations — Arc<str> interning of closed-set
# display fields, 1-alloc etag/size formatting. No Postgres.
[[example]]
name = "bench_dto_map"
path = "examples/bench_dto_map.rs"
required-features = ["bench"]
# CardDAV REPORT — dead per-contact vCard pre-generation + O(N^2) uid scan vs
# single on-demand generation. No Postgres.
[[example]]
name = "bench_carddav_report"
path = "examples/bench_carddav_report.rs"
required-features = ["bench"]
# Search-results cache RSS — entry-count capacity vs byte weigher. No Postgres.
[[example]]
name = "bench_search_cache_mem"
path = "examples/bench_search_cache_mem.rs"
required-features = ["bench"]
[profile.release]
lto = "thin"
codegen-units = 1
opt-level = 3
strip = true
[profile.dev]
opt-level = 1
debug = true
[profile.bench]
lto = "fat"
codegen-units = 1
opt-level = 3