Mercurial > hg
comparison rust/hg-core/src/dirstate_tree/status.rs @ 47409:0ef8231e413f
dirstate-v2: Store a hash of ignore patterns (.hgignore)
Later, this help extend `read_dir` caching to directories that contain ignored
files (but no unknown files). Such cache must be invalidated when ignore patterns
change since a formerly-ignored file might become unknown.
This helps the default configuration of `hg status` where unknown files must
be listed, but ignored files are not.
Differential Revision: https://phab.mercurial-scm.org/D10836
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Wed, 02 Jun 2021 11:25:18 +0200 |
parents | 04d1f17f49e7 |
children | c657beacdf2e |
comparison
equal
deleted
inserted
replaced
47408:7954ee2d7cf7 | 47409:0ef8231e413f |
---|---|
19 use crate::PatternFileWarning; | 19 use crate::PatternFileWarning; |
20 use crate::StatusError; | 20 use crate::StatusError; |
21 use crate::StatusOptions; | 21 use crate::StatusOptions; |
22 use micro_timer::timed; | 22 use micro_timer::timed; |
23 use rayon::prelude::*; | 23 use rayon::prelude::*; |
24 use sha1::{Digest, Sha1}; | |
24 use std::borrow::Cow; | 25 use std::borrow::Cow; |
25 use std::io; | 26 use std::io; |
26 use std::path::Path; | 27 use std::path::Path; |
27 use std::path::PathBuf; | 28 use std::path::PathBuf; |
28 use std::sync::Mutex; | 29 use std::sync::Mutex; |
43 matcher: &(dyn Matcher + Sync), | 44 matcher: &(dyn Matcher + Sync), |
44 root_dir: PathBuf, | 45 root_dir: PathBuf, |
45 ignore_files: Vec<PathBuf>, | 46 ignore_files: Vec<PathBuf>, |
46 options: StatusOptions, | 47 options: StatusOptions, |
47 ) -> Result<(DirstateStatus<'on_disk>, Vec<PatternFileWarning>), StatusError> { | 48 ) -> Result<(DirstateStatus<'on_disk>, Vec<PatternFileWarning>), StatusError> { |
48 let (ignore_fn, warnings): (IgnoreFnType, _) = | 49 let (ignore_fn, warnings, patterns_changed): (IgnoreFnType, _, _) = |
49 if options.list_ignored || options.list_unknown { | 50 if options.list_ignored || options.list_unknown { |
50 get_ignore_function(ignore_files, &root_dir)? | 51 let mut hasher = Sha1::new(); |
52 let (ignore_fn, warnings) = get_ignore_function( | |
53 ignore_files, | |
54 &root_dir, | |
55 &mut |pattern_bytes| hasher.update(pattern_bytes), | |
56 )?; | |
57 let new_hash = *hasher.finalize().as_ref(); | |
58 let changed = new_hash != dmap.ignore_patterns_hash; | |
59 dmap.ignore_patterns_hash = new_hash; | |
60 (ignore_fn, warnings, Some(changed)) | |
51 } else { | 61 } else { |
52 (Box::new(|&_| true), vec![]) | 62 (Box::new(|&_| true), vec![], None) |
53 }; | 63 }; |
54 | 64 |
55 let common = StatusCommon { | 65 let common = StatusCommon { |
56 dmap, | 66 dmap, |
57 options, | 67 options, |
58 matcher, | 68 matcher, |
59 ignore_fn, | 69 ignore_fn, |
60 outcome: Default::default(), | 70 outcome: Default::default(), |
61 cached_directory_mtimes_to_add: Default::default(), | 71 ignore_patterns_have_changed: patterns_changed, |
72 new_cachable_directories: Default::default(), | |
62 filesystem_time_at_status_start: filesystem_now(&root_dir).ok(), | 73 filesystem_time_at_status_start: filesystem_now(&root_dir).ok(), |
63 }; | 74 }; |
64 let is_at_repo_root = true; | 75 let is_at_repo_root = true; |
65 let hg_path = &BorrowedPath::OnDisk(HgPath::new("")); | 76 let hg_path = &BorrowedPath::OnDisk(HgPath::new("")); |
66 let has_ignored_ancestor = false; | 77 let has_ignored_ancestor = false; |
77 root_dir_metadata, | 88 root_dir_metadata, |
78 root_cached_mtime, | 89 root_cached_mtime, |
79 is_at_repo_root, | 90 is_at_repo_root, |
80 )?; | 91 )?; |
81 let mut outcome = common.outcome.into_inner().unwrap(); | 92 let mut outcome = common.outcome.into_inner().unwrap(); |
82 let to_add = common.cached_directory_mtimes_to_add.into_inner().unwrap(); | 93 let new_cachable = common.new_cachable_directories.into_inner().unwrap(); |
83 outcome.dirty = !to_add.is_empty(); | 94 |
84 for (path, mtime) in &to_add { | 95 outcome.dirty = common.ignore_patterns_have_changed == Some(true) |
96 || !new_cachable.is_empty(); | |
97 | |
98 for (path, mtime) in &new_cachable { | |
85 let node = DirstateMap::get_or_insert_node( | 99 let node = DirstateMap::get_or_insert_node( |
86 dmap.on_disk, | 100 dmap.on_disk, |
87 &mut dmap.root, | 101 &mut dmap.root, |
88 path, | 102 path, |
89 WithBasename::to_cow_owned, | 103 WithBasename::to_cow_owned, |
94 NodeData::CachedDirectory { .. } | NodeData::None => { | 108 NodeData::CachedDirectory { .. } | NodeData::None => { |
95 node.data = NodeData::CachedDirectory { mtime: *mtime } | 109 node.data = NodeData::CachedDirectory { mtime: *mtime } |
96 } | 110 } |
97 } | 111 } |
98 } | 112 } |
113 | |
99 Ok((outcome, warnings)) | 114 Ok((outcome, warnings)) |
100 } | 115 } |
101 | 116 |
102 /// Bag of random things needed by various parts of the algorithm. Reduces the | 117 /// Bag of random things needed by various parts of the algorithm. Reduces the |
103 /// number of parameters passed to functions. | 118 /// number of parameters passed to functions. |
105 dmap: &'tree DirstateMap<'on_disk>, | 120 dmap: &'tree DirstateMap<'on_disk>, |
106 options: StatusOptions, | 121 options: StatusOptions, |
107 matcher: &'a (dyn Matcher + Sync), | 122 matcher: &'a (dyn Matcher + Sync), |
108 ignore_fn: IgnoreFnType<'a>, | 123 ignore_fn: IgnoreFnType<'a>, |
109 outcome: Mutex<DirstateStatus<'on_disk>>, | 124 outcome: Mutex<DirstateStatus<'on_disk>>, |
110 cached_directory_mtimes_to_add: | 125 new_cachable_directories: Mutex<Vec<(Cow<'on_disk, HgPath>, Timestamp)>>, |
111 Mutex<Vec<(Cow<'on_disk, HgPath>, Timestamp)>>, | 126 |
127 /// Whether ignore files like `.hgignore` have changed since the previous | |
128 /// time a `status()` call wrote their hash to the dirstate. `None` means | |
129 /// we don’t know as this run doesn’t list either ignored or uknown files | |
130 /// and therefore isn’t reading `.hgignore`. | |
131 ignore_patterns_have_changed: Option<bool>, | |
112 | 132 |
113 /// The current time at the start of the `status()` algorithm, as measured | 133 /// The current time at the start of the `status()` algorithm, as measured |
114 /// and possibly truncated by the filesystem. | 134 /// and possibly truncated by the filesystem. |
115 filesystem_time_at_status_start: Option<SystemTime>, | 135 filesystem_time_at_status_start: Option<SystemTime>, |
116 } | 136 } |
420 let cached = dirstate_node.cached_directory_mtime(); | 440 let cached = dirstate_node.cached_directory_mtime(); |
421 if cached != Some(×tamp) { | 441 if cached != Some(×tamp) { |
422 let hg_path = dirstate_node | 442 let hg_path = dirstate_node |
423 .full_path_borrowed(self.dmap.on_disk)? | 443 .full_path_borrowed(self.dmap.on_disk)? |
424 .detach_from_tree(); | 444 .detach_from_tree(); |
425 self.cached_directory_mtimes_to_add | 445 self.new_cachable_directories |
426 .lock() | 446 .lock() |
427 .unwrap() | 447 .unwrap() |
428 .push((hg_path, timestamp)) | 448 .push((hg_path, timestamp)) |
429 } | 449 } |
430 } | 450 } |