use core::future::poll_fn;
use std::io;
use std::sync::Arc;
use super::FileIo;
#[cfg(ring)]
use super::work::Work;
use crate::io::source::Failure;
use crate::io::source::requests::Lease;
#[derive(Clone, Copy)]
pub(crate) enum SyncKind {
All,
Data,
Range {
#[cfg_attr(not(target_os = "linux"), allow(dead_code))]
offset: u64,
#[cfg_attr(not(target_os = "linux"), allow(dead_code))]
len: u64,
},
}
impl FileIo {
pub(crate) async fn sync(self: &Arc<Self>, kind: SyncKind) -> io::Result<()> {
poll_fn(|cx| self.poll_flush(cx)).await?;
if let Some(failed) = self.sync_failed.get() {
return Err(failed.error());
}
let result = self.sync_call(kind).await;
if let Err(err) = &result {
let _ = self.sync_failed.set(Failure::of(err));
}
result.and_then(|()| self.sync_failed.get().map_or(Ok(()), |f| Err(f.error())))
}
async fn sync_call(&self, kind: SyncKind) -> io::Result<()> {
#[cfg(ring)]
if self.on_ring() {
let job = match kind {
SyncKind::All => crate::fs::ring::sync(&self.fd, false),
SyncKind::Data => crate::fs::ring::sync(&self.fd, true),
SyncKind::Range { offset, len } => match u32::try_from(len) {
Ok(len) => crate::fs::ring::sync_range(&self.fd, offset, len),
Err(_) => Err(()),
},
};
if let Ok(job) = job {
let mut work = Work::Slot(job);
return poll_fn(|cx| work.poll(cx.waker())).await;
}
}
let fd = self.fd.clone();
crate::rt::blocking::call(move || sync_on(&fd, kind)).await
}
}
pub(crate) fn sync_on(fd: &Lease, kind: SyncKind) -> io::Result<()> {
sync_file(&fd.file(), kind)
}
pub(crate) fn sync_file(file: &std::fs::File, kind: SyncKind) -> io::Result<()> {
match kind {
SyncKind::All => file.sync_all(),
#[cfg(not(target_os = "linux"))]
SyncKind::Data | SyncKind::Range { .. } => file.sync_data(),
#[cfg(target_os = "linux")]
SyncKind::Data => file.sync_data(),
#[cfg(target_os = "linux")]
SyncKind::Range { offset, len } => {
use std::os::fd::AsRawFd;
crate::io::sys::sync_file_range(file.as_raw_fd(), offset, len)
}
}
}