diff --git a/services/blob/src/service.rs b/services/blob/src/service.rs --- a/services/blob/src/service.rs +++ b/services/blob/src/service.rs @@ -14,6 +14,7 @@ }, database::{BlobItem, DatabaseClient, ReverseIndexItem}, s3::{MultiPartUploadSession, S3Client, S3Path}, + tools::MemOps, }; pub mod blob { @@ -394,12 +395,11 @@ if self.current_chunk.len() as u64 > S3_MULTIPART_UPLOAD_MINIMUM_CHUNK_SIZE { trace!("Chunk size exceeded, adding new S3 part"); - if let Err(err) = uploader.add_part(self.current_chunk.clone()).await { + if let Err(err) = uploader.add_part(self.current_chunk.take_out()).await { self.should_close_stream = true; error!("Failed to upload S3 part: {:?}", err); return Err(Status::aborted("Internal error")); } - self.current_chunk.clear(); } Ok(blob::PutResponse { data_exists: false }) diff --git a/services/blob/src/tools.rs b/services/blob/src/tools.rs --- a/services/blob/src/tools.rs +++ b/services/blob/src/tools.rs @@ -10,3 +10,50 @@ pub fn is_sandbox_env() -> bool { return is_env_flag_set(constants::SANDBOX_ENV_VAR); } + +pub trait MemOps { + fn take_out(&mut self) -> Self; +} + +impl MemOps for Vec { + /// Moves all the elements of `self` into a new [`Vec`] instance, + /// leaving `self` empty. **No copying is performed.** + /// The memory capacity of `self` stays unchanged. + /// + /// In fact, this is the same as [`std::mem::take`] but maintains capacity. + /// + /// # Example + /// ``` + /// let mut a = vec![1,2,3,4]; + /// let b = a.take_out(); + /// assert_eq!(b.len(), 4); + /// assert!(a.is_empty()); + /// assert_eq!(a.capacity(), b.capacity()); + /// ``` + fn take_out(&mut self) -> Self { + let mut new_vec = Vec::with_capacity(self.capacity()); + std::mem::swap(self, &mut new_vec); + new_vec + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_memops_move_and_clear() { + let mut a = vec![1, 2, 3, 4]; + let a_ptr_before = a.as_ptr(); + + let b = a.take_out(); + let a_ptr_after = a.as_ptr(); + let b_ptr_after = b.as_ptr(); + + assert_ne!(a_ptr_before, a_ptr_after, "Old ptr didn't change"); + assert_eq!(a_ptr_before, b_ptr_after, "Ptr addresses don't match"); + assert_eq!(a.capacity(), b.capacity(), "Capacities don't match"); + assert!(a.is_empty(), "Original vec isn't empty after move"); + assert_eq!(b.len(), 4, "Moved length don't match"); + } +}