#![deny(unsafe_code)]
use std::fs::File;
pub fn advise_sequential(file: &File) {
#[cfg(target_os = "linux")]
linux::advise_sequential(file);
#[cfg(not(target_os = "linux"))]
let _ = file;
}
pub fn advise_willneed_raw(fd: i32, offset: i64, len: i64) {
#[cfg(target_os = "linux")]
linux::advise_willneed_raw(fd, offset, len);
#[cfg(not(target_os = "linux"))]
let _ = (fd, offset, len);
}
#[must_use]
#[cfg(target_os = "linux")]
pub fn hint_fd(file: &File) -> Option<i32> {
use std::os::fd::AsRawFd;
Some(file.as_raw_fd())
}
#[must_use]
#[cfg(not(target_os = "linux"))]
pub fn hint_fd(_file: &File) -> Option<i32> {
None
}
#[cfg(target_os = "linux")]
mod linux {
use std::fs::File;
use std::os::fd::AsRawFd;
use nix::fcntl::{PosixFadviseAdvice, posix_fadvise};
pub(super) fn advise_sequential(file: &File) {
let fd = file.as_raw_fd();
if let Err(e) = posix_fadvise(fd, 0, 0, PosixFadviseAdvice::POSIX_FADV_SEQUENTIAL) {
log::debug!("posix_fadvise(POSIX_FADV_SEQUENTIAL) failed on fd {fd}: {e}");
}
}
pub(super) fn advise_willneed_raw(fd: i32, offset: i64, len: i64) {
if let Err(e) = posix_fadvise(fd, offset, len, PosixFadviseAdvice::POSIX_FADV_WILLNEED) {
log::debug!("posix_fadvise(POSIX_FADV_WILLNEED) failed on fd {fd}: {e}");
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Write;
use tempfile::NamedTempFile;
#[test]
fn advise_sequential_does_not_error_on_regular_file() {
let mut tmp = NamedTempFile::new().expect("create temp file");
tmp.write_all(b"hello world").expect("write temp file");
let f = File::open(tmp.path()).expect("reopen temp file for read");
advise_sequential(&f);
}
#[test]
fn advise_sequential_is_callable_repeatedly() {
let tmp = NamedTempFile::new().expect("create temp file");
let f = File::open(tmp.path()).expect("open temp file");
for _ in 0..16 {
advise_sequential(&f);
}
}
}