use crate::{Error, Result};
use std::os::fd::AsRawFd;
pub fn readahead(file: &impl AsRawFd, offset: u64, count: usize) -> Result<()> {
#[cfg(target_os = "linux")]
{
let off = libc::off64_t::try_from(offset).map_err(|_| Error::System {
operation: "readahead",
source: std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"offset too large for off64_t",
),
})?;
let result = unsafe { libc::readahead(file.as_raw_fd(), off, count) };
if result != 0 {
return Err(Error::System {
operation: "readahead",
source: std::io::Error::last_os_error(),
});
}
}
#[cfg(not(target_os = "linux"))]
{
_ = (file, offset, count);
}
Ok(())
}
pub fn evict_pages(file: &impl AsRawFd, offset: u64, len: u64) -> Result<()> {
#[cfg(target_os = "linux")]
{
let off = libc::off_t::try_from(offset).map_err(|_| Error::System {
operation: "posix_fadvise(DONTNEED)",
source: std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"offset too large for off_t",
),
})?;
let length = libc::off_t::try_from(len).map_err(|_| Error::System {
operation: "posix_fadvise(DONTNEED)",
source: std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"len too large for off_t",
),
})?;
let result = unsafe {
libc::posix_fadvise(file.as_raw_fd(), off, length, libc::POSIX_FADV_DONTNEED)
};
if result != 0 {
return Err(Error::System {
operation: "posix_fadvise(DONTNEED)",
source: std::io::Error::from_raw_os_error(result),
});
}
}
#[cfg(not(target_os = "linux"))]
{
_ = (file, offset, len);
}
Ok(())
}
pub fn advise_sequential(file: &impl AsRawFd) -> Result<()> {
#[cfg(target_os = "linux")]
{
let result =
unsafe { libc::posix_fadvise(file.as_raw_fd(), 0, 0, libc::POSIX_FADV_SEQUENTIAL) };
if result != 0 {
return Err(Error::System {
operation: "posix_fadvise(SEQUENTIAL)",
source: std::io::Error::from_raw_os_error(result),
});
}
}
#[cfg(not(target_os = "linux"))]
{
_ = file;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Write;
#[test]
fn readahead_on_tempfile() {
let mut f = tempfile::NamedTempFile::new().unwrap();
f.write_all(&[0u8; 4096]).unwrap();
let _ = readahead(f.as_file(), 0, 4096);
}
#[test]
fn evict_pages_on_tempfile() {
let mut f = tempfile::NamedTempFile::new().unwrap();
f.write_all(&[0u8; 4096]).unwrap();
let _ = evict_pages(f.as_file(), 0, 4096);
}
#[test]
fn advise_sequential_on_tempfile() {
let mut f = tempfile::NamedTempFile::new().unwrap();
f.write_all(&[0u8; 4096]).unwrap();
assert!(advise_sequential(f.as_file()).is_ok());
}
}