perf: round 19 — auth/WOPI/vCard/PROPFIND per-request & per-row alloc cuts
Benchmark-gated (examples/bench_round19_micro.rs, benches/ROUND19.md): every
section ships a BEFORE/AFTER counting-allocator arm with a byte/-value
equivalence gate and a GATE-FAIL-rollback exit. All eight pass. No Postgres.
- M1 verify_basic_auth cache key: blake3::hash(format!("{u}:{p}")) → incremental
Hasher (byte-identical key, 2→0 allocs on every Basic-auth DAV request)
- M2 WopiTokenService: prebuild Validation/DecodingKey/EncodingKey in new()
instead of per-call (mirrors JwtTokenService; 16→12 allocs/validate)
- V1/V2 vCard emit (contact_to_vcard/generate_vcard): FN fallback drops the
throwaway to_string, NOTE skips the escape copy for newline-free notes, REV
uses new common::fmt::compact_ical_utc stack renderer (11.5× vs chrono
strftime, 3→0 allocs); per-contact 9→4 allocs
- M4 trash_service::row_to_item_dto: move name/path/blob_hash out of the owned
row instead of cloning (3 clones/file row gone)
- M5 search cache key: Uuid::hyphenated().encode_lower stack buffer instead of
to_string (identical u64 key, 1→0 allocs/request)
- M6 streaming PROPFIND: reuse one href buffer across the page instead of a
format! per child (native + NC handlers; 192→3 allocs on a 64-child page)
- M7 nextcloud extract_url_user: return Cow instead of forcing into_owned
(zero-alloc on the common ASCII-username path)
common::fmt::compact_ical_utc added with chrono-parity unit tests (CASES +
60-year sweep). cargo fmt + clippy --all-targets clean; 526 lib unit tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ront9bk7YMoffVQkGG47gh
This commit is contained in:
@@ -210,6 +210,37 @@ pub fn hex_lower(bytes: &[u8]) -> String {
|
||||
out
|
||||
}
|
||||
|
||||
/// `chrono::DateTime<Utc>::format("%Y%m%dT%H%M%SZ")` for a whole-second
|
||||
/// timestamp: the compact iCal/vCard UTC form `20260717T114714Z` (16 bytes)
|
||||
/// written into `buf`.
|
||||
///
|
||||
/// This is the `DTSTAMP` / `REV` / `CREATED` / `LAST-MODIFIED` stamp emitted
|
||||
/// per contact in every CardDAV vCard (`contact_to_vcard` / `generate_vcard`)
|
||||
/// and per event on the calendar create path. chrono's `.format("%Y%m%dT%H%M%SZ")`
|
||||
/// builds a `DelayedFormat` that re-parses the strftime spec (`StrftimeItems`)
|
||||
/// and formats six zero-padded fields through `core::fmt` on every call — the
|
||||
/// exact interpreter cost [`rfc3339_utc`] / [`rfc2822_utc`] were added to
|
||||
/// remove, but neither covers this compact no-separator form.
|
||||
///
|
||||
/// Returns `None` when `secs` is outside the fixed-width range —
|
||||
/// callers fall back to chrono.
|
||||
pub fn compact_ical_utc(buf: &mut [u8; 16], secs: i64) -> Option<&str> {
|
||||
if !(0..=MAX_4DIGIT_YEAR_SECS).contains(&secs) {
|
||||
return None;
|
||||
}
|
||||
let (_days, y, m, d, hh, mm, ss) = split(secs);
|
||||
push4(buf, 0, y);
|
||||
push2(buf, 4, m);
|
||||
push2(buf, 6, d);
|
||||
buf[8] = b'T';
|
||||
push2(buf, 9, hh);
|
||||
push2(buf, 11, mm);
|
||||
push2(buf, 13, ss);
|
||||
buf[15] = b'Z';
|
||||
// SAFETY-free: every byte written above is ASCII.
|
||||
Some(std::str::from_utf8(&buf[..]).expect("ascii"))
|
||||
}
|
||||
|
||||
/// Append the upper-cased form of `s` to `buf` without a temporary `String`.
|
||||
///
|
||||
/// Byte-identical to `buf.push_str(&s.to_uppercase())` — same
|
||||
@@ -305,13 +336,29 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compact_ical_matches_chrono() {
|
||||
for &secs in &CASES {
|
||||
let dt = Utc.timestamp_opt(secs, 0).unwrap();
|
||||
let mut buf = [0u8; 16];
|
||||
assert_eq!(
|
||||
compact_ical_utc(&mut buf, secs).expect("in range"),
|
||||
dt.format("%Y%m%dT%H%M%SZ").to_string(),
|
||||
"secs={secs}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn out_of_range_falls_back() {
|
||||
let mut b3 = [0u8; 25];
|
||||
let mut b2 = [0u8; 31];
|
||||
let mut bc = [0u8; 16];
|
||||
assert!(rfc3339_utc(&mut b3, -1).is_none());
|
||||
assert!(rfc2822_utc(&mut b2, -1).is_none());
|
||||
assert!(compact_ical_utc(&mut bc, -1).is_none());
|
||||
assert!(rfc3339_utc(&mut b3, MAX_4DIGIT_YEAR_SECS + 1).is_none());
|
||||
assert!(compact_ical_utc(&mut bc, MAX_4DIGIT_YEAR_SECS + 1).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -335,8 +382,13 @@ mod tests {
|
||||
let dt = Utc.timestamp_opt(secs, 0).unwrap();
|
||||
let mut b3 = [0u8; 25];
|
||||
let mut b2 = [0u8; 31];
|
||||
let mut bc = [0u8; 16];
|
||||
assert_eq!(rfc3339_utc(&mut b3, secs).unwrap(), dt.to_rfc3339());
|
||||
assert_eq!(rfc2822_utc(&mut b2, secs).unwrap(), dt.to_rfc2822());
|
||||
assert_eq!(
|
||||
compact_ical_utc(&mut bc, secs).unwrap(),
|
||||
dt.format("%Y%m%dT%H%M%SZ").to_string()
|
||||
);
|
||||
secs += 22_380; // 6h13m — walks through all times of day + weekdays
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user