rust: populate mmap by default if available
See
522b4d729e89edc76544fa549ed36de4aea0b7fb for more details.
Background population to follow in a later patch.
--- a/rust/hg-core/src/revlog/mod.rs Wed Jun 19 18:20:22 2024 +0200
+++ b/rust/hg-core/src/revlog/mod.rs Thu Sep 26 13:55:26 2024 +0200
@@ -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 {
--- a/rust/hg-core/src/revlog/options.rs Wed Jun 19 18:20:22 2024 +0200
+++ b/rust/hg-core/src/revlog/options.rs Thu Sep 26 13:55:26 2024 +0200
@@ -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")?
{