pub struct MemoryMappedFile { /* private fields */ }
Expand description
Memory-mapped file with safe, zero-copy region access.
This is the core type for memory-mapped file operations. It provides:
- Safe concurrent access through interior mutability
- Zero-copy reads and writes
- Automatic bounds checking
- Cross-platform compatibility
§Examples
use mmap_io::{MemoryMappedFile, MmapMode};
// Create a new 1KB file
let mmap = MemoryMappedFile::create_rw("data.bin", 1024)?;
// Write some data
mmap.update_region(0, b"Hello, world!")?;
mmap.flush()?;
// Open existing file read-only
let ro_mmap = MemoryMappedFile::open_ro("data.bin")?;
let data = ro_mmap.as_slice(0, 13)?;
assert_eq!(data, b"Hello, world!");
Cloning this struct is cheap; it clones an Arc to the inner state.
For read-write mappings, interior mutability is protected with an RwLock
.
Implementations§
Source§impl MemoryMappedFile
impl MemoryMappedFile
Sourcepub fn builder<P: AsRef<Path>>(path: P) -> MemoryMappedFileBuilder
pub fn builder<P: AsRef<Path>>(path: P) -> MemoryMappedFileBuilder
Builder for constructing a MemoryMappedFile with custom options.
Example:
// let mmap = MemoryMappedFile::builder("file.bin")
// .mode(MmapMode::ReadWrite)
// .size(1_000_000)
// .flush_policy(FlushPolicy::EveryBytes(1_000_000))
// .create().unwrap();
Sourcepub fn create_rw<P: AsRef<Path>>(path: P, size: u64) -> Result<Self>
pub fn create_rw<P: AsRef<Path>>(path: P, size: u64) -> Result<Self>
Create a new file (truncating if exists) and memory-map it in read-write mode with the given size.
§Performance
- Time Complexity: O(1) for mapping creation
- Memory Usage: Virtual address space of
size
bytes (physical memory allocated on demand) - I/O Operations: One file creation, one truncate, one mmap syscall
§Errors
Returns MmapIoError::ResizeFailed
if size is zero or exceeds the maximum safe limit.
Returns MmapIoError::Io
if file creation or mapping fails.
Sourcepub fn open_ro<P: AsRef<Path>>(path: P) -> Result<Self>
pub fn open_ro<P: AsRef<Path>>(path: P) -> Result<Self>
Open an existing file and memory-map it read-only.
§Errors
Returns MmapIoError::Io
if file opening or mapping fails.
Sourcepub fn open_rw<P: AsRef<Path>>(path: P) -> Result<Self>
pub fn open_rw<P: AsRef<Path>>(path: P) -> Result<Self>
Open an existing file and memory-map it read-write.
§Errors
Returns MmapIoError::ResizeFailed
if file is zero-length.
Returns MmapIoError::Io
if file opening or mapping fails.
Sourcepub fn as_slice(&self, offset: u64, len: u64) -> Result<&[u8]>
pub fn as_slice(&self, offset: u64, len: u64) -> Result<&[u8]>
Get a zero-copy read-only slice for the given [offset, offset+len).
For RW mappings, cannot return a reference bound to a temporary guard; use read_into
instead.
§Performance
- Time Complexity: O(1) - direct pointer access
- Memory Usage: No additional allocation (zero-copy)
- Cache Behavior: May trigger page faults on first access
§Errors
Returns MmapIoError::OutOfBounds
if range exceeds file bounds.
Returns MmapIoError::InvalidMode
for RW mappings (use read_into
instead).
Sourcepub fn as_slice_mut(&self, offset: u64, len: u64) -> Result<MappedSliceMut<'_>>
pub fn as_slice_mut(&self, offset: u64, len: u64) -> Result<MappedSliceMut<'_>>
Get a zero-copy mutable slice for the given [offset, offset+len).
Only available in ReadWrite
mode.
§Errors
Returns MmapIoError::InvalidMode
if not in ReadWrite
mode.
Returns MmapIoError::OutOfBounds
if range exceeds file bounds.
Sourcepub fn update_region(&self, offset: u64, data: &[u8]) -> Result<()>
pub fn update_region(&self, offset: u64, data: &[u8]) -> Result<()>
Copy the provided bytes into the mapped file at the given offset. Bounds-checked, zero-copy write.
§Performance
- Time Complexity: O(n) where n is data.len()
- Memory Usage: No additional allocation
- I/O Operations: May trigger flush based on flush policy
§Errors
Returns MmapIoError::InvalidMode
if not in ReadWrite
mode.
Returns MmapIoError::OutOfBounds
if range exceeds file bounds.
Sourcepub async fn update_region_async(&self, offset: u64, data: &[u8]) -> Result<()>
pub async fn update_region_async(&self, offset: u64, data: &[u8]) -> Result<()>
Async write that enforces Async-Only Flushing semantics: always flush after write. Uses spawn_blocking to avoid blocking the async scheduler.
Sourcepub fn flush(&self) -> Result<()>
pub fn flush(&self) -> Result<()>
Flush changes to disk. For read-only mappings, this is a no-op.
Smart internal guards:
- Skip I/O when there are no pending writes (accumulator is zero)
- On Linux, use msync(MS_ASYNC) as a cheaper hint; fall back to full flush on error
§Performance
- Time Complexity: O(n) where n is the size of dirty pages
- I/O Operations: Triggers disk write of modified pages
- Optimization: Skips flush if no writes since last flush
- Platform: Linux uses async msync for better performance
§Errors
Returns MmapIoError::FlushFailed
if flush operation fails.
Sourcepub async fn flush_async(&self) -> Result<()>
pub async fn flush_async(&self) -> Result<()>
Async flush changes to disk. For read-only or COW mappings, this is a no-op. This method enforces “async-only flushing” semantics for async paths.
Sourcepub async fn flush_range_async(&self, offset: u64, len: u64) -> Result<()>
pub async fn flush_range_async(&self, offset: u64, len: u64) -> Result<()>
Async flush a specific byte range to disk.
Sourcepub fn flush_range(&self, offset: u64, len: u64) -> Result<()>
pub fn flush_range(&self, offset: u64, len: u64) -> Result<()>
Flush a specific byte range to disk.
Smart internal guards:
- Skip I/O when there are no pending writes in accumulator
- Optimize microflushes (< page size) with page-aligned batching
- On Linux, prefer msync(MS_ASYNC) for the range; fall back to full range flush on error
§Performance Optimizations
- Microflush Detection: Ranges smaller than page size are batched
- Page Alignment: Small ranges are expanded to page boundaries
- Async Hints: Linux uses MS_ASYNC for better performance
- Zero-Copy: No data copying during flush operations
§Errors
Returns MmapIoError::OutOfBounds
if range exceeds file bounds.
Returns MmapIoError::FlushFailed
if flush operation fails.
Sourcepub fn resize(&self, new_size: u64) -> Result<()>
pub fn resize(&self, new_size: u64) -> Result<()>
Resize (grow or shrink) the mapped file (RW only). This remaps the file internally.
§Performance
- Time Complexity: O(1) for the remap operation
- Memory Usage: Allocates new virtual address space of
new_size
- I/O Operations: File truncate/extend + new mmap syscall
- Note: Existing pointers/slices become invalid after resize
§Errors
Returns MmapIoError::InvalidMode
if not in ReadWrite
mode.
Returns MmapIoError::ResizeFailed
if new size is zero or exceeds the maximum safe limit.
Returns MmapIoError::Io
if resize operation fails.
Sourcepub fn touch_pages(&self) -> Result<()>
pub fn touch_pages(&self) -> Result<()>
Touch (prewarm) pages by reading the first byte of each page. This forces the OS to load all pages into physical memory, eliminating page faults during subsequent access. Useful for benchmarking and performance-critical sections.
§Performance
- Time Complexity: O(n) where n is the number of pages
- Memory Usage: Forces all pages into physical memory
- I/O Operations: May trigger disk reads for unmapped pages
- Cache Behavior: Optimizes subsequent access patterns
§Examples
use mmap_io::MemoryMappedFile;
let mmap = MemoryMappedFile::open_ro("data.bin")?;
// Prewarm all pages before performance-critical section
mmap.touch_pages()?;
// Now all subsequent accesses will be fast (no page faults)
let data = mmap.as_slice(0, 1024)?;
§Errors
Returns MmapIoError::Io
if memory access fails.
Sourcepub fn touch_pages_range(&self, offset: u64, len: u64) -> Result<()>
pub fn touch_pages_range(&self, offset: u64, len: u64) -> Result<()>
Touch (prewarm) a specific range of pages.
Similar to touch_pages()
but only affects the specified range.
§Arguments
offset
- Starting offset in byteslen
- Length of range to touch in bytes
§Errors
Returns MmapIoError::OutOfBounds
if range exceeds file bounds.
Returns MmapIoError::Io
if memory access fails.
Source§impl MemoryMappedFile
impl MemoryMappedFile
Sourcepub fn current_len(&self) -> Result<u64>
pub fn current_len(&self) -> Result<u64>
Return the up-to-date file length (cached). This ensures length remains correct even after resize.
§Errors
Returns MmapIoError::Io
if metadata query fails (not expected in current implementation).
Sourcepub fn read_into(&self, offset: u64, buf: &mut [u8]) -> Result<()>
pub fn read_into(&self, offset: u64, buf: &mut [u8]) -> Result<()>
Read bytes from the mapping into the provided buffer starting at offset
.
Length is buf.len()
; performs bounds checks.
§Performance
- Time Complexity: O(n) where n is buf.len()
- Memory Usage: Uses provided buffer, no additional allocation
- Cache Behavior: Sequential access pattern is cache-friendly
§Errors
Returns MmapIoError::OutOfBounds
if range exceeds file bounds.
Source§impl MemoryMappedFile
impl MemoryMappedFile
Sourcepub fn advise(&self, offset: u64, len: u64, advice: MmapAdvice) -> Result<()>
pub fn advise(&self, offset: u64, len: u64, advice: MmapAdvice) -> Result<()>
Advise the OS about expected access patterns for a memory range.
This can help the OS optimize memory management, prefetching, and caching. The advice is a hint and may be ignored by the OS.
§Platform-specific behavior
- Unix: Uses
madvise
system call - Windows: Uses
PrefetchVirtualMemory
forWillNeed
, no-op for others
§Errors
Returns MmapIoError::OutOfBounds
if the range exceeds file bounds.
Returns MmapIoError::AdviceFailed
if the system call fails.
Source§impl MemoryMappedFile
impl MemoryMappedFile
Sourcepub fn chunks(&self, chunk_size: usize) -> ChunkIterator<'_> ⓘ
pub fn chunks(&self, chunk_size: usize) -> ChunkIterator<'_> ⓘ
Create an iterator over fixed-size chunks of the file.
For read-only and copy-on-write mappings, this returns immutable slices.
For read-write mappings, use chunks_mut()
for mutable access.
§Arguments
chunk_size
- Size of each chunk in bytes
§Examples
use mmap_io::MemoryMappedFile;
let mmap = MemoryMappedFile::open_ro("data.bin")?;
// Process file in 1MB chunks
for chunk in mmap.chunks(1024 * 1024) {
let data = chunk?;
// Process chunk...
}
Sourcepub fn pages(&self) -> PageIterator<'_> ⓘ
pub fn pages(&self) -> PageIterator<'_> ⓘ
Create an iterator over page-aligned chunks of the file.
Pages are aligned to the system’s page size, which is typically 4KB on most systems. This can provide better performance for certain access patterns.
§Examples
use mmap_io::MemoryMappedFile;
let mmap = MemoryMappedFile::open_ro("data.bin")?;
// Process file page by page
for page in mmap.pages() {
let data = page?;
// Process page...
}
Sourcepub fn chunks_mut(&self, chunk_size: usize) -> ChunkIteratorMut<'_>
pub fn chunks_mut(&self, chunk_size: usize) -> ChunkIteratorMut<'_>
Create a mutable iterator over fixed-size chunks of the file.
This is only available for read-write mappings. Due to Rust’s borrowing rules, this returns an iterator that processes chunks through a callback.
§Arguments
chunk_size
- Size of each chunk in bytes
§Examples
use mmap_io::{MemoryMappedFile, MmapMode};
let mmap = MemoryMappedFile::open_rw("data.bin")?;
// Zero out file in 4KB chunks
mmap.chunks_mut(4096).for_each_mut(|offset, chunk| {
chunk.fill(0);
Ok::<(), std::io::Error>(())
})??;
Source§impl MemoryMappedFile
impl MemoryMappedFile
Sourcepub fn lock(&self, offset: u64, len: u64) -> Result<()>
pub fn lock(&self, offset: u64, len: u64) -> Result<()>
Lock memory pages to prevent them from being swapped to disk.
This operation requires appropriate permissions (typically root/admin). Locked pages count against system limits.
§Platform-specific behavior
- Unix: Uses
mlock
system call - Windows: Uses
VirtualLock
§Errors
Returns MmapIoError::OutOfBounds
if the range exceeds file bounds.
Returns MmapIoError::LockFailed
if the lock operation fails (often due to permissions).
Sourcepub fn unlock(&self, offset: u64, len: u64) -> Result<()>
pub fn unlock(&self, offset: u64, len: u64) -> Result<()>
Unlock previously locked memory pages.
This allows the pages to be swapped out again if needed.
§Platform-specific behavior
- Unix: Uses
munlock
system call - Windows: Uses
VirtualUnlock
§Errors
Returns MmapIoError::OutOfBounds
if the range exceeds file bounds.
Returns MmapIoError::UnlockFailed
if the unlock operation fails.
Sourcepub fn lock_all(&self) -> Result<()>
pub fn lock_all(&self) -> Result<()>
Lock all pages of the memory-mapped file.
Convenience method that locks the entire file.
§Errors
Returns MmapIoError::LockFailed
if the lock operation fails.
Sourcepub fn unlock_all(&self) -> Result<()>
pub fn unlock_all(&self) -> Result<()>
Unlock all pages of the memory-mapped file.
Convenience method that unlocks the entire file.
§Errors
Returns MmapIoError::UnlockFailed
if the unlock operation fails.
Source§impl MemoryMappedFile
impl MemoryMappedFile
Sourcepub fn atomic_u64(&self, offset: u64) -> Result<&AtomicU64>
pub fn atomic_u64(&self, offset: u64) -> Result<&AtomicU64>
Get an atomic view of a u64 value at the specified offset.
The offset must be properly aligned for atomic operations (8-byte alignment for u64). This allows lock-free concurrent access to the value.
§Safety
The returned reference is valid for the lifetime of the memory mapping. The caller must ensure that the memory at this offset is not concurrently modified through non-atomic operations.
§Errors
Returns MmapIoError::Misaligned
if the offset is not 8-byte aligned.
Returns MmapIoError::OutOfBounds
if the offset + 8 exceeds file bounds.
Sourcepub fn atomic_u32(&self, offset: u64) -> Result<&AtomicU32>
pub fn atomic_u32(&self, offset: u64) -> Result<&AtomicU32>
Get an atomic view of a u32 value at the specified offset.
The offset must be properly aligned for atomic operations (4-byte alignment for u32). This allows lock-free concurrent access to the value.
§Safety
The returned reference is valid for the lifetime of the memory mapping. The caller must ensure that the memory at this offset is not concurrently modified through non-atomic operations.
§Errors
Returns MmapIoError::Misaligned
if the offset is not 4-byte aligned.
Returns MmapIoError::OutOfBounds
if the offset + 4 exceeds file bounds.
Sourcepub fn atomic_u64_slice(
&self,
offset: u64,
count: usize,
) -> Result<&[AtomicU64]>
pub fn atomic_u64_slice( &self, offset: u64, count: usize, ) -> Result<&[AtomicU64]>
Get multiple atomic u64 views starting at the specified offset.
Returns a slice of atomic values. All values must be within bounds and the offset must be 8-byte aligned.
§Errors
Returns MmapIoError::Misaligned
if the offset is not 8-byte aligned.
Returns MmapIoError::OutOfBounds
if the range exceeds file bounds.
Sourcepub fn atomic_u32_slice(
&self,
offset: u64,
count: usize,
) -> Result<&[AtomicU32]>
pub fn atomic_u32_slice( &self, offset: u64, count: usize, ) -> Result<&[AtomicU32]>
Get multiple atomic u32 views starting at the specified offset.
Returns a slice of atomic values. All values must be within bounds and the offset must be 4-byte aligned.
§Errors
Returns MmapIoError::Misaligned
if the offset is not 4-byte aligned.
Returns MmapIoError::OutOfBounds
if the range exceeds file bounds.
Source§impl MemoryMappedFile
impl MemoryMappedFile
Sourcepub fn watch<F>(&self, callback: F) -> Result<WatchHandle>
pub fn watch<F>(&self, callback: F) -> Result<WatchHandle>
Watch for changes to the mapped file.
The callback will be invoked whenever changes are detected. Returns a handle that stops watching when dropped.
§Platform-specific behavior
- Linux: Uses inotify for efficient monitoring
- macOS: Uses FSEvents or kqueue
- Windows: Uses ReadDirectoryChangesW
- Fallback: Polling-based implementation
§Examples
use mmap_io::{MemoryMappedFile, watch::ChangeEvent};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
let mmap = MemoryMappedFile::open_ro("data.bin")?;
let changed = Arc::new(AtomicBool::new(false));
let changed_clone = Arc::clone(&changed);
let handle = mmap.watch(move |event: ChangeEvent| {
println!("File changed: {:?}", event);
changed_clone.store(true, Ordering::SeqCst);
})?;
// File is being watched...
// Handle is dropped when out of scope, stopping the watch
Trait Implementations§
Source§impl Clone for MemoryMappedFile
impl Clone for MemoryMappedFile
Source§fn clone(&self) -> MemoryMappedFile
fn clone(&self) -> MemoryMappedFile
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read more