diff --git a/rust/hg-core/src/revlog/mod.rs b/rust/hg-core/src/revlog/mod.rs index 6b7ffa3f9199fab91e57d2f6425d2a28f45b4682_cnVzdC9oZy1jb3JlL3NyYy9yZXZsb2cvbW9kLnJz..84b5802ba7d3927e8beb1a3e0d275e41806417e9_cnVzdC9oZy1jb3JlL3NyYy9yZXZsb2cvbW9kLnJz 100644 --- a/rust/hg-core/src/revlog/mod.rs +++ b/rust/hg-core/src/revlog/mod.rs @@ -503,6 +503,10 @@ { let size = store_vfs.file_size(&file)?; if size >= threshold { + // TODO madvise populate read in a background thread + let mut mmap_options = MmapOptions::new(); + // This does nothing on platforms where it's not defined + mmap_options.populate(); // Safety is "enforced" by locks and assuming other // processes are well-behaved. If any misbehaving or // malicious process does touch the index, it could lead @@ -510,7 +514,7 @@ // `mmap`, though some platforms have some ways of // mitigating. // TODO linux: set the immutable flag with `chattr(1)`? - let mmap = unsafe { MmapOptions::new().map(&file) } + let mmap = unsafe { mmap_options.map(&file) } .when_reading_file(index_path)?; Some(Box::new(mmap) as IndexData) } else { diff --git a/rust/hg-core/src/revlog/options.rs b/rust/hg-core/src/revlog/options.rs index 6b7ffa3f9199fab91e57d2f6425d2a28f45b4682_cnVzdC9oZy1jb3JlL3NyYy9yZXZsb2cvb3B0aW9ucy5ycw==..84b5802ba7d3927e8beb1a3e0d275e41806417e9_cnVzdC9oZy1jb3JlL3NyYy9yZXZsb2cvb3B0aW9ucy5ycw== 100644 --- a/rust/hg-core/src/revlog/options.rs +++ b/rust/hg-core/src/revlog/options.rs @@ -103,6 +103,20 @@ } } +/// Technically only Linux 2.5.46+ has `MAP_POPULATE` and only `2.6.23` on +/// private mappings, but if you're using such ancient Linux, you have other +/// problems. +#[cfg(target_os = "linux")] +const fn can_populate_mmap() -> bool { + true +} + +/// There is a of populating mmaps for Windows, but it would need testing. +#[cfg(not(target_os = "linux"))] +const fn can_populate_mmap() { + false +} + #[derive(Debug, Clone, Copy, PartialEq)] /// Holds configuration values about how the revlog data is read pub struct RevlogDataConfig { @@ -155,6 +169,20 @@ } } + // Use mmap if requested, or by default if we can fully populate it + let mmap_index = config + .get_option_no_default(b"storage", b"revlog.mmap.index")? + .unwrap_or(can_populate_mmap()); + if mmap_index { + if let Some(mmap_index_threshold) = config.get_byte_size( + b"storage", + b"revlog.mmap.index:size-threshold", + )? { + // Only mmap if above the requested size threshold + data_config.mmap_index_threshold = Some(mmap_index_threshold); + } + } + if let Some(mmap_index_threshold) = config .get_byte_size(b"storage", b"revlog.mmap.index:size-threshold")? {