perf: round 4 — one-pass row paths, drive-selector cache, CalDAV single-parse, streamed Azure, batched hydration

Nine benchmark-gated changes (benches/ROUND4.md; every one ships with a
BEFORE/AFTER bench + equivalence gate, rollback rule as ROUND2/3):

- Row→entity path build: one-pass StoragePath::from_folder_and_name /
  from_joined + normalize_storage_name_owned + alloc-free Display —
  743→417 ns/file-row (1.78x), −5 allocs/row on every listing surface.
- WebDAV drive-selector: per-user readable_cache (single-flight, 30 s
  TTL, explicit invalidation incl. membership + group changes) replaces
  the grants join per request — 441 µs → 0.8 µs (~550x), 0 queries warm.
- CalDAV from_ical/update_ical_data: 8 full IcalParser runs per VEVENT
  → 1 (7.1x per PUT, 4.4x on 50-event imports); alloc-free split_vevents,
  chunk scan without the whole-body uppercase copy (1.4x), borrowed-key
  UID grouping (1.3x), REPORT props no longer cloned.
- PROPFIND emit: partition Vecs dropped (single-pass 404 list) + stack
  rendered RFC 3339/2822 dates, sizes, quoted etags (common::fmt,
  chrono-byte-identical, sweep-tested) on both DAV surfaces — 1.22x
  per page, 17.9→12.0 allocs/row.
- Grant-listing hydration: calendars/address books/playlists batch
  hydrate via = ANY($1) — 15 serial queries → 1 (~13x per sync poll).
- user-flags cache: get→insert → try_get_with single-flight (32→1
  queries per cold herd).
- Azure downloads: whole-blob Vec buffering → streamed SDK pages —
  TTFB 349→4 ms (87x), peak heap 480→1.9 MiB (254x) on 256 MiB blobs;
  new OXICLOUD_AZURE_ENDPOINT_URL override (Azurite/bench hook).
- Face indexing: unbounded per-image tokio::spawn → core-count
  semaphore, permit before blob read — peak heap 1175→176 MiB (6.7x).

Checks: cargo fmt, clippy --all-features --all-targets -D warnings,
cargo test --workspace (523 passed) + --features test_utils. hurl API
suite and dockerized integration DB not runnable in this environment —
left to CI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017aJu9ghvuT8WqC31ZEGTBA
This commit is contained in:
Claude
2026-07-17 13:48:37 +00:00
parent 8a73607229
commit 12dc648cff
44 changed files with 5092 additions and 402 deletions
+53 -9
View File
@@ -1,7 +1,7 @@
use uuid::Uuid;
use crate::domain::services::path_service::{
StoragePath, normalize_storage_name, validate_storage_name,
StoragePath, normalize_storage_name_owned, validate_storage_name,
};
// Re-export entity errors from the centralized module
@@ -120,7 +120,7 @@ impl Folder {
storage_path: StoragePath,
parent_id: Option<String>,
) -> FolderResult<Self> {
let name = normalize_storage_name(&name);
let name = normalize_storage_name_owned(name);
if let Err(reason) = validate_storage_name(&name) {
return Err(FolderError::InvalidFolderName(format!("{name}: {reason}")));
}
@@ -130,7 +130,7 @@ impl Folder {
.unwrap_or_default()
.as_secs();
let path_string = storage_path.to_string();
let path_string = storage_path.to_path_string();
Ok(Self {
id,
@@ -221,12 +221,56 @@ impl Folder {
created_by: Option<Uuid>,
updated_by: Option<Uuid>,
) -> FolderResult<Self> {
let name = normalize_storage_name(&name);
let name = normalize_storage_name_owned(name);
if let Err(reason) = validate_storage_name(&name) {
return Err(FolderError::InvalidFolderName(format!("{name}: {reason}")));
}
let path_string = storage_path.to_string();
let path_string = storage_path.to_path_string();
Ok(Self {
id,
name,
storage_path,
path_string,
parent_id,
drive_id,
created_at,
modified_at,
tree_modified_at,
created_by,
updated_by,
})
}
/// PG-row constructor: the per-listing-row hot path.
///
/// Takes the materialized `storage.folders.path` column by value and
/// splits it once via [`StoragePath::from_joined`] — when the stored
/// path is already canonical (every row the repository writes), the
/// input `String` is reused as `path_string` with zero copies,
/// replacing the old `from_string` split + `Display` re-join pair.
/// The owned `name` is NFC-normalized without the always-copy of the
/// borrowing variant (DB rows are NFC by invariant).
#[allow(clippy::too_many_arguments)]
pub fn from_materialized_row(
id: String,
name: String,
path: String,
parent_id: Option<String>,
drive_id: Uuid,
created_at: u64,
modified_at: u64,
tree_modified_at: u64,
created_by: Option<Uuid>,
updated_by: Option<Uuid>,
) -> FolderResult<Self> {
let name = normalize_storage_name_owned(name);
if let Err(reason) = validate_storage_name(&name) {
return Err(FolderError::InvalidFolderName(format!("{name}: {reason}")));
}
let (storage_path, path_string) = StoragePath::from_joined(path);
Ok(Self {
id,
@@ -411,7 +455,7 @@ impl Folder {
// round-trips lose the real rollup signal, so callers that
// need a freshly-rolled-up etag must reload from the
// repository.
let name = normalize_storage_name(&name);
let name = normalize_storage_name_owned(name);
Self {
id,
name,
@@ -437,7 +481,7 @@ impl Folder {
/// Creates a new version of the folder with updated name
pub fn with_name(&self, new_name: String) -> FolderResult<Self> {
let new_name = normalize_storage_name(&new_name);
let new_name = normalize_storage_name_owned(new_name);
if let Err(reason) = validate_storage_name(&new_name) {
return Err(FolderError::InvalidFolderName(format!(
"{new_name}: {reason}"
@@ -452,7 +496,7 @@ impl Folder {
};
// Update string representation
let new_path_string = new_storage_path.to_string();
let new_path_string = new_storage_path.to_path_string();
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
@@ -492,7 +536,7 @@ impl Folder {
};
// Update string representation
let new_path_string = new_storage_path.to_string();
let new_path_string = new_storage_path.to_path_string();
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)