Skip to main content

hexz_store/local/
mmap.rs

1//! Memory-mapped file storage backend with zero-copy reads.
2//!
3//! `MmapBackend` maps the entire file into the process address space and returns
4//! `Bytes` slices backed by the mapping. Each `read_exact` call is O(1) — just
5//! an atomic refcount increment and pointer arithmetic, with no `memcpy`.
6
7use bytes::Bytes;
8use hexz_common::Result;
9use hexz_core::store::StorageBackend;
10use memmap2::Mmap;
11use std::fs::File;
12
13/// A read-only memory-mapped file backend with zero-copy reads.
14///
15/// Maps the entire file into the process address space with `MAP_PRIVATE | PROT_READ`.
16/// Reads return `Bytes` slices that reference the mapped region directly, avoiding
17/// any allocation or copy on the read path.
18#[derive(Debug)]
19pub struct MmapBackend {
20    bytes: Bytes,
21    len: u64,
22}
23
24impl MmapBackend {
25    /// Opens and maps `path` read-only. No I/O occurs until pages are accessed.
26    pub fn new(path: &std::path::Path) -> Result<Self> {
27        let file = File::open(path)?;
28        let len = file.metadata()?.len();
29        // SAFETY: The file is immutable for the lifetime of the mapping (archive semantics).
30        let map = unsafe { Mmap::map(&file)? };
31        let bytes = Bytes::from_owner(map);
32        Ok(Self { bytes, len })
33    }
34}
35
36impl StorageBackend for MmapBackend {
37    fn read_exact(&self, offset: u64, len: usize) -> Result<Bytes> {
38        let start = offset as usize;
39        let end = start + len;
40        if end > self.bytes.len() {
41            return Err(std::io::Error::new(
42                std::io::ErrorKind::UnexpectedEof,
43                "Read out of bounds",
44            )
45            .into());
46        }
47        Ok(self.bytes.slice(start..end))
48    }
49
50    fn len(&self) -> u64 {
51        self.len
52    }
53}