Skip to main content

irox_tools/read/
pagefile.rs

1// SPDX-License-Identifier: MIT
2// Copyright 2024 IROX Contributors
3//
4
5use irox_bits::{Error, SeekRead, SeekWrite};
6use std::fs::File;
7use std::path::Path;
8
9pub const FILE_FLAG_NO_BUFFERING: u32 = 0x20000000;
10pub const FILE_FLAG_RANDOM_ACCESS: u32 = 0x10000000;
11pub const FILE_FLAG_WRITE_THROUGH: u32 = 0x80000000;
12pub const FILE_FLAG_OVERLAPPED: u32 = 0x40000000;
13
14pub struct Pagefile {
15    backing_file: File,
16}
17
18impl Pagefile {
19    pub fn open<T: AsRef<Path>>(path: T) -> Result<Pagefile, Error> {
20        let backing_file = std::fs::OpenOptions::new()
21            .read(true)
22            .write(true)
23            .create(true)
24            .truncate(false)
25            // .attributes(
26            //     FILE_FLAG_NO_BUFFERING
27            //         | FILE_FLAG_WRITE_THROUGH
28            //         | FILE_FLAG_OVERLAPPED
29            // )
30            .open(path)?;
31        Ok(Pagefile { backing_file })
32    }
33
34    pub fn read_page<const N: usize>(&mut self, page_num: u64) -> Result<[u8; N], Error> {
35        let mut buf = [0; N];
36        let offset = page_num * N as u64;
37        let read = self.backing_file.seek_read(&mut buf, offset)?;
38        debug_assert!(
39            read == 0 || read == N,
40            "Read less than expected (0 < {read} < {N}) "
41        );
42        Ok(buf)
43    }
44    pub fn write_page<const N: usize>(
45        &mut self,
46        page_num: u64,
47        data: &[u8; N],
48    ) -> Result<(), Error> {
49        let offset = page_num * N as u64;
50        let write = self.backing_file.seek_write(data, offset)?;
51        debug_assert!(write == N, "Wrote less than expected ({write} != {N})");
52        Ok(())
53    }
54}
55
56#[cfg(test)]
57mod test {
58    use crate::random::PRNG;
59    use crate::read::Pagefile;
60    use irox_bits::Error;
61    use std::io::Write;
62
63    #[test]
64    #[ignore]
65    pub fn test() -> Result<(), Error> {
66        let mut file = Pagefile::open("test_page.pagefile")?;
67        let mut rnd = crate::random::PcgXslRrRr::new_seed(0);
68
69        let mut page = [0u8; 4096];
70        let start = std::time::Instant::now();
71        for idx in 0..=1_000_000 {
72            let mut sli = page.as_mut_slice();
73            for _i in 0..32 {
74                sli.write_all(&rnd.next_u128().to_be_bytes())?;
75            }
76            file.write_page(idx, &page)?;
77        }
78        file.backing_file.sync_data()?;
79        let elapsed = start.elapsed();
80        let len = page.len() * 1_000_000;
81        let dur = elapsed.as_secs_f64();
82        println!(
83            "Wrote {} in {}s = {} MB/s",
84            len,
85            dur,
86            len as f64 / dur / 1e6
87        );
88        Ok(())
89    }
90}