Skip to main content

pagers_core/ops/
touch.rs

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}