ab_farmer/single_disk_farm/
direct_io_file_wrapper.rs

1//! Wrapper data structure for direct/unbuffered I/O
2
3use ab_direct_io_file::{AlignedPage, DirectIoFile};
4use ab_farmer_components::ReadAtSync;
5use ab_farmer_components::file_ext::FileExt;
6use std::fs::OpenOptions;
7use std::io;
8use std::path::Path;
9
10/// 4096 is as a relatively safe size due to sector size on SSDs commonly being 512 or 4096 bytes
11pub const DISK_PAGE_SIZE: usize = AlignedPage::SIZE;
12
13/// Wrapper data structure for direct/unbuffered I/O
14#[derive(Debug)]
15pub struct DirectIoFileWrapper {
16    file: DirectIoFile,
17}
18
19impl ReadAtSync for DirectIoFileWrapper {
20    #[inline]
21    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
22        self.read_exact_at(buf, offset)
23    }
24}
25
26impl ReadAtSync for &DirectIoFileWrapper {
27    #[inline]
28    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
29        (*self).read_at(buf, offset)
30    }
31}
32
33impl FileExt for DirectIoFileWrapper {
34    fn size(&self) -> io::Result<u64> {
35        self.file.len()
36    }
37
38    fn preallocate(&self, len: u64) -> io::Result<()> {
39        self.file.allocate(len)
40    }
41
42    fn advise_random_access(&self) -> io::Result<()> {
43        // Ignore, already set
44        Ok(())
45    }
46
47    fn advise_sequential_access(&self) -> io::Result<()> {
48        // Ignore, not supported
49        Ok(())
50    }
51
52    fn disable_cache(&self) -> io::Result<()> {
53        // Ignore, not supported
54        Ok(())
55    }
56
57    fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
58        self.file.read_exact_at(buf, offset)
59    }
60
61    fn write_all_at(&self, buf: &[u8], offset: u64) -> io::Result<()> {
62        self.file.write_all_at(buf, offset)
63    }
64}
65
66impl DirectIoFileWrapper {
67    /// Open file at specified path for direct/unbuffered I/O for reads (if file doesn't exist, it
68    /// will be created).
69    ///
70    /// This is especially important on Windows to prevent huge memory usage.
71    pub fn open<P>(path: P) -> io::Result<Self>
72    where
73        P: AsRef<Path>,
74    {
75        let mut open_options = OpenOptions::new();
76        open_options
77            .read(true)
78            .write(true)
79            .create(true)
80            .truncate(false);
81
82        let file = DirectIoFile::open(open_options, path)?;
83
84        Ok(Self { file })
85    }
86
87    /// Truncates or extends the underlying file, updating the size of this file to become `size`.
88    pub fn set_len(&self, size: u64) -> io::Result<()> {
89        self.file.set_len(size)
90    }
91}