rust: populate mmap by default if available
authorRaphaël Gomès <rgomes@octobus.net>
Thu, 26 Sep 2024 13:55:26 +0200
changeset 52169 84b5802ba7d3
parent 52168 6b7ffa3f9199
child 52170 1a8466fd904a
rust: populate mmap by default if available See 522b4d729e89edc76544fa549ed36de4aea0b7fb for more details. Background population to follow in a later patch.
rust/hg-core/src/revlog/mod.rs
rust/hg-core/src/revlog/options.rs
--- 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")?
         {