From 0986ebf81c933990961c66c8eb953cdca47c5130 Mon Sep 17 00:00:00 2001 From: Dionisio Date: Tue, 24 Feb 2026 12:48:08 +0100 Subject: [PATCH] perf(transcode): eliminate double buffer copy by accepting Bytes instead of &[u8] Change ImageTranscodePort::get_transcoded signature from &[u8] to Bytes. - Rayon closure now receives Bytes::clone() (O(1) ref-count) instead of .to_vec() (~5 MB copy) - Fallback path returns owned Bytes directly instead of Bytes::from(to_vec()) (~5 MB copy) - Caller passes content.clone() (O(1)) instead of implicit deref Saves ~10 MB of allocation per transcode call on a 5 MB image. --- src/application/ports/transcode_ports.rs | 2 +- src/application/services/file_retrieval_service.rs | 2 +- .../services/image_transcode_service.rs | 13 ++++++++----- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/application/ports/transcode_ports.rs b/src/application/ports/transcode_ports.rs index d5d35833..c70d75a8 100644 --- a/src/application/ports/transcode_ports.rs +++ b/src/application/ports/transcode_ports.rs @@ -90,7 +90,7 @@ pub trait ImageTranscodePort: Send + Sync + 'static { async fn get_transcoded( &self, file_id: &str, - original_content: &[u8], + original_content: Bytes, original_mime: &str, target_format: OutputFormat, ) -> Result<(Bytes, String, bool), DomainError>; diff --git a/src/application/services/file_retrieval_service.rs b/src/application/services/file_retrieval_service.rs index e3389607..3832df9a 100644 --- a/src/application/services/file_retrieval_service.rs +++ b/src/application/services/file_retrieval_service.rs @@ -88,7 +88,7 @@ impl FileRetrievalService { return None; } let format = OutputFormat::WebP; - match transcode.get_transcoded(id, content, mime, format).await { + match transcode.get_transcoded(id, content.clone(), mime, format).await { Ok((transcoded, webp_mime, true)) => { debug!( "🖼️ WebP transcode: {} -> {} bytes ({:.0}% smaller)", diff --git a/src/infrastructure/services/image_transcode_service.rs b/src/infrastructure/services/image_transcode_service.rs index 7d4ddd7e..2fca238c 100644 --- a/src/infrastructure/services/image_transcode_service.rs +++ b/src/infrastructure/services/image_transcode_service.rs @@ -192,10 +192,13 @@ impl ImageTranscodeService { /// Get transcoded version of an image. /// Returns `(content, mime_type, was_transcoded)`. + /// + /// Accepts `Bytes` (ref-counted) so callers avoid copying the buffer. + /// Cloning `Bytes` is O(1) — only an atomic increment. pub async fn get_transcoded( &self, file_id: &str, - original_content: &[u8], + original_content: Bytes, original_mime: &str, target_format: OutputFormat, ) -> Result<(Bytes, String, bool), String> { @@ -228,13 +231,13 @@ impl ImageTranscodeService { } // ── 3. Transcode on dedicated rayon pool (never blocks Tokio) ── - let content_owned = original_content.to_vec(); + let content_for_rayon = original_content.clone(); // O(1) ref-count bump let mime_owned = original_mime.to_string(); let (tx, rx) = tokio::sync::oneshot::channel(); transcode_pool().spawn(move || { - let result = transcode_image_blocking(&content_owned, &mime_owned, target_format); + let result = transcode_image_blocking(&content_for_rayon, &mime_owned, target_format); let _ = tx.send(result); }); @@ -256,7 +259,7 @@ impl ImageTranscodeService { transcoded_size ); return Ok(( - Bytes::from(original_content.to_vec()), + original_content, original_mime.to_string(), false, )); @@ -394,7 +397,7 @@ impl ImageTranscodePort for ImageTranscodeService { async fn get_transcoded( &self, file_id: &str, - original_content: &[u8], + original_content: Bytes, original_mime: &str, target_format: PortOutputFormat, ) -> Result<(Bytes, String, bool), DomainError> {