pub trait WalSyncBackend: Send + Sync {
fn sync_file(&self, file: &std::fs::File) -> std::io::Result<()>;
}
pub struct StdFsync;
impl WalSyncBackend for StdFsync {
#[inline]
fn sync_file(&self, file: &std::fs::File) -> std::io::Result<()> {
file.sync_all()
}
}
#[cfg(feature = "io-uring-backend")]
pub struct IoUringFsync {
ring: parking_lot::Mutex<io_uring::IoUring>,
}
#[cfg(feature = "io-uring-backend")]
impl IoUringFsync {
pub fn new(ring_entries: u32) -> std::io::Result<Self> {
let ring = io_uring::IoUring::new(ring_entries)?;
Ok(Self {
ring: parking_lot::Mutex::new(ring),
})
}
pub fn default_ring() -> std::io::Result<Self> {
Self::new(8)
}
}
#[cfg(feature = "io-uring-backend")]
impl WalSyncBackend for IoUringFsync {
fn sync_file(&self, file: &std::fs::File) -> std::io::Result<()> {
use std::os::unix::io::AsRawFd;
let fd = io_uring::types::Fd(file.as_raw_fd());
let fsync_op = io_uring::opcode::Fsync::new(fd).build();
let mut ring = self.ring.lock();
unsafe {
ring.submission().push(&fsync_op).map_err(|_| {
std::io::Error::new(std::io::ErrorKind::Other, "io_uring submission queue full")
})?;
}
ring.submit_and_wait(1)?;
let cqe = ring.completion().next().ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::Other,
"io_uring: no completion entry after fsync",
)
})?;
let result = cqe.result();
if result < 0 {
return Err(std::io::Error::from_raw_os_error(-result));
}
Ok(())
}
}