Files
Oxicloud/Cargo.toml
T
2026-07-22 06:53:35 +02:00

886 lines
39 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.7"
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"
arc-swap = "1.9"
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"
# Fast, DoS-resistant (per-instance random-seeded) hasher for trusted- and
# attacker-controlled internal maps/sets. Already present transitively via
# hashbrown, so this direct dep adds no new compiled crate (benches/ROUND26.md §G1).
foldhash = "0.2"
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"
# Ephemeral service containers for integration tests (gated by
# `--cfg integration_tests`). `testcontainers-modules` re-exports the
# `testcontainers` runner, so the postgres image + runner come from one dep.
testcontainers-modules = { version = "0.13", features = ["postgres"] }
# 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-29 battery ────────────────────────────────────────────────────────────
# Round-29 CPU/alloc micro-pack (no Postgres) — NC REPORT per-row href String(s)
# → reused buffer via nc_href_into with a once-encoded user (A); cache-serve fast
# path eager get_or_load args (etag/key/id) built before the borrow-probe hit (B);
# read_full single-frame BytesMut concat → zero-copy passthrough (C).
[[example]]
name = "bench_round29_micro"
path = "examples/bench_round29_micro.rs"
required-features = ["bench"]
# Round-27 battery ────────────────────────────────────────────────────────────
# Round-27 CPU/alloc micro-pack (no Postgres) — NC PROPFIND per-row oc:id String
# → reused buffer via format_oc_id_into (H1); contact create/update JSONB write
# through a throwaway serde_json::Value DOM → sqlx::types::Json(&dtos) direct
# serialize (P2, the write-side twin of §J1).
[[example]]
name = "bench_round27_micro"
path = "examples/bench_round27_micro.rs"
required-features = ["bench"]
# Round-26 battery ────────────────────────────────────────────────────────────
# Round-26 CPU/alloc micro-pack (no Postgres) — drive-policy JSONB decode through
# a throwaway serde_json::Value DOM → from_slice::<DrivePolicies> (P1, the §J1
# pattern applied to the drive-policy path §J2 left behind).
[[example]]
name = "bench_round26_micro"
path = "examples/bench_round26_micro.rs"
required-features = ["bench"]
# Round-26 disk-I/O pack — CachedBlobBackend redundant per-write create_dir_all
# on warm shards → pre-create the 256 shard dirs at init (D1). (D2, moving the
# eviction unlink off the reactor via spawn_blocking, was tested and REVERTED —
# spawn_blocking dispatch costs more than the fast local unlink; see ROUND26.md.)
[[example]]
name = "bench_round26_diskio"
path = "examples/bench_round26_diskio.rs"
required-features = ["bench"]
# Round-26 hasher pack — delta-upload have/need hash sets: SipHash → foldhash
# (per-instance random-seeded, DoS-safe for the attacker-controlled hashes) (G1).
[[example]]
name = "bench_round26_hasher"
path = "examples/bench_round26_hasher.rs"
required-features = ["bench"]
# Round-25 battery ────────────────────────────────────────────────────────────
# Round-25 CPU/alloc/RAM micro-pack (no Postgres) — deterministic alloc+bytes
# gates: EncryptedBlobBackend::decrypt_bytes split_off full copy → in-place
# detached decrypt + zero-copy slice (M1, the RAM headline); delta-commit
# chunk-hash list third clone → move-unzip (M2); folder download dead
# Query<HashMap> extractor removal (M3).
[[example]]
name = "bench_round25_micro"
path = "examples/bench_round25_micro.rs"
required-features = ["bench"]
# Round-25 PG query-shape pack — public-playlist listing 1+N COUNT round-trips
# → one LEFT JOIN GROUP BY (Q1); contact REST listings dropping the over-fetched
# multi-KB vcard TEXT the ContactDto discards (Q2). Needs the dev Postgres up
# (reads DATABASE_URL from .env).
[[example]]
name = "bench_round25_queries"
path = "examples/bench_round25_queries.rs"
required-features = ["bench"]
# Round-24 battery ────────────────────────────────────────────────────────────
# Round-24 download_zip authz+metadata N+1 → batch, VALIDATED. The per-file
# get_file_with_perms (require + get, 2 round-trips/file) becomes one
# check_files_read_batch + one get_files_by_ids. Because the change is
# authorization-sensitive, the gate is the security property: the batch check
# must make the identical per-file inclusion decision (same set AND input order)
# as the shipped-before require loop, over owned + denied + missing ids, and
# never include a denied/missing file. Drives the real PgAclEngine. Needs the
# dev Postgres up (reads DATABASE_URL from .env).
[[example]]
name = "bench_round24_zip_authz"
path = "examples/bench_round24_zip_authz.rs"
required-features = ["bench"]
# Round-23 battery ────────────────────────────────────────────────────────────
# Round-23 CPU/alloc micro-pack (no Postgres) — deterministic alloc gates for
# the decode/clone candidates: contact JSONB `Value`+`from_value` → typed
# `sqlx::types::Json<T>` decode (J1); `DrivePolicies::from_value` DOM clone →
# borrow-deserialize (J2); dedup hash reshape clone-collect → `into_iter().unzip()`
# (U1). The PG latency/round-trip/equivalence evidence is bench_round23_queries.
[[example]]
name = "bench_round23_micro"
path = "examples/bench_round23_micro.rs"
required-features = ["bench"]
# Round-23 PG query-shape pack — end-to-end latency + equivalence on the live
# dev Postgres: contact JSONB typed decode on real rows (Q1); get_user_profile
# 2 serial reads → tokio::join! (Q4); subject_group remove_member 2 recursive
# CTEs → 1 reused (Q6). Needs the dev Postgres up (reads DATABASE_URL from .env).
[[example]]
name = "bench_round23_queries"
path = "examples/bench_round23_queries.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