diff --git a/core/Cargo.toml b/core/Cargo.toml index 0aab086b4..c0c579152 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -14,7 +14,7 @@ name = "limbo_core" path = "lib.rs" [features] -default = ["fs", "json", "uuid"] +default = ["fs", "json", "uuid", "io_uring"] fs = [] json = [ "dep:jsonb", @@ -22,11 +22,12 @@ json = [ "dep:pest_derive", ] uuid = ["dep:uuid"] +io_uring = ["dep:io-uring"] [target.'cfg(target_os = "linux")'.dependencies] -io-uring = "0.6.1" +io-uring = { version = "0.6.1", optional = true } -[target.'cfg(target_os = "macos")'.dependencies] +[target.'cfg(target_family = "unix")'.dependencies] polling = "3.7.2" rustix = "0.38.34" diff --git a/core/error.rs b/core/error.rs index 85473ff68..646e85825 100644 --- a/core/error.rs +++ b/core/error.rs @@ -19,12 +19,12 @@ pub enum LimboError { EnvVarError(#[from] std::env::VarError), #[error("I/O error: {0}")] IOError(#[from] std::io::Error), - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", feature = "io_uring"))] #[error("I/O error: {0}")] - LinuxIOError(String), + UringIOError(String), #[error("Locking error: {0}")] LockingError(String), - #[cfg(target_os = "macos")] + #[cfg(target_family = "unix")] #[error("I/O error: {0}")] RustixIOError(#[from] rustix::io::Errno), #[error("Parse error: {0}")] diff --git a/core/io/linux.rs b/core/io/io_uring.rs similarity index 93% rename from core/io/linux.rs rename to core/io/io_uring.rs index 70de8ef79..54a02ee61 100644 --- a/core/io/linux.rs +++ b/core/io/io_uring.rs @@ -14,15 +14,15 @@ const MAX_IOVECS: usize = 128; const SQPOLL_IDLE: u32 = 1000; #[derive(Debug, Error)] -enum LinuxIOError { +enum UringIOError { IOUringCQError(i32), } // Implement the Display trait to customize error messages -impl fmt::Display for LinuxIOError { +impl fmt::Display for UringIOError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - LinuxIOError::IOUringCQError(code) => write!( + UringIOError::IOUringCQError(code) => write!( f, "IOUring completion queue error occurred with code {}", code @@ -31,8 +31,8 @@ impl fmt::Display for LinuxIOError { } } -pub struct LinuxIO { - inner: Rc>, +pub struct UringIO { + inner: Rc>, } struct WrappedIOUring { @@ -42,13 +42,13 @@ struct WrappedIOUring { key: u64, } -struct InnerLinuxIO { +struct InnerUringIO { ring: WrappedIOUring, iovecs: [iovec; MAX_IOVECS], next_iovec: usize, } -impl LinuxIO { +impl UringIO { pub fn new() -> Result { let ring = match io_uring::IoUring::builder() .setup_sqpoll(SQPOLL_IDLE) @@ -57,7 +57,7 @@ impl LinuxIO { Ok(ring) => ring, Err(_) => io_uring::IoUring::new(MAX_IOVECS as u32)?, }; - let inner = InnerLinuxIO { + let inner = InnerUringIO { ring: WrappedIOUring { ring, pending_ops: 0, @@ -76,7 +76,7 @@ impl LinuxIO { } } -impl InnerLinuxIO { +impl InnerUringIO { pub fn get_iovec(&mut self, buf: *const u8, len: usize) -> &iovec { let iovec = &mut self.iovecs[self.next_iovec]; iovec.iov_base = buf as *mut std::ffi::c_void; @@ -125,7 +125,7 @@ impl WrappedIOUring { } } -impl IO for LinuxIO { +impl IO for UringIO { fn open_file(&self, path: &str, flags: OpenFlags, direct: bool) -> Result> { trace!("open_file(path = {})", path); let file = std::fs::File::options() @@ -142,14 +142,14 @@ impl IO for LinuxIO { Err(error) => debug!("Error {error:?} returned when setting O_DIRECT flag to read file. The performance of the system may be affected"), }; } - let linux_file = Rc::new(LinuxFile { + let uring_file = Rc::new(UringFile { io: self.inner.clone(), file, }); if std::env::var(common::ENV_DISABLE_FILE_LOCK).is_err() { - linux_file.lock_file(true)?; + uring_file.lock_file(true)?; } - Ok(linux_file) + Ok(uring_file) } fn run_once(&self) -> Result<()> { @@ -165,9 +165,9 @@ impl IO for LinuxIO { while let Some(cqe) = ring.get_completion() { let result = cqe.result(); if result < 0 { - return Err(LimboError::LinuxIOError(format!( + return Err(LimboError::UringIOError(format!( "{} cqe: {:?}", - LinuxIOError::IOUringCQError(result), + UringIOError::IOUringCQError(result), cqe ))); } @@ -191,12 +191,12 @@ impl IO for LinuxIO { } } -pub struct LinuxFile { - io: Rc>, +pub struct UringFile { + io: Rc>, file: std::fs::File, } -impl File for LinuxFile { +impl File for UringFile { fn lock_file(&self, exclusive: bool) -> Result<()> { let fd = self.file.as_raw_fd(); let flock = flock { @@ -306,7 +306,7 @@ impl File for LinuxFile { } } -impl Drop for LinuxFile { +impl Drop for UringFile { fn drop(&mut self) { self.unlock_file().expect("Failed to unlock file"); } @@ -319,6 +319,6 @@ mod tests { #[test] fn test_multiple_processes_cannot_open_file() { - common::tests::test_multiple_processes_cannot_open_file(LinuxIO::new); + common::tests::test_multiple_processes_cannot_open_file(UringIO::new); } } diff --git a/core/io/mod.rs b/core/io/mod.rs index 3bed97b16..7e910f4af 100644 --- a/core/io/mod.rs +++ b/core/io/mod.rs @@ -164,14 +164,14 @@ impl Buffer { } cfg_block! { - #[cfg(target_os = "linux")] { - mod linux; - pub use linux::LinuxIO as PlatformIO; + #[cfg(all(target_os = "linux", feature = "io_uring"))] { + mod io_uring; + pub use io_uring::UringIO as PlatformIO; } - #[cfg(target_os = "macos")] { - mod darwin; - pub use darwin::DarwinIO as PlatformIO; + #[cfg(any(all(target_os = "linux",not(feature = "io_uring")), target_os = "macos"))] { + mod unix; + pub use unix::UnixIO as PlatformIO; } #[cfg(target_os = "windows")] { diff --git a/core/io/darwin.rs b/core/io/unix.rs similarity index 97% rename from core/io/darwin.rs rename to core/io/unix.rs index c052b572f..c86e05ee4 100644 --- a/core/io/darwin.rs +++ b/core/io/unix.rs @@ -14,13 +14,13 @@ use std::collections::HashMap; use std::io::{Read, Seek, Write}; use std::rc::Rc; -pub struct DarwinIO { +pub struct UnixIO { poller: Rc>, events: Rc>, callbacks: Rc>>, } -impl DarwinIO { +impl UnixIO { pub fn new() -> Result { Ok(Self { poller: Rc::new(RefCell::new(Poller::new()?)), @@ -30,7 +30,7 @@ impl DarwinIO { } } -impl IO for DarwinIO { +impl IO for UnixIO { fn open_file(&self, path: &str, flags: OpenFlags, _direct: bool) -> Result> { trace!("open_file(path = {})", path); let file = std::fs::File::options() @@ -40,15 +40,15 @@ impl IO for DarwinIO { .create(matches!(flags, OpenFlags::Create)) .open(path)?; - let darwin_file = Rc::new(DarwinFile { + let unix_file = Rc::new(UnixFile { file: Rc::new(RefCell::new(file)), poller: self.poller.clone(), callbacks: self.callbacks.clone(), }); if std::env::var(common::ENV_DISABLE_FILE_LOCK).is_err() { - darwin_file.lock_file(true)?; + unix_file.lock_file(true)?; } - Ok(darwin_file) + Ok(unix_file) } fn run_once(&self) -> Result<()> { @@ -127,13 +127,13 @@ enum CompletionCallback { ), } -pub struct DarwinFile { +pub struct UnixFile { file: Rc>, poller: Rc>, callbacks: Rc>>, } -impl File for DarwinFile { +impl File for UnixFile { fn lock_file(&self, exclusive: bool) -> Result<()> { let fd = self.file.borrow().as_raw_fd(); let flock = flock { @@ -279,7 +279,7 @@ impl File for DarwinFile { } } -impl Drop for DarwinFile { +impl Drop for UnixFile { fn drop(&mut self) { self.unlock_file().expect("Failed to unlock file"); } @@ -291,6 +291,6 @@ mod tests { #[test] fn test_multiple_processes_cannot_open_file() { - common::tests::test_multiple_processes_cannot_open_file(DarwinIO::new); + common::tests::test_multiple_processes_cannot_open_file(UnixIO::new); } }