From 7b2b9cefd9b5737261025dfe4fe18c52df250183 Mon Sep 17 00:00:00 2001 From: Croxx Date: Sun, 29 Sep 2024 00:02:02 +0800 Subject: [PATCH] refactor: refine device build (#745) * refactor: refine device build Signed-off-by: MrCroxx * refactor: restrict device config visibility Signed-off-by: MrCroxx * refactor: remove verify from dev config trait, unnecessary Signed-off-by: MrCroxx --------- Signed-off-by: MrCroxx --- examples/hybrid.rs | 8 +-- examples/hybrid_full.rs | 9 ++- examples/tail_based_tracing.rs | 8 +-- foyer-bench/src/main.rs | 20 +++--- foyer-storage/src/device/direct_file.rs | 83 +++++++++++----------- foyer-storage/src/device/direct_fs.rs | 92 ++++++++++++------------- foyer-storage/src/device/mod.rs | 53 ++++++-------- foyer-storage/src/device/monitor.rs | 29 +++----- foyer-storage/src/large/generic.rs | 20 +++--- foyer-storage/src/large/scanner.rs | 18 +++-- foyer-storage/src/large/tombstone.rs | 18 ++--- foyer-storage/src/prelude.rs | 8 +-- foyer-storage/src/small/generic.rs | 14 ++-- foyer-storage/src/store.rs | 43 ++++++------ foyer-storage/tests/storage_test.rs | 9 ++- foyer/src/hybrid/builder.rs | 8 +-- foyer/src/hybrid/cache.rs | 14 ++-- foyer/src/prelude.rs | 9 ++- 18 files changed, 211 insertions(+), 252 deletions(-) diff --git a/examples/hybrid.rs b/examples/hybrid.rs index fe15af3f..898cd31d 100644 --- a/examples/hybrid.rs +++ b/examples/hybrid.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use foyer::{DirectFsDeviceOptionsBuilder, Engine, HybridCache, HybridCacheBuilder}; +use foyer::{DirectFsDeviceOptions, Engine, HybridCache, HybridCacheBuilder}; #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -21,11 +21,7 @@ async fn main() -> anyhow::Result<()> { let hybrid: HybridCache = HybridCacheBuilder::new() .memory(64 * 1024 * 1024) .storage(Engine::Large) // use large object disk cache engine only - .with_device_config( - DirectFsDeviceOptionsBuilder::new(dir.path()) - .with_capacity(256 * 1024 * 1024) - .build(), - ) + .with_device_options(DirectFsDeviceOptions::new(dir.path()).with_capacity(256 * 1024 * 1024)) .build() .await?; diff --git a/examples/hybrid_full.rs b/examples/hybrid_full.rs index acdf3d40..aca38a03 100644 --- a/examples/hybrid_full.rs +++ b/examples/hybrid_full.rs @@ -17,7 +17,7 @@ use std::sync::Arc; use anyhow::Result; use chrono::Datelike; use foyer::{ - DirectFsDeviceOptionsBuilder, Engine, FifoPicker, HybridCache, HybridCacheBuilder, LargeEngineOptions, LruConfig, + DirectFsDeviceOptions, Engine, FifoPicker, HybridCache, HybridCacheBuilder, LargeEngineOptions, LruConfig, RateLimitPicker, RecoverMode, RuntimeConfig, SmallEngineOptions, TokioRuntimeConfig, TombstoneLogConfigBuilder, }; use tempfile::tempdir; @@ -36,11 +36,10 @@ async fn main() -> Result<()> { .with_hash_builder(ahash::RandomState::default()) .with_weighter(|_key, value: &String| value.len()) .storage(Engine::Mixed(0.1)) - .with_device_config( - DirectFsDeviceOptionsBuilder::new(dir.path()) + .with_device_options( + DirectFsDeviceOptions::new(dir.path()) .with_capacity(64 * 1024 * 1024) - .with_file_size(4 * 1024 * 1024) - .build(), + .with_file_size(4 * 1024 * 1024), ) .with_flush(true) .with_recover_mode(RecoverMode::Quiet) diff --git a/examples/tail_based_tracing.rs b/examples/tail_based_tracing.rs index 254e4377..6bfbba98 100644 --- a/examples/tail_based_tracing.rs +++ b/examples/tail_based_tracing.rs @@ -14,7 +14,7 @@ use std::time::Duration; -use foyer::{DirectFsDeviceOptionsBuilder, Engine, HybridCache, HybridCacheBuilder}; +use foyer::{DirectFsDeviceOptions, Engine, HybridCache, HybridCacheBuilder}; #[cfg(feature = "jaeger")] fn init_jaeger_exporter() { @@ -71,11 +71,7 @@ async fn main() -> anyhow::Result<()> { let hybrid: HybridCache = HybridCacheBuilder::new() .memory(64 * 1024 * 1024) .storage(Engine::Large) - .with_device_config( - DirectFsDeviceOptionsBuilder::new(dir.path()) - .with_capacity(256 * 1024 * 1024) - .build(), - ) + .with_device_options(DirectFsDeviceOptions::new(dir.path()).with_capacity(256 * 1024 * 1024)) .build() .await?; diff --git a/foyer-bench/src/main.rs b/foyer-bench/src/main.rs index 0a0ef321..5cd639e1 100644 --- a/foyer-bench/src/main.rs +++ b/foyer-bench/src/main.rs @@ -34,9 +34,9 @@ use analyze::{analyze, monitor, Metrics}; use bytesize::ByteSize; use clap::{builder::PossibleValuesParser, ArgGroup, Parser}; use foyer::{ - Compression, DirectFileDeviceOptionsBuilder, DirectFsDeviceOptionsBuilder, Engine, FifoConfig, FifoPicker, - HybridCache, HybridCacheBuilder, InvalidRatioPicker, LargeEngineOptions, LfuConfig, LruConfig, RateLimitPicker, - RecoverMode, RuntimeConfig, S3FifoConfig, SmallEngineOptions, TokioRuntimeConfig, TracingConfig, + Compression, DirectFileDeviceOptions, DirectFsDeviceOptions, Engine, FifoConfig, FifoPicker, HybridCache, + HybridCacheBuilder, InvalidRatioPicker, LargeEngineOptions, LfuConfig, LruConfig, RateLimitPicker, RecoverMode, + RuntimeConfig, S3FifoConfig, SmallEngineOptions, TokioRuntimeConfig, TracingConfig, }; use futures::future::join_all; use itertools::Itertools; @@ -462,17 +462,15 @@ async fn benchmark(args: Args) { .storage(args.engine); builder = match (args.file.as_ref(), args.dir.as_ref()) { - (Some(file), None) => builder.with_device_config( - DirectFileDeviceOptionsBuilder::new(file) + (Some(file), None) => builder.with_device_options( + DirectFileDeviceOptions::new(file) .with_capacity(args.disk.as_u64() as _) - .with_region_size(args.region_size.as_u64() as _) - .build(), + .with_region_size(args.region_size.as_u64() as _), ), - (None, Some(dir)) => builder.with_device_config( - DirectFsDeviceOptionsBuilder::new(dir) + (None, Some(dir)) => builder.with_device_options( + DirectFsDeviceOptions::new(dir) .with_capacity(args.disk.as_u64() as _) - .with_file_size(args.region_size.as_u64() as _) - .build(), + .with_file_size(args.region_size.as_u64() as _), ), _ => unreachable!(), }; diff --git a/foyer-storage/src/device/direct_file.rs b/foyer-storage/src/device/direct_file.rs index 8c4ab1ff..88bba196 100644 --- a/foyer-storage/src/device/direct_file.rs +++ b/foyer-storage/src/device/direct_file.rs @@ -22,36 +22,21 @@ use foyer_common::{asyncify::asyncify_with_runtime, bits}; use fs4::free_space; use serde::{Deserialize, Serialize}; -use super::{Dev, DevExt, DevOptions, RegionId}; +use super::{Dev, DevExt, RegionId}; use crate::{ device::ALIGN, error::{Error, Result}, IoBytes, IoBytesMut, Runtime, }; -/// Options for the direct file device. #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct DirectFileDeviceOptions { - /// Path of the direct file device. - pub path: PathBuf, - /// Capacity of the direct file device. - pub capacity: usize, - /// Region size of the direct file device. - pub region_size: usize, -} - -/// A device that uses a single direct i/o file. -#[derive(Debug, Clone)] -pub struct DirectFileDevice { - file: Arc, - +pub struct DirectFileDeviceConfig { + path: PathBuf, capacity: usize, region_size: usize, - - runtime: Runtime, } -impl DevOptions for DirectFileDeviceOptions { +impl DirectFileDeviceConfig { fn verify(&self) -> Result<()> { if self.region_size == 0 || self.region_size % ALIGN != 0 { return Err(anyhow::anyhow!( @@ -74,6 +59,17 @@ impl DevOptions for DirectFileDeviceOptions { } } +/// A device that uses a single direct i/o file. +#[derive(Debug, Clone)] +pub struct DirectFileDevice { + file: Arc, + + capacity: usize, + region_size: usize, + + runtime: Runtime, +} + impl DirectFileDevice { /// Positioned write API for the direct file device. #[fastrace::trace(name = "foyer::storage::device::direct_file::pwrite")] @@ -160,7 +156,7 @@ impl DirectFileDevice { } impl Dev for DirectFileDevice { - type Options = DirectFileDeviceOptions; + type Config = DirectFileDeviceConfig; fn capacity(&self) -> usize { self.capacity @@ -171,7 +167,7 @@ impl Dev for DirectFileDevice { } #[fastrace::trace(name = "foyer::storage::device::direct_file::open")] - async fn open(options: Self::Options, runtime: Runtime) -> Result { + async fn open(options: Self::Config, runtime: Runtime) -> Result { options.verify()?; let dir = options @@ -254,19 +250,19 @@ impl Dev for DirectFileDevice { } } -/// [`DirectFileDeviceOptionsBuilder`] is used to build the options for the direct fs device. +/// [`DirectFileDeviceOptions`] is used to build the options for the direct fs device. /// /// The direct fs device uses a directory in a file system to store the data of disk cache. /// /// It uses direct I/O to reduce buffer copy and page cache pollution if supported. #[derive(Debug)] -pub struct DirectFileDeviceOptionsBuilder { +pub struct DirectFileDeviceOptions { path: PathBuf, capacity: Option, region_size: Option, } -impl DirectFileDeviceOptionsBuilder { +impl DirectFileDeviceOptions { const DEFAULT_FILE_SIZE: usize = 64 * 1024 * 1024; /// Use the given file path as the direct file device path. @@ -297,14 +293,15 @@ impl DirectFileDeviceOptionsBuilder { self.region_size = Some(region_size); self } +} - /// Build the options of the direct file device with the given arguments. - pub fn build(self) -> DirectFileDeviceOptions { - let path = self.path; +impl From for DirectFileDeviceConfig { + fn from(options: DirectFileDeviceOptions) -> Self { + let path = options.path; let align_v = |value: usize, align: usize| value - value % align; - let capacity = self.capacity.unwrap_or({ + let capacity = options.capacity.unwrap_or({ // Create an empty directory before to get free space. let dir = path.parent().expect("path must point to a file").to_path_buf(); create_dir_all(&dir).unwrap(); @@ -312,12 +309,15 @@ impl DirectFileDeviceOptionsBuilder { }); let capacity = align_v(capacity, ALIGN); - let region_size = self.region_size.unwrap_or(Self::DEFAULT_FILE_SIZE).min(capacity); + let region_size = options + .region_size + .unwrap_or(DirectFileDeviceOptions::DEFAULT_FILE_SIZE) + .min(capacity); let region_size = align_v(region_size, ALIGN); let capacity = align_v(capacity, region_size); - DirectFileDeviceOptions { + DirectFileDeviceConfig { path, capacity, region_size, @@ -335,11 +335,11 @@ mod tests { fn test_options_builder() { let dir = tempfile::tempdir().unwrap(); - let options = DirectFileDeviceOptionsBuilder::new(dir.path().join("test-direct-file")).build(); + let config: DirectFileDeviceConfig = DirectFileDeviceOptions::new(dir.path().join("test-direct-file")).into(); - tracing::debug!("{options:?}"); + tracing::debug!("{config:?}"); - options.verify().unwrap(); + config.verify().unwrap(); } #[test_log::test] @@ -347,11 +347,12 @@ mod tests { fn test_options_builder_noent() { let dir = tempfile::tempdir().unwrap(); - let options = DirectFileDeviceOptionsBuilder::new(dir.path().join("noent").join("test-direct-file")).build(); + let config: DirectFileDeviceConfig = + DirectFileDeviceOptions::new(dir.path().join("noent").join("test-direct-file")).into(); - tracing::debug!("{options:?}"); + tracing::debug!("{config:?}"); - options.verify().unwrap(); + config.verify().unwrap(); } #[test_log::test(tokio::test)] @@ -359,14 +360,14 @@ mod tests { let dir = tempfile::tempdir().unwrap(); let runtime = Runtime::current(); - let options = DirectFileDeviceOptionsBuilder::new(dir.path().join("test-direct-file")) + let config: DirectFileDeviceConfig = DirectFileDeviceOptions::new(dir.path().join("test-direct-file")) .with_capacity(4 * 1024 * 1024) .with_region_size(1024 * 1024) - .build(); + .into(); - tracing::debug!("{options:?}"); + tracing::debug!("{config:?}"); - let device = DirectFileDevice::open(options.clone(), runtime.clone()).await.unwrap(); + let device = DirectFileDevice::open(config.clone(), runtime.clone()).await.unwrap(); let mut buf = IoBytesMut::with_capacity(64 * 1024); buf.extend(repeat_n(b'x', 64 * 1024 - 100)); @@ -381,7 +382,7 @@ mod tests { drop(device); - let device = DirectFileDevice::open(options, runtime).await.unwrap(); + let device = DirectFileDevice::open(config, runtime).await.unwrap(); let b = device.read(0, 4096, 64 * 1024 - 100).await.unwrap().freeze(); assert_eq!(buf, b); diff --git a/foyer-storage/src/device/direct_fs.rs b/foyer-storage/src/device/direct_fs.rs index 4e1deb95..30310a06 100644 --- a/foyer-storage/src/device/direct_fs.rs +++ b/foyer-storage/src/device/direct_fs.rs @@ -24,41 +24,21 @@ use futures::future::try_join_all; use itertools::Itertools; use serde::{Deserialize, Serialize}; -use super::{Dev, DevExt, DevOptions, RegionId}; +use super::{Dev, DevExt, RegionId}; use crate::{ device::ALIGN, error::{Error, Result}, IoBytes, IoBytesMut, Runtime, }; -/// Options for the direct fs device. #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct DirectFsDeviceOptions { - /// Directory of the direct fs device. - pub dir: PathBuf, - /// Capacity of the direct fs device. - pub capacity: usize, - /// Direct i/o file size of the direct fs device. - pub file_size: usize, -} - -/// A device that uses direct i/o files in a directory of a file system. -#[derive(Debug, Clone)] -pub struct DirectFsDevice { - inner: Arc, -} - -#[derive(Debug)] -struct DirectFsDeviceInner { - files: Vec>, - +pub struct DirectFsDeviceConfig { + dir: PathBuf, capacity: usize, file_size: usize, - - runtime: Runtime, } -impl DevOptions for DirectFsDeviceOptions { +impl DirectFsDeviceConfig { fn verify(&self) -> Result<()> { if self.file_size == 0 || self.file_size % ALIGN != 0 { return Err(anyhow::anyhow!( @@ -81,6 +61,22 @@ impl DevOptions for DirectFsDeviceOptions { } } +/// A device that uses direct i/o files in a directory of a file system. +#[derive(Debug, Clone)] +pub struct DirectFsDevice { + inner: Arc, +} + +#[derive(Debug)] +struct DirectFsDeviceInner { + files: Vec>, + + capacity: usize, + file_size: usize, + + runtime: Runtime, +} + impl DirectFsDevice { const PREFIX: &'static str = "foyer-storage-direct-fs-"; @@ -94,7 +90,7 @@ impl DirectFsDevice { } impl Dev for DirectFsDevice { - type Options = DirectFsDeviceOptions; + type Config = DirectFsDeviceConfig; fn capacity(&self) -> usize { self.inner.capacity @@ -105,7 +101,7 @@ impl Dev for DirectFsDevice { } #[fastrace::trace(name = "foyer::storage::device::direct_fs::open")] - async fn open(options: Self::Options, runtime: Runtime) -> Result { + async fn open(options: Self::Config, runtime: Runtime) -> Result { options.verify()?; // TODO(MrCroxx): write and read options to a manifest file for pinning @@ -248,19 +244,19 @@ impl Dev for DirectFsDevice { } } -/// [`DirectFsDeviceOptionsBuilder`] is used to build the options for the direct fs device. +/// [`DirectFsDeviceOptions`] is used to build the options for the direct fs device. /// /// The direct fs device uses a directory in a file system to store the data of disk cache. /// /// It uses direct I/O to reduce buffer copy and page cache pollution if supported. #[derive(Debug)] -pub struct DirectFsDeviceOptionsBuilder { +pub struct DirectFsDeviceOptions { dir: PathBuf, capacity: Option, file_size: Option, } -impl DirectFsDeviceOptionsBuilder { +impl DirectFsDeviceOptions { const DEFAULT_FILE_SIZE: usize = 64 * 1024 * 1024; /// Use the given `dir` as the direct fs device. @@ -291,26 +287,30 @@ impl DirectFsDeviceOptionsBuilder { self.file_size = Some(file_size); self } +} - /// Build the options of the direct fs device with the given arguments. - pub fn build(self) -> DirectFsDeviceOptions { - let dir = self.dir; +impl From for DirectFsDeviceConfig { + fn from(options: DirectFsDeviceOptions) -> Self { + let dir = options.dir; let align_v = |value: usize, align: usize| value - value % align; - let capacity = self.capacity.unwrap_or({ + let capacity = options.capacity.unwrap_or({ // Create an empty directory before to get free space. create_dir_all(&dir).unwrap(); free_space(&dir).unwrap() as usize / 10 * 8 }); let capacity = align_v(capacity, ALIGN); - let file_size = self.file_size.unwrap_or(Self::DEFAULT_FILE_SIZE).min(capacity); + let file_size = options + .file_size + .unwrap_or(DirectFsDeviceOptions::DEFAULT_FILE_SIZE) + .min(capacity); let file_size = align_v(file_size, ALIGN); let capacity = align_v(capacity, file_size); - DirectFsDeviceOptions { + DirectFsDeviceConfig { dir, capacity, file_size, @@ -328,11 +328,11 @@ mod tests { fn test_options_builder() { let dir = tempfile::tempdir().unwrap(); - let options = DirectFsDeviceOptionsBuilder::new(dir.path()).build(); + let config: DirectFsDeviceConfig = DirectFsDeviceOptions::new(dir.path()).into(); - tracing::debug!("{options:?}"); + tracing::debug!("{config:?}"); - options.verify().unwrap(); + config.verify().unwrap(); } #[test_log::test] @@ -340,11 +340,11 @@ mod tests { fn test_options_builder_noent() { let dir = tempfile::tempdir().unwrap(); - let options = DirectFsDeviceOptionsBuilder::new(dir.path().join("noent")).build(); + let config: DirectFsDeviceConfig = DirectFsDeviceOptions::new(dir.path().join("noent")).into(); - tracing::debug!("{options:?}"); + tracing::debug!("{config:?}"); - options.verify().unwrap(); + config.verify().unwrap(); } #[test_log::test(tokio::test)] @@ -352,14 +352,14 @@ mod tests { let dir = tempfile::tempdir().unwrap(); let runtime = Runtime::current(); - let options = DirectFsDeviceOptionsBuilder::new(dir.path()) + let config: DirectFsDeviceConfig = DirectFsDeviceOptions::new(dir.path()) .with_capacity(4 * 1024 * 1024) .with_file_size(1024 * 1024) - .build(); + .into(); - tracing::debug!("{options:?}"); + tracing::debug!("{config:?}"); - let device = DirectFsDevice::open(options.clone(), runtime.clone()).await.unwrap(); + let device = DirectFsDevice::open(config.clone(), runtime.clone()).await.unwrap(); let mut buf = IoBytesMut::with_capacity(64 * 1024); buf.extend(repeat_n(b'x', 64 * 1024 - 100)); @@ -374,7 +374,7 @@ mod tests { drop(device); - let device = DirectFsDevice::open(options, runtime).await.unwrap(); + let device = DirectFsDevice::open(config, runtime).await.unwrap(); let b = device.read(0, 4096, 64 * 1024 - 100).await.unwrap().freeze(); assert_eq!(buf, b); diff --git a/foyer-storage/src/device/mod.rs b/foyer-storage/src/device/mod.rs index 998dbf25..15127518 100644 --- a/foyer-storage/src/device/mod.rs +++ b/foyer-storage/src/device/mod.rs @@ -21,6 +21,8 @@ pub mod monitor; use std::{fmt::Debug, future::Future}; use allocator::AlignedAllocator; +use direct_file::DirectFileDeviceConfig; +use direct_fs::DirectFsDeviceConfig; use monitor::Monitored; use crate::{ @@ -33,18 +35,16 @@ pub const IO_BUFFER_ALLOCATOR: AlignedAllocator = AlignedAllocator::new() pub type RegionId = u32; -/// Options for the device. -pub trait DevOptions: Send + Sync + 'static + Debug + Clone { - /// Verify the correctness of the options. - fn verify(&self) -> Result<()>; -} +/// Config for the device. +pub trait DevConfig: Send + Sync + 'static + Debug {} +impl DevConfig for T {} /// [`Dev`] represents 4K aligned block device. /// /// Both i/o block and i/o buffer must be aligned to 4K. pub trait Dev: Send + Sync + 'static + Sized + Clone + Debug { - /// Options for the device. - type Options: DevOptions; + /// Config for the device. + type Config: DevConfig; /// The capacity of the device, must be 4K aligned. fn capacity(&self) -> usize; @@ -53,9 +53,9 @@ pub trait Dev: Send + Sync + 'static + Sized + Clone + Debug { fn region_size(&self) -> usize; // TODO(MrCroxx): Refactor the builder. - /// Open the device with the given options. + /// Open the device with the given config. #[must_use] - fn open(options: Self::Options, runtime: Runtime) -> impl Future> + Send; + fn open(config: Self::Config, runtime: Runtime) -> impl Future> + Send; /// Write API for the device. #[must_use] @@ -86,29 +86,20 @@ pub trait DevExt: Dev { impl DevExt for T where T: Dev {} #[derive(Debug, Clone)] -pub enum DeviceOptions { - DirectFile(DirectFileDeviceOptions), - DirectFs(DirectFsDeviceOptions), -} - -impl From for DeviceOptions { - fn from(value: DirectFileDeviceOptions) -> Self { - Self::DirectFile(value) - } +pub enum DeviceConfig { + DirectFile(DirectFileDeviceConfig), + DirectFs(DirectFsDeviceConfig), } -impl From for DeviceOptions { - fn from(value: DirectFsDeviceOptions) -> Self { - Self::DirectFs(value) +impl From for DeviceConfig { + fn from(options: DirectFileDeviceOptions) -> Self { + Self::DirectFile(options.into()) } } -impl DevOptions for DeviceOptions { - fn verify(&self) -> Result<()> { - match self { - DeviceOptions::DirectFile(dev) => dev.verify(), - DeviceOptions::DirectFs(dev) => dev.verify(), - } +impl From for DeviceConfig { + fn from(options: DirectFsDeviceOptions) -> Self { + Self::DirectFs(options.into()) } } @@ -119,7 +110,7 @@ pub enum Device { } impl Dev for Device { - type Options = DeviceOptions; + type Config = DeviceConfig; fn capacity(&self) -> usize { match self { @@ -135,10 +126,10 @@ impl Dev for Device { } } - async fn open(options: Self::Options, runtime: Runtime) -> Result { + async fn open(options: Self::Config, runtime: Runtime) -> Result { match options { - DeviceOptions::DirectFile(opts) => Ok(Self::DirectFile(DirectFileDevice::open(opts, runtime).await?)), - DeviceOptions::DirectFs(opts) => Ok(Self::DirectFs(DirectFsDevice::open(opts, runtime).await?)), + DeviceConfig::DirectFile(opts) => Ok(Self::DirectFile(DirectFileDevice::open(opts, runtime).await?)), + DeviceConfig::DirectFs(opts) => Ok(Self::DirectFs(DirectFsDevice::open(opts, runtime).await?)), } } diff --git a/foyer-storage/src/device/monitor.rs b/foyer-storage/src/device/monitor.rs index bf29227f..1e897b51 100644 --- a/foyer-storage/src/device/monitor.rs +++ b/foyer-storage/src/device/monitor.rs @@ -24,7 +24,7 @@ use std::{ use foyer_common::{bits, metrics::Metrics}; use super::RegionId; -use crate::{error::Result, Dev, DevExt, DevOptions, DirectFileDevice, IoBytes, IoBytesMut, Runtime}; +use crate::{error::Result, Dev, DevExt, DirectFileDevice, IoBytes, IoBytesMut, Runtime}; /// The statistics information of the device. #[derive(Debug, Default)] @@ -44,35 +44,26 @@ pub struct DeviceStats { } #[derive(Clone)] -pub struct MonitoredOptions +pub struct MonitoredConfig where D: Dev, { - pub options: D::Options, + pub config: D::Config, pub metrics: Arc, } -impl Debug for MonitoredOptions +impl Debug for MonitoredConfig where D: Dev, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MonitoredOptions") - .field("options", &self.options) + .field("options", &self.config) .field("metrics", &self.metrics) .finish() } } -impl DevOptions for MonitoredOptions -where - D: Dev, -{ - fn verify(&self) -> Result<()> { - self.options.verify() - } -} - #[derive(Debug, Clone)] pub struct Monitored where @@ -87,8 +78,8 @@ impl Monitored where D: Dev, { - async fn open(options: MonitoredOptions, runtime: Runtime) -> Result { - let device = D::open(options.options, runtime).await?; + async fn open(options: MonitoredConfig, runtime: Runtime) -> Result { + let device = D::open(options.config, runtime).await?; Ok(Self { device, stats: Arc::default(), @@ -149,7 +140,7 @@ impl Dev for Monitored where D: Dev, { - type Options = MonitoredOptions; + type Config = MonitoredConfig; fn capacity(&self) -> usize { self.device.capacity() @@ -159,8 +150,8 @@ where self.device.region_size() } - async fn open(options: Self::Options, runtime: Runtime) -> Result { - Self::open(options, runtime).await + async fn open(config: Self::Config, runtime: Runtime) -> Result { + Self::open(config, runtime).await } async fn write(&self, buf: IoBytes, region: RegionId, offset: u64) -> Result<()> { diff --git a/foyer-storage/src/large/generic.rs b/foyer-storage/src/large/generic.rs index c501714a..5c8fce90 100644 --- a/foyer-storage/src/large/generic.rs +++ b/foyer-storage/src/large/generic.rs @@ -488,20 +488,18 @@ mod tests { use std::{fs::File, path::Path}; use ahash::RandomState; + use bytesize::ByteSize; use foyer_memory::{Cache, CacheBuilder, FifoConfig}; use itertools::Itertools; use tokio::runtime::Handle; use super::*; use crate::{ - device::{ - direct_fs::DirectFsDeviceOptions, - monitor::{Monitored, MonitoredOptions}, - }, + device::monitor::{Monitored, MonitoredConfig}, picker::utils::{FifoPicker, RejectAllPicker}, serde::EntrySerializer, test_utils::BiasedPicker, - TombstoneLogConfigBuilder, + DirectFsDeviceOptions, TombstoneLogConfigBuilder, }; const KB: usize = 1024; @@ -515,13 +513,11 @@ mod tests { async fn device_for_test(dir: impl AsRef) -> MonitoredDevice { let runtime = Runtime::current(); Monitored::open( - MonitoredOptions { - options: DirectFsDeviceOptions { - dir: dir.as_ref().into(), - capacity: 64 * KB, - file_size: 16 * KB, - } - .into(), + MonitoredConfig { + config: DirectFsDeviceOptions::new(dir) + .with_capacity(ByteSize::kib(64).as_u64() as _) + .with_file_size(ByteSize::kib(16).as_u64() as _) + .into(), metrics: Arc::new(Metrics::new("test")), }, runtime, diff --git a/foyer-storage/src/large/scanner.rs b/foyer-storage/src/large/scanner.rs index bd4bb77d..9704f6f0 100644 --- a/foyer-storage/src/large/scanner.rs +++ b/foyer-storage/src/large/scanner.rs @@ -241,28 +241,26 @@ impl RegionScanner { mod tests { use std::path::Path; + use bytesize::ByteSize; + use super::*; use crate::{ device::{ - monitor::{Monitored, MonitoredOptions}, + monitor::{Monitored, MonitoredConfig}, Dev, MonitoredDevice, }, region::RegionStats, DirectFsDeviceOptions, Runtime, }; - const KB: usize = 1024; - async fn device_for_test(dir: impl AsRef) -> MonitoredDevice { let runtime = Runtime::current(); Monitored::open( - MonitoredOptions { - options: DirectFsDeviceOptions { - dir: dir.as_ref().into(), - capacity: 64 * KB, - file_size: 16 * KB, - } - .into(), + MonitoredConfig { + config: DirectFsDeviceOptions::new(dir) + .with_capacity(ByteSize::kib(64).as_u64() as _) + .with_file_size(ByteSize::kib(16).as_u64() as _) + .into(), metrics: Arc::new(Metrics::new("test")), }, runtime, diff --git a/foyer-storage/src/large/tombstone.rs b/foyer-storage/src/large/tombstone.rs index 3d61e803..c5da6a5a 100644 --- a/foyer-storage/src/large/tombstone.rs +++ b/foyer-storage/src/large/tombstone.rs @@ -25,12 +25,12 @@ use tokio::sync::Mutex; use crate::{ device::{ - direct_file::{DirectFileDevice, DirectFileDeviceOptionsBuilder}, - monitor::{Monitored, MonitoredOptions}, + direct_file::DirectFileDevice, + monitor::{Monitored, MonitoredConfig}, Dev, DevExt, RegionId, }, error::{Error, Result}, - IoBytesMut, Runtime, + DirectFileDeviceOptions, IoBytesMut, Runtime, }; /// The configurations for the tombstone log. @@ -136,11 +136,11 @@ impl TombstoneLog { let capacity = bits::align_up(align, (cache_device.capacity() / align) * Tombstone::serialized_len()); let device = Monitored::open( - MonitoredOptions { - options: DirectFileDeviceOptionsBuilder::new(path) + MonitoredConfig { + config: DirectFileDeviceOptions::new(path) .with_region_size(align) .with_capacity(capacity) - .build(), + .into(), metrics, }, runtime, @@ -312,7 +312,7 @@ mod tests { use tempfile::tempdir; use super::*; - use crate::device::direct_fs::{DirectFsDevice, DirectFsDeviceOptionsBuilder}; + use crate::device::direct_fs::{DirectFsDevice, DirectFsDeviceOptions}; #[test_log::test(tokio::test)] async fn test_tombstone_log() { @@ -322,9 +322,9 @@ mod tests { // 4 MB cache device => 16 KB tombstone log => 1K tombstones let device = DirectFsDevice::open( - DirectFsDeviceOptionsBuilder::new(dir.path()) + DirectFsDeviceOptions::new(dir.path()) .with_capacity(4 * 1024 * 1024) - .build(), + .into(), runtime.clone(), ) .await diff --git a/foyer-storage/src/prelude.rs b/foyer-storage/src/prelude.rs index ac221496..1cd942b4 100644 --- a/foyer-storage/src/prelude.rs +++ b/foyer-storage/src/prelude.rs @@ -16,10 +16,10 @@ pub use crate::{ compress::Compression, device::{ bytes::{IoBuffer, IoBytes, IoBytesMut}, - direct_file::{DirectFileDevice, DirectFileDeviceOptions, DirectFileDeviceOptionsBuilder}, - direct_fs::{DirectFsDevice, DirectFsDeviceOptions, DirectFsDeviceOptionsBuilder}, + direct_file::{DirectFileDevice, DirectFileDeviceOptions}, + direct_fs::{DirectFsDevice, DirectFsDeviceOptions}, monitor::DeviceStats, - Dev, DevExt, DevOptions, + Dev, DevConfig, DevExt, }, error::{Error, Result}, large::{ @@ -34,7 +34,7 @@ pub use crate::{ statistics::Statistics, storage::{either::Order, Storage}, store::{ - DeviceConfig, Engine, LargeEngineOptions, RuntimeConfig, SmallEngineOptions, Store, StoreBuilder, + DeviceOptions, Engine, LargeEngineOptions, RuntimeConfig, SmallEngineOptions, Store, StoreBuilder, TokioRuntimeConfig, }, }; diff --git a/foyer-storage/src/small/generic.rs b/foyer-storage/src/small/generic.rs index d1f6b753..07fa414f 100644 --- a/foyer-storage/src/small/generic.rs +++ b/foyer-storage/src/small/generic.rs @@ -307,7 +307,7 @@ mod tests { use super::*; use crate::{ device::{ - monitor::{Monitored, MonitoredOptions}, + monitor::{Monitored, MonitoredConfig}, Dev, }, serde::EntrySerializer, @@ -323,13 +323,11 @@ mod tests { async fn device_for_test(dir: impl AsRef) -> MonitoredDevice { let runtime = Runtime::current(); Monitored::open( - MonitoredOptions { - options: DirectFsDeviceOptions { - dir: dir.as_ref().into(), - capacity: ByteSize::kib(64).as_u64() as _, - file_size: ByteSize::kib(16).as_u64() as _, - } - .into(), + MonitoredConfig { + config: DirectFsDeviceOptions::new(dir) + .with_capacity(ByteSize::kib(64).as_u64() as _) + .with_file_size(ByteSize::kib(16).as_u64() as _) + .into(), metrics: Arc::new(Metrics::new("test")), }, runtime, diff --git a/foyer-storage/src/store.rs b/foyer-storage/src/store.rs index adea7039..ac49db59 100644 --- a/foyer-storage/src/store.rs +++ b/foyer-storage/src/store.rs @@ -36,9 +36,8 @@ use tokio::runtime::Handle; use crate::{ compress::Compression, device::{ - direct_fs::DirectFsDeviceOptions, - monitor::{DeviceStats, Monitored, MonitoredOptions}, - DeviceOptions, RegionId, ALIGN, + monitor::{DeviceStats, Monitored, MonitoredConfig}, + DeviceConfig, RegionId, ALIGN, }, engine::{EngineConfig, EngineEnum, SizeSelector}, error::{Error, Result}, @@ -55,7 +54,7 @@ use crate::{ either::{EitherConfig, Order}, Storage, }, - Dev, DevExt, DirectFileDeviceOptions, + Dev, DevExt, DirectFileDeviceOptions, DirectFsDeviceOptions, }; /// The disk cache engine that serves as the storage backend of `foyer`. @@ -204,22 +203,22 @@ where /// The configurations for the device. #[derive(Debug, Clone)] -pub enum DeviceConfig { +pub enum DeviceOptions { /// No device. None, /// With device options. - DeviceOptions(DeviceOptions), + DeviceConfig(DeviceConfig), } -impl From for DeviceConfig { - fn from(value: DirectFileDeviceOptions) -> Self { - Self::DeviceOptions(value.into()) +impl From for DeviceOptions { + fn from(options: DirectFileDeviceOptions) -> Self { + Self::DeviceConfig(options.into()) } } -impl From for DeviceConfig { - fn from(value: DirectFsDeviceOptions) -> Self { - Self::DeviceOptions(value.into()) +impl From for DeviceOptions { + fn from(options: DirectFsDeviceOptions) -> Self { + Self::DeviceConfig(options.into()) } } @@ -348,7 +347,7 @@ where name: String, memory: Cache, - device_config: DeviceConfig, + device_options: DeviceOptions, engine: Engine, runtime_config: RuntimeConfig, @@ -377,7 +376,7 @@ where name: "foyer".to_string(), memory, - device_config: DeviceConfig::None, + device_options: DeviceOptions::None, engine, runtime_config: RuntimeConfig::Disabled, @@ -401,9 +400,9 @@ where self } - /// Set device config for the disk cache store. - pub fn with_device_config(mut self, device_config: impl Into) -> Self { - self.device_config = device_config.into(); + /// Set device options for the disk cache store. + pub fn with_device_options(mut self, device_options: impl Into) -> Self { + self.device_options = device_options.into(); self } @@ -524,16 +523,16 @@ where let runtime = runtime.clone(); // Use the user runtime to open engine. tokio::spawn(async move { - match self.device_config { - DeviceConfig::None => { + match self.device_options { + DeviceOptions::None => { tracing::warn!( "[store builder]: No device config set. Use `NoneStore` which always returns `None` for queries." ); EngineEnum::open(EngineConfig::Noop).await } - DeviceConfig::DeviceOptions(options) => { - let device = match Monitored::open(MonitoredOptions { - options, + DeviceOptions::DeviceConfig(options) => { + let device = match Monitored::open(MonitoredConfig { + config: options, metrics: metrics.clone(), }, runtime.clone()) .await { diff --git a/foyer-storage/tests/storage_test.rs b/foyer-storage/tests/storage_test.rs index e20b75ef..a2304352 100644 --- a/foyer-storage/tests/storage_test.rs +++ b/foyer-storage/tests/storage_test.rs @@ -19,7 +19,7 @@ use std::{path::Path, sync::Arc, time::Duration}; use ahash::RandomState; use foyer_memory::{Cache, CacheBuilder, CacheEntry, FifoConfig}; use foyer_storage::{ - test_utils::Recorder, Compression, DirectFsDeviceOptionsBuilder, Engine, LargeEngineOptions, StoreBuilder, + test_utils::Recorder, Compression, DirectFsDeviceOptions, Engine, LargeEngineOptions, StoreBuilder, }; const KB: usize = 1024; @@ -110,11 +110,10 @@ fn basic( ) -> StoreBuilder> { // TODO(MrCroxx): Test mixed engine here. StoreBuilder::new(memory.clone(), Engine::Large) - .with_device_config( - DirectFsDeviceOptionsBuilder::new(path) + .with_device_options( + DirectFsDeviceOptions::new(path) .with_capacity(4 * MB) - .with_file_size(MB) - .build(), + .with_file_size(MB), ) .with_admission_picker(recorder.clone()) .with_flush(true) diff --git a/foyer/src/hybrid/builder.rs b/foyer/src/hybrid/builder.rs index 892cf0b8..f5c3683e 100644 --- a/foyer/src/hybrid/builder.rs +++ b/foyer/src/hybrid/builder.rs @@ -22,7 +22,7 @@ use foyer_common::{ }; use foyer_memory::{Cache, CacheBuilder, EvictionConfig, Weighter}; use foyer_storage::{ - AdmissionPicker, Compression, DeviceConfig, Engine, LargeEngineOptions, RecoverMode, RuntimeConfig, + AdmissionPicker, Compression, DeviceOptions, Engine, LargeEngineOptions, RecoverMode, RuntimeConfig, SmallEngineOptions, StoreBuilder, }; @@ -204,9 +204,9 @@ where V: StorageValue, S: HashBuilder + Debug, { - /// Set device config for the disk cache store. - pub fn with_device_config(self, device_config: impl Into) -> Self { - let builder = self.builder.with_device_config(device_config); + /// Set device options for the disk cache store. + pub fn with_device_options(self, device_options: impl Into) -> Self { + let builder = self.builder.with_device_options(device_options); Self { name: self.name, tracing_config: self.tracing_config, diff --git a/foyer/src/hybrid/cache.rs b/foyer/src/hybrid/cache.rs index 49948fc2..5a728018 100644 --- a/foyer/src/hybrid/cache.rs +++ b/foyer/src/hybrid/cache.rs @@ -551,11 +551,10 @@ mod tests { .memory(4 * MB) // TODO(MrCroxx): Test with `Engine::Mixed`. .storage(Engine::Large) - .with_device_config( - DirectFsDeviceOptionsBuilder::new(dir) + .with_device_options( + DirectFsDeviceOptions::new(dir) .with_capacity(16 * MB) - .with_file_size(MB) - .build(), + .with_file_size(MB), ) .build() .await @@ -575,11 +574,10 @@ mod tests { .memory(4 * MB) // TODO(MrCroxx): Test with `Engine::Mixed`. .storage(Engine::Large) - .with_device_config( - DirectFsDeviceOptionsBuilder::new(dir) + .with_device_options( + DirectFsDeviceOptions::new(dir) .with_capacity(16 * MB) - .with_file_size(MB) - .build(), + .with_file_size(MB), ) .with_admission_picker(Arc::new(BiasedPicker::new(admits))) .build() diff --git a/foyer/src/prelude.rs b/foyer/src/prelude.rs index 4746626e..937c1f5f 100644 --- a/foyer/src/prelude.rs +++ b/foyer/src/prelude.rs @@ -24,11 +24,10 @@ pub use memory::{ S3FifoConfig, Weighter, }; pub use storage::{ - AdmissionPicker, AdmitAllPicker, Compression, Dev, DevExt, DevOptions, DeviceStats, DirectFileDevice, - DirectFileDeviceOptions, DirectFileDeviceOptionsBuilder, DirectFsDevice, DirectFsDeviceOptions, - DirectFsDeviceOptionsBuilder, Engine, EvictionPicker, FifoPicker, InvalidRatioPicker, LargeEngineOptions, - RateLimitPicker, RecoverMode, ReinsertionPicker, RejectAllPicker, Runtime, RuntimeConfig, SmallEngineOptions, - Storage, Store, StoreBuilder, TokioRuntimeConfig, TombstoneLogConfigBuilder, + AdmissionPicker, AdmitAllPicker, Compression, Dev, DevConfig, DevExt, DeviceStats, DirectFileDevice, + DirectFileDeviceOptions, DirectFsDevice, DirectFsDeviceOptions, Engine, EvictionPicker, FifoPicker, + InvalidRatioPicker, LargeEngineOptions, RateLimitPicker, RecoverMode, ReinsertionPicker, RejectAllPicker, Runtime, + RuntimeConfig, SmallEngineOptions, Storage, Store, StoreBuilder, TokioRuntimeConfig, TombstoneLogConfigBuilder, }; pub use crate::hybrid::{