use std::io;
use std::os::unix::io::AsRawFd;
use io_uring::{opcode, types, IoUring};
const RING_DEPTH: u32 = 8;
pub(super) struct UringContext {
ring: IoUring,
fd: types::Fd,
}
impl std::fmt::Debug for UringContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("UringContext")
.field("fd", &self.fd.0)
.finish_non_exhaustive()
}
}
impl UringContext {
pub(super) fn new(file: &std::fs::File) -> io::Result<Self> {
let ring = IoUring::new(RING_DEPTH)?;
let fd = types::Fd(file.as_raw_fd());
Ok(Self { ring, fd })
}
pub(super) fn pwrite_at(&mut self, offset: u64, buf: &[u8]) -> io::Result<()> {
let entry = opcode::Write::new(self.fd, buf.as_ptr(), buf.len() as u32)
.offset(offset)
.build()
.user_data(0);
unsafe {
self.ring
.submission()
.push(&entry)
.map_err(|_| io::Error::other("uring SQ full"))?;
}
self.ring.submit_and_wait(1)?;
let cqe = self
.ring
.completion()
.next()
.ok_or_else(|| io::Error::other("uring CQE missing"))?;
let n = cqe.result();
if n < 0 {
return Err(io::Error::from_raw_os_error(-n));
}
if (n as usize) != buf.len() {
return Err(io::Error::other(format!(
"short uring write: wrote {} of {}",
n,
buf.len()
)));
}
Ok(())
}
pub(super) fn pread_at(&mut self, offset: u64, buf: &mut [u8]) -> io::Result<()> {
let entry = opcode::Read::new(self.fd, buf.as_mut_ptr(), buf.len() as u32)
.offset(offset)
.build()
.user_data(0);
unsafe {
self.ring
.submission()
.push(&entry)
.map_err(|_| io::Error::other("uring SQ full"))?;
}
self.ring.submit_and_wait(1)?;
let cqe = self
.ring
.completion()
.next()
.ok_or_else(|| io::Error::other("uring CQE missing"))?;
let n = cqe.result();
if n < 0 {
return Err(io::Error::from_raw_os_error(-n));
}
if (n as usize) != buf.len() {
return Err(io::Error::other(format!(
"short uring read: read {} of {}",
n,
buf.len()
)));
}
Ok(())
}
}