Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 25e717e

Browse files
author
James Gober
committed
release: 0.9.8
1 parent 45609d0 commit 25e717e

10 files changed

Lines changed: 1099 additions & 42 deletions

File tree

CHANGELOG.md

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,91 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
<br>
1111

12+
<!-- VERSION: 0.9.8 -->
13+
## [0.9.8] - 2026-05-12
14+
15+
### Added
16+
17+
- **(E1, E6)** `MemoryMappedFile::open_or_create(path, default_size)`
18+
and `MemoryMappedFileBuilder::open_or_create()` for the
19+
open-if-present / create-if-absent pattern in one call.
20+
- **(F9)** `MemoryMappedFile::from_file(file, mode, path)` to wrap a
21+
pre-opened `std::fs::File` (e.g. one opened with custom
22+
`OpenOptions` flags like `O_DIRECT` / `O_NOATIME` or inherited
23+
from a parent process).
24+
- **(F5)** `MemoryMappedFile::unmap(self) -> Result<File, Self>`
25+
consumes the mapping, drops the underlying mapping + background
26+
flusher in safe order, and returns the underlying `File`. Returns
27+
`Err(self)` unchanged if other clones of the mapping are alive.
28+
- **(E7)** `flush_policy()` returns the configured `FlushPolicy`;
29+
`pending_bytes()` returns the live `EveryBytes` / `EveryWrites`
30+
accumulator value. Both are `#[inline]` and `O(1)`; useful for
31+
diagnostics and observability dashboards.
32+
- **(E2)** `unsafe fn as_ptr(&self) -> *const u8` and `unsafe fn
33+
as_mut_ptr(&self) -> Result<*mut u8>` expose raw base pointers
34+
to the mapping for FFI / advanced use. Full safety contract in
35+
the rustdoc.
36+
- **(F2)** `prefetch_range(offset, len)` issues
37+
`posix_fadvise(POSIX_FADV_WILLNEED)` on the file descriptor on
38+
Linux (warms the page cache from the file side, complementary to
39+
`advise(MmapAdvice::WillNeed)` which warms via `madvise` on the
40+
VM side). No-op fallback on non-Linux. Bounds-checked.
41+
- `tests/ergonomic_api.rs` (17 tests) covers every new method:
42+
open_or_create both paths, builder open_or_create, from_file
43+
RO/RW/zero-length, unmap unique/shared, flush_policy /
44+
pending_bytes, as_ptr / as_mut_ptr roundtrips, prefetch_range
45+
in-bounds / OOB / zero-length.
46+
47+
### Fixed
48+
49+
- **`flush::TimeBasedFlusher`** thread loop used `interval -
50+
elapsed` directly. If `thread::sleep` overshot under heavy
51+
scheduler contention `elapsed` could exceed `interval` and the
52+
subtraction would panic on Duration underflow. Switched to
53+
`interval.saturating_sub(elapsed)` so the next slice clamps to
54+
zero (immediate retry) instead of panicking.
55+
56+
### Performance
57+
58+
- **Bounds-check helpers `#[inline]`-ed.** `ensure_in_bounds` and
59+
`slice_range` are called from every bounds-checked public method
60+
(`as_slice`, `as_slice_mut`, `read_into`, `update_region`,
61+
`flush_range`, `touch_pages_range`, `prefetch_range`, advise,
62+
lock, segment access). Inlining removes a call/return boundary
63+
on every read/write. Also merged the two-branch bounds check
64+
into a single `saturating_add` comparison.
65+
- **`len()` / `is_empty()` / `mode()` / `flush_policy()` /
66+
`pending_bytes()` marked `#[inline]`**: trivial accessors that
67+
the optimiser should fold into the call site every time.
68+
69+
### Documentation
70+
71+
- `docs/API.md`: full sections for all eight new methods, TOC
72+
updated, version snippets bumped to 0.9.8, Version History
73+
entry added.
74+
- `REPS.md` section 4: new ergonomic methods + builder addition
75+
listed with `// Since 0.9.8` markers.
76+
- `Cargo.toml` SEO: description leads with the unique selling
77+
point (zero-copy), names the supported platforms, and lists use
78+
cases concretely; keywords tightened to the highest-volume
79+
search terms (`mmap`, `memory-mapped`, `zero-copy`, `filesystem`,
80+
`io`); categories include `concurrency`.
81+
- `README.md`: opening hook rewritten around the actual
82+
differentiators (zero-copy on every mode, zero-allocation
83+
iteration, lock-free atomic views, configurable durability).
84+
85+
### Notes
86+
87+
- No new runtime dependencies. The Linux `posix_fadvise` path uses
88+
the already-required `libc` crate.
89+
- MSRV unchanged at Rust 1.75.
90+
- **F1** (anonymous shared-memory mapping) remains open. The
91+
refactor (Inner.file: `Option<File>`, sentinel path handling,
92+
per-method "anonymous-aware" branches) is sized for a focused
93+
pass rather than rolled into this ergonomic milestone.
94+
95+
<br>
96+
1297
<!-- VERSION: 0.9.7 -->
1398
## [0.9.7] - 2026-05-12
1499

