Skip to content

Commit 920ef29

Browse files
committed
Use libc::mmap instead of memmap2
Change-Id: I16c7969d44f35d0086ef86c458c7131aa17b3078 Signed-off-by: kexuan.yang <kexuan.yang@gmail.com>
1 parent 8815cfe commit 920ef29

File tree

5 files changed

+104
-18
lines changed

5 files changed

+104
-18
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ exclude = [
1515

1616
[dependencies]
1717
protobuf = "3.3.0"
18-
memmap2 = "0.9.3"
18+
libc = "0.2.152"
1919
crc = "3.0.1"
2020
eax = { version = "0.5.0", features = ["stream"], optional = true }
2121
aes = { version = "0.8.3", optional = true }

src/core/iter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ mod tests {
110110
.open(file_name)
111111
.unwrap();
112112
file.set_len(1024).unwrap();
113-
let mut mm = MemoryMap::new(&file);
113+
let mut mm = MemoryMap::new(&file, 1024);
114114
let mut buffers: Vec<Buffer> = vec![];
115115
let test_encoder = &TestEncoderDecoder;
116116
for i in 0..10 {

src/core/memory_map.rs

Lines changed: 83 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,106 @@
11
use std::fs::File;
2-
use std::ops::Range;
3-
4-
use memmap2::{Advice, MmapMut};
2+
use std::ops::{Deref, DerefMut, Range};
3+
use std::os::fd::{AsRawFd, RawFd};
4+
use std::ptr::NonNull;
5+
use std::{io, ptr, slice};
56

67
pub const LEN_OFFSET: usize = 8;
78

9+
#[cfg(any(target_os = "linux", target_os = "android"))]
10+
const MAP_POPULATE: libc::c_int = libc::MAP_POPULATE;
11+
12+
#[cfg(not(any(target_os = "linux", target_os = "android")))]
13+
const MAP_POPULATE: libc::c_int = 0;
14+
15+
#[derive(Debug)]
16+
struct RawMmap {
17+
ptr: NonNull<libc::c_void>,
18+
len: usize,
19+
}
20+
21+
impl RawMmap {
22+
fn new(fd: RawFd, len: usize) -> io::Result<RawMmap> {
23+
unsafe {
24+
let ptr = libc::mmap(
25+
ptr::null_mut(),
26+
len as libc::size_t,
27+
libc::PROT_READ | libc::PROT_WRITE,
28+
libc::MAP_SHARED | MAP_POPULATE,
29+
fd,
30+
0,
31+
);
32+
if ptr == libc::MAP_FAILED {
33+
Err(io::Error::last_os_error())
34+
} else {
35+
libc::madvise(ptr, len, libc::MADV_WILLNEED);
36+
Ok(RawMmap {
37+
ptr: NonNull::new(ptr).unwrap(),
38+
len,
39+
})
40+
}
41+
}
42+
}
43+
44+
fn flush(&self, len: usize) -> io::Result<()> {
45+
let result = unsafe { libc::msync(self.ptr.as_ptr(), len as libc::size_t, libc::MS_SYNC) };
46+
if result == 0 {
47+
Ok(())
48+
} else {
49+
Err(io::Error::last_os_error())
50+
}
51+
}
52+
}
53+
54+
impl Drop for RawMmap {
55+
fn drop(&mut self) {
56+
unsafe {
57+
libc::munmap(self.ptr.as_ptr(), self.len as libc::size_t);
58+
}
59+
}
60+
}
61+
62+
impl Deref for RawMmap {
63+
type Target = [u8];
64+
#[inline]
65+
fn deref(&self) -> &[u8] {
66+
unsafe { slice::from_raw_parts(self.ptr.as_ptr() as *const u8, self.len) }
67+
}
68+
}
69+
70+
impl DerefMut for RawMmap {
71+
#[inline]
72+
fn deref_mut(&mut self) -> &mut [u8] {
73+
unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr() as *mut u8, self.len) }
74+
}
75+
}
76+
77+
unsafe impl Send for RawMmap {}
78+
unsafe impl Sync for RawMmap {}
79+
880
#[derive(Debug)]
9-
pub struct MemoryMap(MmapMut);
81+
pub struct MemoryMap(RawMmap);
1082

1183
impl MemoryMap {
12-
pub fn new(file: &File) -> Self {
13-
let raw_mmap = unsafe { MmapMut::map_mut(file) }.unwrap();
14-
raw_mmap.advise(Advice::WillNeed).unwrap();
84+
pub fn new(file: &File, len: usize) -> Self {
85+
let raw_mmap = RawMmap::new(file.as_raw_fd(), len).unwrap();
1586
MemoryMap(raw_mmap)
1687
}
1788

18-
pub fn append(&mut self, value: Vec<u8>) -> std::io::Result<()> {
89+
pub fn append(&mut self, value: Vec<u8>) -> io::Result<()> {
1990
let data_len = value.len();
2091
let start = self.len();
2192
let content_len = start - LEN_OFFSET;
2293
let end = data_len + start;
2394
let new_content_len = data_len + content_len;
2495
self.0[0..LEN_OFFSET].copy_from_slice(new_content_len.to_be_bytes().as_slice());
2596
self.0[start..end].copy_from_slice(value.as_slice());
26-
self.0.flush()
97+
self.0.flush(end)
2798
}
2899

29-
pub fn reset(&mut self) -> std::io::Result<()> {
100+
pub fn reset(&mut self) -> io::Result<()> {
30101
let len = 0usize;
31102
self.0[0..LEN_OFFSET].copy_from_slice(len.to_be_bytes().as_slice());
32-
self.0.flush()
103+
self.0.flush(LEN_OFFSET)
33104
}
34105

35106
pub fn len(&self) -> usize {
@@ -58,7 +129,7 @@ mod tests {
58129
.open("test_mmap")
59130
.unwrap();
60131
file.set_len(1024).unwrap();
61-
let mut mm = MemoryMap::new(&file);
132+
let mut mm = MemoryMap::new(&file, 1024);
62133
assert_eq!(mm.len(), 8);
63134
mm.append(vec![1, 2, 3]).unwrap();
64135
mm.append(vec![4]).unwrap();

src/core/mmkv_impl.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ impl IOWriter {
107107

108108
fn expand(&mut self) {
109109
self.config.expand();
110-
self.mm = MemoryMap::new(&self.config.file);
110+
self.mm = MemoryMap::new(&self.config.file, self.config.file_size() as usize);
111111
}
112112

113113
fn remove_file(&mut self) {
@@ -127,7 +127,7 @@ impl MmkvImpl {
127127
#[cfg(not(feature = "encryption"))]
128128
let encoder = Box::new(CrcEncoderDecoder);
129129
let mut kv_map = HashMap::new();
130-
let mm = MemoryMap::new(&config.file);
130+
let mm = MemoryMap::new(&config.file, config.file_size() as usize);
131131
#[cfg(feature = "encryption")]
132132
let decoder = encryptor.clone();
133133
#[cfg(not(feature = "encryption"))]

src/mmkv.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,25 @@ use crate::log::logger;
55
use crate::Error::InstanceClosed;
66
use crate::{LogLevel, Result};
77
use std::path::{Path, PathBuf};
8+
use std::sync::atomic::{AtomicUsize, Ordering};
89
use std::sync::RwLock;
910

1011
const DEFAULT_FILE_NAME: &str = "mini_mmkv";
11-
const PAGE_SIZE: u64 = 4 * 1024; // 4KB is the default Linux page size
12+
13+
fn page_size() -> usize {
14+
static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
15+
16+
match PAGE_SIZE.load(Ordering::Relaxed) {
17+
0 => {
18+
let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize };
19+
20+
PAGE_SIZE.store(page_size, Ordering::Relaxed);
21+
22+
page_size
23+
}
24+
page_size => page_size,
25+
}
26+
}
1227

1328
static MMKV_INSTANCE: RwLock<Option<MmkvImpl>> = RwLock::new(None);
1429

@@ -61,7 +76,7 @@ impl MMKV {
6176
let mut instance = MMKV_INSTANCE.write().unwrap();
6277
drop(instance.take());
6378
let file_path = MMKV::resolve_file_path(dir);
64-
let config = Config::new(file_path.as_path(), PAGE_SIZE);
79+
let config = Config::new(file_path.as_path(), page_size() as u64);
6580
*instance = Some(MmkvImpl::new(
6681
config,
6782
#[cfg(feature = "encryption")]

0 commit comments

Comments
 (0)