file_engine/profiler/workload.rs
1use std::path::PathBuf;
2use std::time::SystemTime;
3
4#[derive(Debug, Clone, PartialEq, Eq, Default)]
5pub struct Entry {
6 pub path: PathBuf,
7 pub relative_path: PathBuf,
8 pub size: u64,
9 /// `None` when the platform/filesystem doesn't report mtimes.
10 /// Populated by `scan.rs`; only consumed by `sync`'s
11 /// `DiffStrategy::SizeAndModifiedTime`, but kept here rather than in
12 /// a sync-specific type since the Profiler already fetches it for
13 /// every entry as part of the same `metadata()` call that gets size.
14 pub modified: Option<SystemTime>,
15}
16
17/// A directory the Profiler discovered while walking — separate from
18/// `Entry` because directories aren't part of size-based batching at all
19/// (no bytes to transfer), only ever consumed by permission-preservation.
20///
21/// `Entry` deliberately has no equivalent `mode` field: `std::fs::copy`
22/// (which `CopyAction` already uses) unconditionally copies the source
23/// file's permission bits to the destination — verified empirically, not
24/// assumed — so an explicit file-mode-preservation step would just
25/// re-apply what `copy()` already did, from a captured-at-scan-time value
26/// that's actually less current than what `copy()` reads live. Directory
27/// creation (`create_dir_all`) has no equivalent built-in behavior, which
28/// is what makes preserving *directory* permissions the one part of this
29/// feature that does something. See dev-docs/design/permissions.md.
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct DirEntry {
32 pub path: PathBuf,
33 /// Empty for the scanned root itself.
34 pub relative_path: PathBuf,
35 pub mode: Option<u32>,
36}
37
38#[derive(Debug, Clone, Default)]
39pub struct Workload {
40 pub small: Vec<Entry>,
41 pub large: Vec<Entry>,
42 pub directories: Vec<DirEntry>,
43}
44
45impl Workload {
46 /// Entries exactly at `threshold` are classified as small.
47 /// `directories` is left empty — set separately by `scan_blocking`,
48 /// since directories aren't part of the size-based split this
49 /// function performs.
50 pub(crate) fn partition(entries: Vec<Entry>, threshold: u64) -> Self {
51 let (small, large) = entries.into_iter().partition(|e| e.size <= threshold);
52 Self { small, large, directories: Vec::new() }
53 }
54}