@@ -500,7 +585,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
500585
- Basic README.
501586

502587
<!-- LINK REFERENCE -->
503-
[Unreleased]: https://github.com/jamesgober/mmap-io/compare/v0.9.7...HEAD
588+
[Unreleased]: https://github.com/jamesgober/mmap-io/compare/v0.9.8...HEAD
589+
[0.9.8]: https://github.com/jamesgober/mmap-io/compare/v0.9.7...v0.9.8
504590
[0.9.7]: https://github.com/jamesgober/mmap-io/compare/v0.9.6...v0.9.7
505591
[0.9.6]: https://github.com/jamesgober/mmap-io/compare/v0.9.5...v0.9.6
506592
[0.9.5]: https://github.com/jamesgober/mmap-io/compare/v0.9.4...v0.9.5

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
[package]
22
name = "mmap-io"
3-
version = "0.9.7"
3+
version = "0.9.8"
44
edition = "2021"
55
rust-version = "1.75"
66
readme = "README.md"
77
license = "Apache-2.0"
88
publish = true
9-
description = "High-performance, async-ready memory-mapped file I/O library for Rust. Supports fast segment-based loading, updates, and persistence. Designed for database engines, game runtimes, and real-time applications."
9+
description = "Zero-copy memory-mapped file I/O for Rust. Safe concurrent reads, writes, and atomic views across Linux, macOS, and Windows. Built for databases, log structures, game runtimes, caches, and IPC."
1010
keywords = [
11-
"mmap",
12-
"memory-mapped",
13-
"file-io",
14-
"async",
15-
"database"
11+
"mmap",
12+
"memory-mapped",
13+
"zero-copy",
14+
"filesystem",
15+
"io"
1616
]
1717
categories = [
18-
"filesystem",
19-
"data-structures",
20-
"asynchronous",
18+
"filesystem",
19+
"data-structures",
20+
"concurrency",
2121
"database-implementations"
2222
]
2323
homepage = "https://github.com/jamesgober/mmap-io"

README.md

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,22 @@
1515
</p>
1616

1717
<p align="center">
18-
Zero-copy reads. Efficient writes. Safe concurrent access.<br>
19-
Built for databases, game runtimes, caches, and real-time applications.
18+
Zero-copy reads. Lock-free atomic views. Safe concurrent access.<br>
19+
Built for databases, log structures, caches, game runtimes, and shared-memory IPC.
2020
</p>
2121

2222
---
2323

24-
## Capabilities
24+
## What you get
2525

26-
- **Zero-copy reads** and efficient writes.
27-
- **Read-only**, **read-write**, and **copy-on-write** modes.
28-
- **Segment-based access** (offset + length).
29-
- **Thread-safe** via interior mutability (parking_lot `RwLock`).
30-
- **Cross-platform** via `memmap2`.
31-
- Optional **async** helpers with Tokio.
32-
- **Configurable flush policies** with smart microflush optimization.
33-
- **Page prewarming** for predictable benchmark timing.
34-
- **Huge pages support** (best-effort, Linux/Windows).
35-
- **MSRV: 1.75**.
26+
- **Zero-copy reads on every mode.** `as_slice` returns a `MappedSlice<'_>` borrowed directly from the mapping. No allocation. No memcpy. Works on read-only, read-write, and copy-on-write mappings uniformly.
27+
- **Zero-allocation iteration.** `mmap.chunks(N)` and `mmap.pages()` walk the file in fixed strides without ever heap-allocating. A 1 GiB scan at 4 KiB chunks skips 262,144 allocations and half the memory bandwidth of the naive approach.
28+
- **Aligned atomic views.** `atomic_u32` / `atomic_u64` return a wrapper that derefs to `&AtomicU64`. Multi-thread `fetch_add` over a memory-mapped counter is one cache-line ping; no cross-process locking required.
29+
- **Configurable durability.** `FlushPolicy::EveryBytes(N)`, `EveryWrites(N)`, `EveryMillis(N)`, `Always`, or `Manual`. The accumulator is correctly debited on partial flushes (audit C1) and the millis policy actually runs a background flusher (audit C2).
30+
- **Thread-safe.** Interior mutability via `parking_lot::RwLock`. Multiple concurrent readers, one writer at a time. Live atomic views block `resize()` until released so memory under your reference cannot move (audit C3).
31+
- **Cross-platform.** Linux, macOS, Windows. Per-platform fast paths (`MS_ASYNC` flush on Linux, `MADV_HUGEPAGE` on huge-page hints, `posix_fadvise` for OS-level prefetch).
32+
- **Opt-in surface.** Default features are `advise` + `iterator`. Everything else (`async`, `atomic`, `cow`, `locking`, `watch`, `hugepages`) is off by default to keep compile time tight.
33+
- **MSRV: 1.75.** Pinned and verified in CI.
3634

