seekable_async_file/
mmap.rs

1use crate::common::ISyncIO;
2use off64::usz;
3use std::path::Path;
4use std::sync::Arc;
5use tokio::fs::OpenOptions;
6
7/// A `File`-like value that can perform async `read_at` and `write_at` for I/O at specific offsets without mutating any state (i.e. is thread safe). Metrics are collected, and syncs can be delayed for write batching opportunities as a performance optimisation.
8pub struct MMapIO {
9  mmap: Arc<memmap2::MmapRaw>,
10  mmap_len: usize,
11}
12
13impl MMapIO {
14  /// Open a file descriptor in read and write modes, creating it if it doesn't exist. If it already exists, the contents won't be truncated.
15  ///
16  /// If the mmap feature is being used, to save a `stat` call, the size must be provided. This also allows opening non-standard files which may have a size of zero (e.g. block devices). A different size value also allows only using a portion of the beginning of the file.
17  ///
18  /// The `io_direct` and `io_dsync` parameters set the `O_DIRECT` and `O_DSYNC` flags, respectively. Unless you need those flags, provide `false`.
19  ///
20  /// Make sure to execute `start_delayed_data_sync_background_loop` in the background after this call.
21  pub async fn open(path: &Path, size: u64, flags: i32) -> Self {
22    let async_fd = OpenOptions::new()
23      .read(true)
24      .write(true)
25      .custom_flags(flags)
26      .open(path)
27      .await
28      .unwrap();
29
30    let fd = async_fd.into_std().await;
31
32    Self {
33      mmap: Arc::new(memmap2::MmapRaw::map_raw(&fd).unwrap()),
34      mmap_len: usz!(size),
35    }
36  }
37
38  pub unsafe fn get_mmap_raw_ptr(&self, offset: u64) -> *const u8 {
39    self.mmap.as_ptr().add(usz!(offset))
40  }
41
42  pub unsafe fn get_mmap_raw_mut_ptr(&self, offset: u64) -> *mut u8 {
43    self.mmap.as_mut_ptr().add(usz!(offset))
44  }
45}
46
47impl ISyncIO for MMapIO {
48  fn read_at_sync(&self, offset: u64, len: u64) -> Vec<u8> {
49    let offset = usz!(offset);
50    let len = usz!(len);
51    let memory = unsafe { std::slice::from_raw_parts(self.mmap.as_ptr(), self.mmap_len) };
52    memory[offset..offset + len].to_vec()
53  }
54
55  fn write_at_sync(&self, offset: u64, data: &[u8]) -> () {
56    let offset = usz!(offset);
57    let len = data.as_ref().len();
58
59    let memory = unsafe { std::slice::from_raw_parts_mut(self.mmap.as_mut_ptr(), self.mmap_len) };
60    memory[offset..offset + len].copy_from_slice(data.as_ref());
61  }
62
63  fn sync_data_sync(&self) -> () {
64    self.mmap.flush().unwrap();
65  }
66}