Skip to main content

pagers_core/ops/
touch.rs

1use memmap2::Advice;
2
3use crate::mincore::PageMap;
4
5use super::{FileContext, Op, ResidencyEffect};
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 EFFECT: ResidencyEffect = ResidencyEffect::Populate;
14    type Output = usize;
15
16    fn execute<PM: PageMap + Sync>(&self, ctx: &FileContext<'_, PM>) -> crate::Result<usize> {
17        let mmap = ctx.mmap();
18        let len = ctx.len();
19        ctx.check_cancelled()?;
20
21        if len == 0 {
22            return Ok(0);
23        }
24
25        let page_size = *crate::pagesize::PAGE_SIZE;
26        let total_pages = len.div_ceil(page_size);
27
28        let needs_touch = |i: &usize| ctx.residency().is_none_or(|r| !r.is_set(*i));
29
30        let mut touched = 0usize;
31
32        if (0..total_pages).any(|i| needs_touch(&i)) {
33            const PROGRESS_INTERVAL: usize = 256;
34            initiate_readahead(ctx);
35
36            for page_idx in (0..total_pages).filter(needs_touch) {
37                ctx.check_cancelled()?;
38                let offset = page_idx * page_size;
39                unsafe {
40                    std::ptr::read_volatile(mmap.as_ptr().add(offset));
41                }
42                touched += 1;
43                if (page_idx + 1) % PROGRESS_INTERVAL == 0 {
44                    ctx.report_progress(page_idx + 1, touched);
45                }
46            }
47        }
48
49        Ok(touched)
50    }
51}
52
53fn initiate_readahead<PM: PageMap>(ctx: &FileContext<'_, PM>) {
54    let len = ctx.len();
55
56    #[cfg(target_os = "linux")]
57    {
58        use std::os::unix::io::AsFd;
59        let fd = ctx.file().as_fd();
60        let offset = ctx.offset() as libc::off_t;
61        let len = len as libc::off_t;
62        let _ = nix::fcntl::posix_fadvise(
63            fd,
64            offset,
65            len,
66            nix::fcntl::PosixFadviseAdvice::POSIX_FADV_SEQUENTIAL,
67        );
68        let _ = nix::fcntl::posix_fadvise(
69            fd,
70            offset,
71            len,
72            nix::fcntl::PosixFadviseAdvice::POSIX_FADV_WILLNEED,
73        );
74    }
75
76    let _ = ctx.mmap().advise_range(Advice::WillNeed, 0, len);
77}