3735
## Quick start
3836

@@ -45,26 +43,28 @@ mmap-io = "0.9"
4543
use mmap_io::MemoryMappedFile;
4644

4745
fn main() -> Result<(), mmap_io::MmapIoError> {
48-
// Open an existing file in read-only mode
46+
// Open an existing file in read-only mode.
4947
let mmap = MemoryMappedFile::open_ro("data.bin")?;
5048

51-
// Zero-copy read of the first 16 bytes
49+
// Zero-copy read of the first 16 bytes. `slice` derefs to &[u8].
5250
let slice = mmap.as_slice(0, 16)?;
53-
println!("First bytes: {slice:?}");
51+
println!("First bytes: {:?}", &*slice);
5452

5553
Ok(())
5654
}
5755
```
5856

59-
Or write a fresh file:
57+
Open-or-create with one call:
6058

6159
```rust
62-
use mmap_io::{create_mmap, update_region, flush};
60+
use mmap_io::MemoryMappedFile;
6361

6462
fn main() -> Result<(), mmap_io::MmapIoError> {
65-
let mmap = create_mmap("data.bin", 1024 * 1024)?;
66-
update_region(&mmap, 100, b"Hello, mmap!")?;
67-
flush(&mmap)?;
63+
// Opens "data.bin" if it exists; creates it at 1 MiB otherwise.
64+
let mmap = MemoryMappedFile::open_or_create("data.bin", 1024 * 1024)?;
65+
66+
mmap.update_region(100, b"Hello, mmap!")?;
67+
mmap.flush()?;
6868
Ok(())
6969
}
7070
```

REPS.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,11 @@ impl MemoryMappedFile {
8888
pub fn create_rw<P: AsRef<Path>>(path: P, size: u64) -> Result<Self>;
8989
pub fn open_ro<P: AsRef<Path>>(path: P) -> Result<Self>;
9090
pub fn open_rw<P: AsRef<Path>>(path: P) -> Result<Self>;
91-
// Since 0.9.7: works uniformly on RO, COW, AND RW.
91+
// Since 0.9.8: ergonomic constructors and teardown.
92+
pub fn open_or_create<P: AsRef<Path>>(path: P, default_size: u64) -> Result<Self>;
93+
pub fn from_file<P: AsRef<Path>>(file: File, mode: MmapMode, path: P) -> Result<Self>;
94+
pub fn unmap(self) -> std::result::Result<File, Self>;
95+
// Since 0.9.7: as_slice works uniformly on RO, COW, AND RW.
9296
pub fn as_slice(&self, offset: u64, len: u64) -> Result<MappedSlice<'_>>;
9397
pub fn as_slice_mut(&self, offset: u64, len: u64) -> Result<MappedSliceMut<'_>>;
9498
pub fn read_into(&self, offset: u64, dst: &mut [u8]) -> Result<()>;
@@ -102,6 +106,21 @@ impl MemoryMappedFile {
102106
pub fn is_empty(&self) -> bool;
103107
pub fn path(&self) -> &Path;
104108
pub fn mode(&self) -> MmapMode;
109+
// Since 0.9.8: introspection accessors.
110+
pub fn flush_policy(&self) -> FlushPolicy;
111+
pub fn pending_bytes(&self) -> u64;
112+
// Since 0.9.8: FFI escape hatches.
113+
pub unsafe fn as_ptr(&self) -> *const u8;
114+
pub unsafe fn as_mut_ptr(&self) -> Result<*mut u8>;
115+
// Since 0.9.8: kernel-side prefetch hint (posix_fadvise on
116+
// Linux; no-op elsewhere). Complementary to MmapAdvice::WillNeed
117+
// (which is a VM-side hint via madvise).
118+
pub fn prefetch_range(&self, offset: u64, len: u64) -> Result<()>;
119+
}
120+
121+
// Builder additions since 0.9.8:
122+
impl MemoryMappedFileBuilder {
123+
pub fn open_or_create(self) -> Result<MemoryMappedFile>;
105124
}
106125

107126
// manager (high-level)

0 commit comments

Comments
 (0)