diff --git a/foyer-storage/src/engine/block/engine.rs b/foyer-storage/src/engine/block/engine.rs index 76c57e83..d78bb156 100644 --- a/foyer-storage/src/engine/block/engine.rs +++ b/foyer-storage/src/engine/block/engine.rs @@ -59,7 +59,7 @@ use crate::{ }, error::{Error, Result}, filter::conditions::IoThrottle, - io::{bytes::IoSliceMut, PAGE}, + io::{bytes::IoSliceMut, device::DeviceCaps, PAGE}, keeper::PieceRef, runtime::Runtime, serde::EntryDeserializer, @@ -332,6 +332,10 @@ where let device = self.device; let block_size = self.block_size; + match device.caps() { + DeviceCaps::Block(_) => {} + } + let mut tombstones = vec![]; let tombstone_log = if self.enable_tombstone_log { diff --git a/foyer-storage/src/io/device/combined.rs b/foyer-storage/src/io/device/combined.rs index 93ddcffc..dd59cc86 100644 --- a/foyer-storage/src/io/device/combined.rs +++ b/foyer-storage/src/io/device/combined.rs @@ -16,7 +16,7 @@ use std::sync::{Arc, RwLock}; use crate::{ io::{ - device::{Device, DeviceBuilder, Partition, PartitionId}, + device::{BlockCaps, Device, DeviceBuilder, DeviceCaps, Partition, PartitionId}, error::{IoError, IoResult}, }, RawFile, Statistics, Throttle, @@ -65,6 +65,16 @@ impl CombinedDeviceBuilder { impl DeviceBuilder for CombinedDeviceBuilder { fn build(self) -> IoResult> { + let mut alignment = 0; + for device in &self.devices { + match device.caps() { + DeviceCaps::Block(block) => alignment = alignment.max(block.alignment), + } + } + if self.devices.is_empty() { + return Err(IoError::other("combined device requires at least one inner device")); + } + let device = CombinedDevice { devices: self.devices, statistics: Arc::new(Statistics::new(self.throttle)), @@ -72,6 +82,7 @@ impl DeviceBuilder for CombinedDeviceBuilder { partitions: vec![], next: 0, }), + caps: DeviceCaps::Block(BlockCaps { alignment }), }; let device = Arc::new(device); Ok(device) @@ -90,9 +101,14 @@ pub struct CombinedDevice { devices: Vec>, inner: RwLock, statistics: Arc, + caps: DeviceCaps, } impl Device for CombinedDevice { + fn caps(&self) -> &DeviceCaps { + &self.caps + } + fn capacity(&self) -> usize { self.devices.iter().map(|d| d.capacity()).sum() } diff --git a/foyer-storage/src/io/device/file.rs b/foyer-storage/src/io/device/file.rs index a5812516..750e26b6 100644 --- a/foyer-storage/src/io/device/file.rs +++ b/foyer-storage/src/io/device/file.rs @@ -22,7 +22,10 @@ use fs4::free_space; use crate::{ io::{ - device::{statistics::Statistics, throttle::Throttle, Device, DeviceBuilder, Partition, PartitionId}, + device::{ + statistics::Statistics, throttle::Throttle, BlockCaps, Device, DeviceBuilder, DeviceCaps, Partition, + PartitionId, + }, error::IoResult, PAGE, }, @@ -119,6 +122,7 @@ impl DeviceBuilder for FileDeviceBuilder { capacity, statistics, partitions: RwLock::new(vec![]), + caps: DeviceCaps::Block(BlockCaps::default()), }; let device: Arc = Arc::new(device); Ok(device) @@ -132,9 +136,14 @@ pub struct FileDevice { capacity: usize, partitions: RwLock>>, statistics: Arc, + caps: DeviceCaps, } impl Device for FileDevice { + fn caps(&self) -> &DeviceCaps { + &self.caps + } + fn capacity(&self) -> usize { self.capacity } diff --git a/foyer-storage/src/io/device/fs.rs b/foyer-storage/src/io/device/fs.rs index aeb473a1..0d6984cc 100644 --- a/foyer-storage/src/io/device/fs.rs +++ b/foyer-storage/src/io/device/fs.rs @@ -22,7 +22,10 @@ use fs4::free_space; use crate::{ io::{ - device::{statistics::Statistics, throttle::Throttle, Device, DeviceBuilder, Partition, PartitionId}, + device::{ + statistics::Statistics, throttle::Throttle, BlockCaps, Device, DeviceBuilder, DeviceCaps, Partition, + PartitionId, + }, error::IoResult, PAGE, }, @@ -103,6 +106,7 @@ impl DeviceBuilder for FsDeviceBuilder { #[cfg(target_os = "linux")] direct: self.direct, partitions: RwLock::new(vec![]), + caps: DeviceCaps::Block(BlockCaps::default()), }; let device: Arc = Arc::new(device); Ok(device) @@ -118,6 +122,7 @@ pub struct FsDevice { #[cfg(target_os = "linux")] direct: bool, partitions: RwLock>>, + caps: DeviceCaps, } impl FsDevice { @@ -128,6 +133,10 @@ impl FsDevice { } impl Device for FsDevice { + fn caps(&self) -> &DeviceCaps { + &self.caps + } + fn capacity(&self) -> usize { self.capacity } diff --git a/foyer-storage/src/io/device/mod.rs b/foyer-storage/src/io/device/mod.rs index 82dd90b0..752bc710 100644 --- a/foyer-storage/src/io/device/mod.rs +++ b/foyer-storage/src/io/device/mod.rs @@ -17,7 +17,7 @@ pub mod throttle; use std::{any::Any, fmt::Debug, sync::Arc}; -use crate::io::{device::statistics::Statistics, error::IoResult}; +use crate::io::{device::statistics::Statistics, error::IoResult, PAGE}; pub type PartitionId = u32; @@ -42,6 +42,26 @@ pub trait DeviceBuilder: Send + Sync + 'static + Debug { fn build(self) -> IoResult>; } +/// The capabilities of a device. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DeviceCaps { + /// A block-addressable device. + Block(BlockCaps), +} + +/// Capabilities for block devices. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct BlockCaps { + /// The required alignment for block I/O. + pub alignment: usize, +} + +impl Default for BlockCaps { + fn default() -> Self { + Self { alignment: PAGE } + } +} + /// Partition is a logical segment of a device. pub trait Partition: Send + Sync + 'static + Debug + Any { /// Get the id of the partition. @@ -61,6 +81,9 @@ pub trait Partition: Send + Sync + 'static + Debug + Any { /// Device trait. pub trait Device: Send + Sync + 'static + Debug + Any { + /// Get the capabilities of the device. + fn caps(&self) -> &DeviceCaps; + /// Get the capacity of the device. /// /// NOTE: `capacity` must be 4K aligned. diff --git a/foyer-storage/src/io/device/noop.rs b/foyer-storage/src/io/device/noop.rs index b7390aba..73a39e17 100644 --- a/foyer-storage/src/io/device/noop.rs +++ b/foyer-storage/src/io/device/noop.rs @@ -16,7 +16,10 @@ use std::sync::{Arc, RwLock}; use crate::{ io::{ - device::{statistics::Statistics, throttle::Throttle, Device, DeviceBuilder, Partition, PartitionId}, + device::{ + statistics::Statistics, throttle::Throttle, BlockCaps, Device, DeviceBuilder, DeviceCaps, Partition, + PartitionId, + }, error::IoResult, }, RawFile, @@ -48,6 +51,7 @@ impl DeviceBuilder for NoopDeviceBuilder { partitions: RwLock::new(vec![]), capacity: self.capacity, statistics, + caps: DeviceCaps::Block(BlockCaps::default()), })) } } @@ -59,9 +63,14 @@ pub struct NoopDevice { capacity: usize, statistics: Arc, + caps: DeviceCaps, } impl Device for NoopDevice { + fn caps(&self) -> &DeviceCaps { + &self.caps + } + fn capacity(&self) -> usize { self.capacity } diff --git a/foyer-storage/src/io/device/partial.rs b/foyer-storage/src/io/device/partial.rs index 36be9a53..3b74cecd 100644 --- a/foyer-storage/src/io/device/partial.rs +++ b/foyer-storage/src/io/device/partial.rs @@ -16,7 +16,7 @@ use std::sync::{Arc, RwLock}; use crate::{ io::{ - device::{statistics::Statistics, Device, DeviceBuilder, Partition, PartitionId}, + device::{statistics::Statistics, Device, DeviceBuilder, DeviceCaps, Partition, PartitionId}, error::IoResult, }, IoError, @@ -51,10 +51,14 @@ impl PartialDeviceBuilder { impl DeviceBuilder for PartialDeviceBuilder { fn build(self) -> IoResult> { + let caps = match self.device.caps() { + DeviceCaps::Block(block) => *block, + }; Ok(Arc::new(PartialDevice { inner: self.device, capacity: self.capacity, partitions: RwLock::new(vec![]), + caps: DeviceCaps::Block(caps), })) } } @@ -65,9 +69,14 @@ pub struct PartialDevice { inner: Arc, capacity: usize, partitions: RwLock>>, + caps: DeviceCaps, } impl Device for PartialDevice { + fn caps(&self) -> &DeviceCaps { + &self.caps + } + fn capacity(&self) -> usize { self.capacity } diff --git a/foyer-storage/src/prelude.rs b/foyer-storage/src/prelude.rs index 11ea7378..f4e76adf 100644 --- a/foyer-storage/src/prelude.rs +++ b/foyer-storage/src/prelude.rs @@ -38,7 +38,7 @@ pub use crate::{ partial::PartialDeviceBuilder, statistics::Statistics, throttle::{IopsCounter, Throttle}, - Device, DeviceBuilder, RawFile, + BlockCaps, Device, DeviceBuilder, DeviceCaps, RawFile, }, engine::{ noop::{NoopIoEngine, NoopIoEngineBuilder},