1use memmap2::Advice;
2
3use crate::mincore::PageMap;
4
5use super::{FileContext, Op};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub struct Touch;
10
11impl Op for Touch {
12 const LABEL: &str = "touched";
13 const ACTION_SIGN: isize = 1;
14 type Output = usize;
15
16 fn action_pages(
17 output: &usize,
18 _total_pages: usize,
19 _pages_in_core_before: Option<usize>,
20 _pages_in_core_after: usize,
21 ) -> usize {
22 *output
23 }
24
25 fn execute<PM: PageMap + Sync>(&self, ctx: &FileContext<'_, PM>) -> crate::Result<usize> {
26 let mmap = &ctx.mmap;
27 let len = ctx.len;
28
29 if len == 0 {
30 return Ok(0);
31 }
32
33 let page_size = *crate::pagesize::PAGE_SIZE;
34 let total_pages = len.div_ceil(page_size);
35
36 let needs_touch = |i: &usize| ctx.residency.is_none_or(|r| !r.is_set(*i));
37
38 let mut touched = 0usize;
39
40 if (0..total_pages).any(|i| needs_touch(&i)) {
41 const PROGRESS_INTERVAL: usize = 256;
42
43 std::thread::scope(|s| {
44 s.spawn(|| initiate_readahead(ctx));
45
46 for page_idx in (0..total_pages).filter(needs_touch) {
47 let offset = page_idx * page_size;
48 unsafe {
49 std::ptr::read_volatile(mmap.as_ptr().add(offset));
50 }
51 touched += 1;
52 if let Some(on_progress) = &ctx.on_progress
53 && (page_idx + 1) % PROGRESS_INTERVAL == 0
54 {
55 on_progress(page_idx + 1, touched);
56 }
57 }
58 });
59 }
60
61 Ok(touched)
62 }
63}
64
65fn initiate_readahead<PM: PageMap>(ctx: &FileContext<'_, PM>) {
66 let offset = ctx.offset as libc::off_t;
67 let len = ctx.len as libc::off_t;
68
69 #[cfg(target_os = "linux")]
70 {
71 use std::os::unix::io::AsFd;
72 let fd = ctx.file.as_fd();
73 let _ = nix::fcntl::posix_fadvise(
74 fd,
75 offset,
76 len,
77 nix::fcntl::PosixFadviseAdvice::POSIX_FADV_SEQUENTIAL,
78 );
79 let _ = nix::fcntl::posix_fadvise(
80 fd,
81 offset,
82 len,
83 nix::fcntl::PosixFadviseAdvice::POSIX_FADV_WILLNEED,
84 );
85 }
86
87 let _ = ctx
88 .mmap
89 .advise_range(Advice::WillNeed, offset as usize, len as usize);
90}