Show More
@@ -446,6 +446,48 impl Revlog { | |||||
446 |
|
446 | |||
447 | type IndexData = Box<dyn Deref<Target = [u8]> + Send + Sync>; |
|
447 | type IndexData = Box<dyn Deref<Target = [u8]> + Send + Sync>; | |
448 |
|
448 | |||
|
449 | /// TODO We should check for version 5.14+ at runtime, but we either should | |||
|
450 | /// add the `nix` dependency to get it efficiently, or vendor the code to read | |||
|
451 | /// both of which are overkill for such a feature. If we need this dependency | |||
|
452 | /// for more things later, we'll use it here too. | |||
|
453 | #[cfg(target_os = "linux")] | |||
|
454 | fn can_advise_populate_read() -> bool { | |||
|
455 | true | |||
|
456 | } | |||
|
457 | ||||
|
458 | #[cfg(not(target_os = "linux"))] | |||
|
459 | fn can_advise_populate_read() -> bool { | |||
|
460 | false | |||
|
461 | } | |||
|
462 | ||||
|
463 | /// Call `madvise` on the mmap with `MADV_POPULATE_READ` in a separate thread | |||
|
464 | /// to populate the mmap in the background for a small perf improvement. | |||
|
465 | #[cfg(target_os = "linux")] | |||
|
466 | fn advise_populate_read_mmap(mmap: &memmap2::Mmap) { | |||
|
467 | const MADV_POPULATE_READ: i32 = 22; | |||
|
468 | ||||
|
469 | // This is fine because the mmap is still referenced for at least | |||
|
470 | // the duration of this function, and the kernel will reject any wrong | |||
|
471 | // address. | |||
|
472 | let ptr = mmap.as_ptr() as u64; | |||
|
473 | let len = mmap.len(); | |||
|
474 | ||||
|
475 | // Fire and forget. The `JoinHandle` returned by `spawn` is dropped right | |||
|
476 | // after the call, the thread is thus detached. We don't care about success | |||
|
477 | // or failure here. | |||
|
478 | std::thread::spawn(move || unsafe { | |||
|
479 | // mmap's pointer is always page-aligned on Linux. In the case of | |||
|
480 | // file-based mmap (which is our use-case), the length should be | |||
|
481 | // correct. If not, it's not a safety concern as the kernel will just | |||
|
482 | // ignore unmapped pages and return ENOMEM, which we will promptly | |||
|
483 | // ignore, because we don't care about any errors. | |||
|
484 | libc::madvise(ptr as *mut libc::c_void, len, MADV_POPULATE_READ); | |||
|
485 | }); | |||
|
486 | } | |||
|
487 | ||||
|
488 | #[cfg(not(target_os = "linux"))] | |||
|
489 | fn advise_populate_read_mmap(mmap: &memmap2::Mmap) {} | |||
|
490 | ||||
449 | /// Open the revlog [`Index`] at `index_path`, through the `store_vfs` and the |
|
491 | /// Open the revlog [`Index`] at `index_path`, through the `store_vfs` and the | |
450 | /// given `options`. This controls whether (and how) we `mmap` the index file, |
|
492 | /// given `options`. This controls whether (and how) we `mmap` the index file, | |
451 | /// and returns an empty buffer if the index does not exist on disk. |
|
493 | /// and returns an empty buffer if the index does not exist on disk. | |
@@ -465,8 +507,12 pub fn open_index( | |||||
465 | if size >= threshold { |
|
507 | if size >= threshold { | |
466 | // TODO madvise populate read in a background thread |
|
508 | // TODO madvise populate read in a background thread | |
467 | let mut mmap_options = MmapOptions::new(); |
|
509 | let mut mmap_options = MmapOptions::new(); | |
468 | // This does nothing on platforms where it's not defined |
|
510 | if !can_advise_populate_read() { | |
469 | mmap_options.populate(); |
|
511 | // Fall back to populating in the main thread if | |
|
512 | // post-creation advice is not supported. | |||
|
513 | // Does nothing on platforms where it's not defined. | |||
|
514 | mmap_options.populate(); | |||
|
515 | } | |||
470 | // Safety is "enforced" by locks and assuming other |
|
516 | // Safety is "enforced" by locks and assuming other | |
471 | // processes are well-behaved. If any misbehaving or |
|
517 | // processes are well-behaved. If any misbehaving or | |
472 | // malicious process does touch the index, it could lead |
|
518 | // malicious process does touch the index, it could lead | |
@@ -476,6 +522,11 pub fn open_index( | |||||
476 | // TODO linux: set the immutable flag with `chattr(1)`? |
|
522 | // TODO linux: set the immutable flag with `chattr(1)`? | |
477 | let mmap = unsafe { mmap_options.map(&file) } |
|
523 | let mmap = unsafe { mmap_options.map(&file) } | |
478 | .when_reading_file(index_path)?; |
|
524 | .when_reading_file(index_path)?; | |
|
525 | ||||
|
526 | if can_advise_populate_read() { | |||
|
527 | advise_populate_read_mmap(&mmap); | |||
|
528 | } | |||
|
529 | ||||
479 | Some(Box::new(mmap) as IndexData) |
|
530 | Some(Box::new(mmap) as IndexData) | |
480 | } else { |
|
531 | } else { | |
481 | None |
|
532 | None |
General Comments 0
You need to be logged in to leave comments.
Login now