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
This commit is contained in:
@@ -575,21 +575,38 @@ impl CalendarEvent {
|
||||
self.end_time = end_time;
|
||||
self.updated_at = Utc::now();
|
||||
|
||||
// Update iCalendar data
|
||||
let start_str = if self.all_day {
|
||||
format!("{}T000000Z", start_time.format("%Y%m%d"))
|
||||
// Update iCalendar data. Timed events stack-render the compact UTC
|
||||
// stamp via `fmt::compact_ical_utc` (the ROUND19 §V2 pattern: drops
|
||||
// chrono's `%Y%m%dT%H%M%SZ` strftime interpreter — ~3 → 0 allocs each),
|
||||
// with chrono kept as the out-of-range fallback. All-day keeps its
|
||||
// `%Y%m%d` + literal-suffix form. Byte-identical output either way.
|
||||
let (mut sbuf, mut ebuf) = ([0u8; 16], [0u8; 16]);
|
||||
let (start_owned, end_owned);
|
||||
let start_str: &str = if self.all_day {
|
||||
start_owned = format!("{}T000000Z", start_time.format("%Y%m%d"));
|
||||
&start_owned
|
||||
} else if let Some(s) =
|
||||
crate::common::fmt::compact_ical_utc(&mut sbuf, start_time.timestamp())
|
||||
{
|
||||
s
|
||||
} else {
|
||||
format!("{}", start_time.format("%Y%m%dT%H%M%SZ"))
|
||||
start_owned = format!("{}", start_time.format("%Y%m%dT%H%M%SZ"));
|
||||
&start_owned
|
||||
};
|
||||
let end_str: &str = if self.all_day {
|
||||
end_owned = format!("{}T000000Z", end_time.format("%Y%m%d"));
|
||||
&end_owned
|
||||
} else if let Some(e) =
|
||||
crate::common::fmt::compact_ical_utc(&mut ebuf, end_time.timestamp())
|
||||
{
|
||||
e
|
||||
} else {
|
||||
end_owned = format!("{}", end_time.format("%Y%m%dT%H%M%SZ"));
|
||||
&end_owned
|
||||
};
|
||||
|
||||
let end_str = if self.all_day {
|
||||
format!("{}T000000Z", end_time.format("%Y%m%d"))
|
||||
} else {
|
||||
format!("{}", end_time.format("%Y%m%dT%H%M%SZ"))
|
||||
};
|
||||
|
||||
self.update_ical_property("DTSTART", &start_str);
|
||||
self.update_ical_property("DTEND", &end_str);
|
||||
self.update_ical_property("DTSTART", start_str);
|
||||
self.update_ical_property("DTEND", end_str);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -603,21 +620,37 @@ impl CalendarEvent {
|
||||
self.all_day = all_day;
|
||||
self.updated_at = Utc::now();
|
||||
|
||||
// Update iCalendar data
|
||||
let start_str = if all_day {
|
||||
format!("VALUE=DATE:{}", self.start_time.format("%Y%m%d"))
|
||||
// Update iCalendar data. Timed events stack-render the compact UTC
|
||||
// stamp via `fmt::compact_ical_utc` (drops chrono's `%Y%m%dT%H%M%SZ`
|
||||
// strftime interpreter — ~3 → 0 allocs each), chrono fallback out of
|
||||
// range. All-day keeps its `VALUE=DATE:` + `%Y%m%d` form. Byte-identical.
|
||||
let (mut sbuf, mut ebuf) = ([0u8; 16], [0u8; 16]);
|
||||
let (start_owned, end_owned);
|
||||
let start_str: &str = if all_day {
|
||||
start_owned = format!("VALUE=DATE:{}", self.start_time.format("%Y%m%d"));
|
||||
&start_owned
|
||||
} else if let Some(s) =
|
||||
crate::common::fmt::compact_ical_utc(&mut sbuf, self.start_time.timestamp())
|
||||
{
|
||||
s
|
||||
} else {
|
||||
format!("{}", self.start_time.format("%Y%m%dT%H%M%SZ"))
|
||||
start_owned = format!("{}", self.start_time.format("%Y%m%dT%H%M%SZ"));
|
||||
&start_owned
|
||||
};
|
||||
let end_str: &str = if all_day {
|
||||
end_owned = format!("VALUE=DATE:{}", self.end_time.format("%Y%m%d"));
|
||||
&end_owned
|
||||
} else if let Some(e) =
|
||||
crate::common::fmt::compact_ical_utc(&mut ebuf, self.end_time.timestamp())
|
||||
{
|
||||
e
|
||||
} else {
|
||||
end_owned = format!("{}", self.end_time.format("%Y%m%dT%H%M%SZ"));
|
||||
&end_owned
|
||||
};
|
||||
|
||||
let end_str = if all_day {
|
||||
format!("VALUE=DATE:{}", self.end_time.format("%Y%m%d"))
|
||||
} else {
|
||||
format!("{}", self.end_time.format("%Y%m%dT%H%M%SZ"))
|
||||
};
|
||||
|
||||
self.update_ical_property("DTSTART", &start_str);
|
||||
self.update_ical_property("DTEND", &end_str);
|
||||
self.update_ical_property("DTSTART", start_str);
|
||||
self.update_ical_property("DTEND", end_str);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -180,13 +180,18 @@ impl TryFrom<&str> for ShareItemType {
|
||||
type Error = ShareError;
|
||||
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"file" => Ok(ShareItemType::File),
|
||||
"folder" => Ok(ShareItemType::Folder),
|
||||
_ => Err(ShareError::ValidationError(format!(
|
||||
// ASCII case-insensitive compare against the two literals instead of a
|
||||
// throwaway Unicode `to_lowercase()` String — byte-identical acceptance
|
||||
// for the ASCII targets "file"/"folder" (1 → 0 allocs/call).
|
||||
if s.eq_ignore_ascii_case("file") {
|
||||
Ok(ShareItemType::File)
|
||||
} else if s.eq_ignore_ascii_case("folder") {
|
||||
Ok(ShareItemType::Folder)
|
||||
} else {
|
||||
Err(ShareError::ValidationError(format!(
|
||||
"Invalid item type: {}",
|
||||
s
|
||||
))),
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user