1 use crate::dirstate::entry::Timestamp; |
1 use crate::dirstate::entry::TruncatedTimestamp; |
2 use crate::dirstate::status::IgnoreFnType; |
2 use crate::dirstate::status::IgnoreFnType; |
3 use crate::dirstate_tree::dirstate_map::BorrowedPath; |
3 use crate::dirstate_tree::dirstate_map::BorrowedPath; |
4 use crate::dirstate_tree::dirstate_map::ChildNodesRef; |
4 use crate::dirstate_tree::dirstate_map::ChildNodesRef; |
5 use crate::dirstate_tree::dirstate_map::DirstateMap; |
5 use crate::dirstate_tree::dirstate_map::DirstateMap; |
6 use crate::dirstate_tree::dirstate_map::NodeData; |
6 use crate::dirstate_tree::dirstate_map::NodeData; |
124 dmap: &'tree DirstateMap<'on_disk>, |
124 dmap: &'tree DirstateMap<'on_disk>, |
125 options: StatusOptions, |
125 options: StatusOptions, |
126 matcher: &'a (dyn Matcher + Sync), |
126 matcher: &'a (dyn Matcher + Sync), |
127 ignore_fn: IgnoreFnType<'a>, |
127 ignore_fn: IgnoreFnType<'a>, |
128 outcome: Mutex<DirstateStatus<'on_disk>>, |
128 outcome: Mutex<DirstateStatus<'on_disk>>, |
129 new_cachable_directories: Mutex<Vec<(Cow<'on_disk, HgPath>, Timestamp)>>, |
129 new_cachable_directories: |
|
130 Mutex<Vec<(Cow<'on_disk, HgPath>, TruncatedTimestamp)>>, |
130 outated_cached_directories: Mutex<Vec<Cow<'on_disk, HgPath>>>, |
131 outated_cached_directories: Mutex<Vec<Cow<'on_disk, HgPath>>>, |
131 |
132 |
132 /// Whether ignore files like `.hgignore` have changed since the previous |
133 /// Whether ignore files like `.hgignore` have changed since the previous |
133 /// time a `status()` call wrote their hash to the dirstate. `None` means |
134 /// time a `status()` call wrote their hash to the dirstate. `None` means |
134 /// we don’t know as this run doesn’t list either ignored or uknown files |
135 /// we don’t know as this run doesn’t list either ignored or uknown files |
163 fn check_for_outdated_directory_cache( |
164 fn check_for_outdated_directory_cache( |
164 &self, |
165 &self, |
165 dirstate_node: &NodeRef<'tree, 'on_disk>, |
166 dirstate_node: &NodeRef<'tree, 'on_disk>, |
166 ) -> Result<(), DirstateV2ParseError> { |
167 ) -> Result<(), DirstateV2ParseError> { |
167 if self.ignore_patterns_have_changed == Some(true) |
168 if self.ignore_patterns_have_changed == Some(true) |
168 && dirstate_node.cached_directory_mtime().is_some() |
169 && dirstate_node.cached_directory_mtime()?.is_some() |
169 { |
170 { |
170 self.outated_cached_directories.lock().unwrap().push( |
171 self.outated_cached_directories.lock().unwrap().push( |
171 dirstate_node |
172 dirstate_node |
172 .full_path_borrowed(self.dmap.on_disk)? |
173 .full_path_borrowed(self.dmap.on_disk)? |
173 .detach_from_tree(), |
174 .detach_from_tree(), |
180 /// `symlink_metadata` for child nodes that exist in the dirstate and don’t |
181 /// `symlink_metadata` for child nodes that exist in the dirstate and don’t |
181 /// need to call `read_dir`. |
182 /// need to call `read_dir`. |
182 fn can_skip_fs_readdir( |
183 fn can_skip_fs_readdir( |
183 &self, |
184 &self, |
184 directory_metadata: Option<&std::fs::Metadata>, |
185 directory_metadata: Option<&std::fs::Metadata>, |
185 cached_directory_mtime: Option<Timestamp>, |
186 cached_directory_mtime: Option<TruncatedTimestamp>, |
186 ) -> bool { |
187 ) -> bool { |
187 if !self.options.list_unknown && !self.options.list_ignored { |
188 if !self.options.list_unknown && !self.options.list_ignored { |
188 // All states that we care about listing have corresponding |
189 // All states that we care about listing have corresponding |
189 // dirstate entries. |
190 // dirstate entries. |
190 // This happens for example with `hg status -mard`. |
191 // This happens for example with `hg status -mard`. |
197 // The dirstate contains a cached mtime for this directory, set |
198 // The dirstate contains a cached mtime for this directory, set |
198 // by a previous run of the `status` algorithm which found this |
199 // by a previous run of the `status` algorithm which found this |
199 // directory eligible for `read_dir` caching. |
200 // directory eligible for `read_dir` caching. |
200 if let Some(meta) = directory_metadata { |
201 if let Some(meta) = directory_metadata { |
201 if let Ok(current_mtime) = meta.modified() { |
202 if let Ok(current_mtime) = meta.modified() { |
202 let current_mtime = Timestamp::from(current_mtime); |
203 let truncated = |
203 if current_mtime == cached_mtime { |
204 TruncatedTimestamp::from(current_mtime); |
|
205 if truncated.very_likely_equal(&cached_mtime) { |
204 // The mtime of that directory has not changed |
206 // The mtime of that directory has not changed |
205 // since then, which means that the results of |
207 // since then, which means that the results of |
206 // `read_dir` should also be unchanged. |
208 // `read_dir` should also be unchanged. |
207 return true; |
209 return true; |
208 } |
210 } |
220 has_ignored_ancestor: bool, |
222 has_ignored_ancestor: bool, |
221 dirstate_nodes: ChildNodesRef<'tree, 'on_disk>, |
223 dirstate_nodes: ChildNodesRef<'tree, 'on_disk>, |
222 directory_hg_path: &BorrowedPath<'tree, 'on_disk>, |
224 directory_hg_path: &BorrowedPath<'tree, 'on_disk>, |
223 directory_fs_path: &Path, |
225 directory_fs_path: &Path, |
224 directory_metadata: Option<&std::fs::Metadata>, |
226 directory_metadata: Option<&std::fs::Metadata>, |
225 cached_directory_mtime: Option<Timestamp>, |
227 cached_directory_mtime: Option<TruncatedTimestamp>, |
226 is_at_repo_root: bool, |
228 is_at_repo_root: bool, |
227 ) -> Result<bool, DirstateV2ParseError> { |
229 ) -> Result<bool, DirstateV2ParseError> { |
228 if self.can_skip_fs_readdir(directory_metadata, cached_directory_mtime) |
230 if self.can_skip_fs_readdir(directory_metadata, cached_directory_mtime) |
229 { |
231 { |
230 dirstate_nodes |
232 dirstate_nodes |
361 is_ignored, |
363 is_ignored, |
362 dirstate_node.children(self.dmap.on_disk)?, |
364 dirstate_node.children(self.dmap.on_disk)?, |
363 hg_path, |
365 hg_path, |
364 fs_path, |
366 fs_path, |
365 Some(fs_metadata), |
367 Some(fs_metadata), |
366 dirstate_node.cached_directory_mtime(), |
368 dirstate_node.cached_directory_mtime()?, |
367 is_at_repo_root, |
369 is_at_repo_root, |
368 )?; |
370 )?; |
369 self.maybe_save_directory_mtime( |
371 self.maybe_save_directory_mtime( |
370 children_all_have_dirstate_node_or_are_ignored, |
372 children_all_have_dirstate_node_or_are_ignored, |
371 fs_metadata, |
373 fs_metadata, |
464 // directory change could potentially happen during exactly |
466 // directory change could potentially happen during exactly |
465 // the wrong tick. |
467 // the wrong tick. |
466 // |
468 // |
467 // We deem this scenario (unlike the previous one) to be |
469 // We deem this scenario (unlike the previous one) to be |
468 // unlikely enough in practice. |
470 // unlikely enough in practice. |
469 let timestamp = directory_mtime.into(); |
471 let truncated = TruncatedTimestamp::from(directory_mtime); |
470 let cached = dirstate_node.cached_directory_mtime(); |
472 let is_up_to_date = if let Some(cached) = |
471 if cached != Some(timestamp) { |
473 dirstate_node.cached_directory_mtime()? |
|
474 { |
|
475 cached.very_likely_equal(&truncated) |
|
476 } else { |
|
477 false |
|
478 }; |
|
479 if !is_up_to_date { |
472 let hg_path = dirstate_node |
480 let hg_path = dirstate_node |
473 .full_path_borrowed(self.dmap.on_disk)? |
481 .full_path_borrowed(self.dmap.on_disk)? |
474 .detach_from_tree(); |
482 .detach_from_tree(); |
475 self.new_cachable_directories |
483 self.new_cachable_directories |
476 .lock() |
484 .lock() |
477 .unwrap() |
485 .unwrap() |
478 .push((hg_path, timestamp)) |
486 .push((hg_path, truncated)) |
479 } |
487 } |
480 } |
488 } |
481 } |
489 } |
482 } |
490 } |
483 Ok(()) |
491 Ok(()) |