/* A storage middleware that logs the time underlying storage operations took. */ use crate::{ storage::{StorageFactory, StorageFactoryExt, TorrentStorage}, ManagedTorrentInfo, }; #[derive(Clone)] pub struct TimingStorageFactory { name: String, underlying_factory: U, } impl TimingStorageFactory { pub fn new(name: String, underlying: U) -> Self { Self { name, underlying_factory: underlying, } } } impl StorageFactory for TimingStorageFactory { type Storage = TimingStorage; fn create(&self, info: &crate::ManagedTorrentInfo) -> anyhow::Result { Ok(TimingStorage { name: self.name.clone(), underlying: self.underlying_factory.create(info)?, }) } fn is_type_id(&self, type_id: std::any::TypeId) -> bool { self.underlying_factory.is_type_id(type_id) } fn clone_box(&self) -> crate::storage::BoxStorageFactory { self.clone().boxed() } } pub struct TimingStorage { name: String, underlying: U, } macro_rules! timeit { ($name:expr, $op:expr, $($rest:tt),*) => { { let start = std::time::Instant::now(); let r = $op; let elapsed = start.elapsed(); tracing::debug!(name = $name, $($rest),*, elapsed_micros=elapsed.as_micros()); r } }; } impl TorrentStorage for TimingStorage { fn pread_exact(&self, file_id: usize, offset: u64, buf: &mut [u8]) -> anyhow::Result<()> { let storage = &self.name; let len = buf.len(); timeit!( "pread_exact", self.underlying.pread_exact(file_id, offset, buf), file_id, offset, storage, len ) } fn pwrite_all(&self, file_id: usize, offset: u64, buf: &[u8]) -> anyhow::Result<()> { let storage = &self.name; let len = buf.len(); timeit!( "pwrite_all", self.underlying.pwrite_all(file_id, offset, buf), file_id, offset, storage, len ) } fn remove_file(&self, file_id: usize, filename: &std::path::Path) -> anyhow::Result<()> { self.underlying.remove_file(file_id, filename) } fn ensure_file_length(&self, file_id: usize, length: u64) -> anyhow::Result<()> { self.underlying.ensure_file_length(file_id, length) } fn take(&self) -> anyhow::Result> { Ok(Box::new(TimingStorage { underlying: self.underlying.take()?, name: self.name.clone(), })) } fn remove_directory_if_empty(&self, path: &std::path::Path) -> anyhow::Result<()> { self.underlying.remove_directory_if_empty(path) } fn init(&mut self, meta: &ManagedTorrentInfo) -> anyhow::Result<()> { self.underlying.init(meta) } }