perf: use Arc<str> for repetitive DTO fields to eliminate clone allocations
Replace String with Arc<str> for fields that contain repeated static values (mime_type, icon_class, icon_special_class, category) in FileDto, FolderDto, and OptimizedFileContent. These fields are computed from ~40 static lookup tables and cloned on every request. With Arc<str>, clone becomes O(1) atomic increment instead of O(n) heap allocation — saving thousands of allocations/s under load. Fields kept as String: id, name, path, folder_id, owner_id (unique per item, rarely cloned). Zero API impact — serde serializes Arc<str> identically to String. https://claude.ai/code/session_01EbAFEfyJNLRmJHmmYDX3Tt
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::domain::entities::file::File;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -20,8 +22,9 @@ pub struct FileDto {
|
||||
/// Size in bytes
|
||||
pub size: u64,
|
||||
|
||||
/// MIME type
|
||||
pub mime_type: String,
|
||||
/// MIME type — `Arc<str>` because MIME values repeat across files
|
||||
/// and DTOs are cloned on every request (clone is O(1) atomic increment).
|
||||
pub mime_type: Arc<str>,
|
||||
|
||||
/// Parent folder ID
|
||||
pub folder_id: Option<String>,
|
||||
@@ -32,15 +35,15 @@ pub struct FileDto {
|
||||
/// Last modification timestamp
|
||||
pub modified_at: u64,
|
||||
|
||||
// ── Pre-computed display fields ──
|
||||
// ── Pre-computed display fields (Arc<str>: values come from static tables) ──
|
||||
/// FontAwesome icon CSS class (e.g. "fas fa-file-image")
|
||||
pub icon_class: String,
|
||||
pub icon_class: Arc<str>,
|
||||
|
||||
/// Extra CSS class for icon styling (e.g. "image-icon", "" when default)
|
||||
pub icon_special_class: String,
|
||||
pub icon_special_class: Arc<str>,
|
||||
|
||||
/// Human-readable file category (e.g. "Image", "Document")
|
||||
pub category: String,
|
||||
pub category: Arc<str>,
|
||||
|
||||
/// Human-readable formatted size (e.g. "3.27 MB")
|
||||
pub size_formatted: String,
|
||||
@@ -61,13 +64,13 @@ impl From<File> for FileDto {
|
||||
name: name.to_string(),
|
||||
path: file.path_string().to_string(),
|
||||
size,
|
||||
mime_type: mime.to_string(),
|
||||
mime_type: Arc::from(mime),
|
||||
folder_id: file.folder_id().map(String::from),
|
||||
created_at: file.created_at(),
|
||||
modified_at: file.modified_at(),
|
||||
icon_class: icon_class_for(name, mime).to_string(),
|
||||
icon_special_class: icon_special_class_for(name, mime).to_string(),
|
||||
category: category_for(name, mime).to_string(),
|
||||
icon_class: Arc::from(icon_class_for(name, mime)),
|
||||
icon_special_class: Arc::from(icon_special_class_for(name, mime)),
|
||||
category: Arc::from(category_for(name, mime)),
|
||||
size_formatted: format_file_size(size),
|
||||
owner_id: file.owner_id().map(String::from),
|
||||
}
|
||||
@@ -84,7 +87,7 @@ impl From<FileDto> for File {
|
||||
dto.name,
|
||||
dto.path,
|
||||
dto.size,
|
||||
dto.mime_type,
|
||||
dto.mime_type.to_string(),
|
||||
dto.folder_id,
|
||||
dto.created_at,
|
||||
dto.modified_at,
|
||||
@@ -100,13 +103,13 @@ impl FileDto {
|
||||
name: "stub-file".to_string(),
|
||||
path: "/stub/path".to_string(),
|
||||
size: 0,
|
||||
mime_type: "application/octet-stream".to_string(),
|
||||
mime_type: Arc::from("application/octet-stream"),
|
||||
folder_id: None,
|
||||
created_at: 0,
|
||||
modified_at: 0,
|
||||
icon_class: "fas fa-file".to_string(),
|
||||
icon_special_class: String::new(),
|
||||
category: "Document".to_string(),
|
||||
icon_class: Arc::from("fas fa-file"),
|
||||
icon_special_class: Arc::from(""),
|
||||
category: Arc::from("Document"),
|
||||
size_formatted: "0 Bytes".to_string(),
|
||||
owner_id: None,
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::domain::entities::folder::Folder;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -53,15 +55,15 @@ pub struct FolderDto {
|
||||
/// Whether this is a root folder
|
||||
pub is_root: bool,
|
||||
|
||||
// ── Pre-computed display fields ──
|
||||
// ── Pre-computed display fields (Arc<str>: always identical values) ──
|
||||
/// FontAwesome icon CSS class (always "fas fa-folder")
|
||||
pub icon_class: String,
|
||||
pub icon_class: Arc<str>,
|
||||
|
||||
/// Extra CSS class for icon styling (always "folder-icon")
|
||||
pub icon_special_class: String,
|
||||
pub icon_special_class: Arc<str>,
|
||||
|
||||
/// Human-readable category (always "Folder")
|
||||
pub category: String,
|
||||
pub category: Arc<str>,
|
||||
}
|
||||
|
||||
impl From<Folder> for FolderDto {
|
||||
@@ -77,9 +79,9 @@ impl From<Folder> for FolderDto {
|
||||
created_at: folder.created_at(),
|
||||
modified_at: folder.modified_at(),
|
||||
is_root,
|
||||
icon_class: "fas fa-folder".to_string(),
|
||||
icon_special_class: "folder-icon".to_string(),
|
||||
category: "Folder".to_string(),
|
||||
icon_class: Arc::from("fas fa-folder"),
|
||||
icon_special_class: Arc::from("folder-icon"),
|
||||
category: Arc::from("Folder"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,9 +114,9 @@ impl FolderDto {
|
||||
created_at: 0,
|
||||
modified_at: 0,
|
||||
is_root: true,
|
||||
icon_class: "fas fa-folder".to_string(),
|
||||
icon_special_class: "folder-icon".to_string(),
|
||||
category: "Folder".to_string(),
|
||||
icon_class: Arc::from("fas fa-folder"),
|
||||
icon_special_class: Arc::from("folder-icon"),
|
||||
category: Arc::from("Folder"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ pub enum OptimizedFileContent {
|
||||
/// Small-file content (possibly transcoded / compressed) already in RAM.
|
||||
Bytes {
|
||||
data: Bytes,
|
||||
mime_type: String,
|
||||
mime_type: Arc<str>,
|
||||
was_transcoded: bool,
|
||||
},
|
||||
/// Memory-mapped file (10–100 MB).
|
||||
|
||||
@@ -61,7 +61,7 @@ impl FileRetrievalService {
|
||||
mime: &str,
|
||||
file_size: u64,
|
||||
accept_webp: bool,
|
||||
) -> Option<(Bytes, String)> {
|
||||
) -> Option<(Bytes, Arc<str>)> {
|
||||
if !accept_webp {
|
||||
return None;
|
||||
}
|
||||
@@ -81,7 +81,7 @@ impl FileRetrievalService {
|
||||
transcoded.len(),
|
||||
(1.0 - transcoded.len() as f64 / content.len().max(1) as f64) * 100.0
|
||||
);
|
||||
Some((transcoded, webp_mime))
|
||||
Some((transcoded, Arc::from(&*webp_mime)))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
@@ -152,7 +152,7 @@ impl FileRetrievalService {
|
||||
// Store in cache
|
||||
if let Some(cache) = &self.content_cache {
|
||||
let etag: Arc<str> = format!("\"{}-{}\"", id, modified_at).into();
|
||||
let ct: Arc<str> = Arc::from(&*mime_type);
|
||||
let ct: Arc<str> = mime_type.clone();
|
||||
cache
|
||||
.put(id.to_string(), content_bytes.clone(), etag, ct)
|
||||
.await;
|
||||
|
||||
@@ -158,7 +158,7 @@ impl SearchService {
|
||||
name: file.name.clone(),
|
||||
path: file.path.clone(),
|
||||
size: file.size,
|
||||
mime_type: file.mime_type.clone(),
|
||||
mime_type: file.mime_type.to_string(),
|
||||
folder_id: file.folder_id.clone(),
|
||||
created_at: file.created_at,
|
||||
modified_at: file.modified_at,
|
||||
|
||||
Reference in New Issue
Block a user