Mercurial > public > mercurial-scm > hg
comparison rust/hg-core/src/dirstate_tree/status.rs @ 49585:18282cf18aa2
branching: merge stable into default
author | Rapha?l Gom?s <rgomes@octobus.net> |
---|---|
date | Mon, 14 Nov 2022 10:59:09 +0100 |
parents | da48f170d203 363923bd51cd |
children | c7fb9b74e753 |
comparison
equal
deleted
inserted
replaced
49577:53e4f44ba0e8 | 49585:18282cf18aa2 |
---|---|
8 use crate::dirstate_tree::dirstate_map::NodeRef; | 8 use crate::dirstate_tree::dirstate_map::NodeRef; |
9 use crate::dirstate_tree::on_disk::DirstateV2ParseError; | 9 use crate::dirstate_tree::on_disk::DirstateV2ParseError; |
10 use crate::matchers::get_ignore_function; | 10 use crate::matchers::get_ignore_function; |
11 use crate::matchers::Matcher; | 11 use crate::matchers::Matcher; |
12 use crate::utils::files::get_bytes_from_os_string; | 12 use crate::utils::files::get_bytes_from_os_string; |
13 use crate::utils::files::get_bytes_from_path; | |
13 use crate::utils::files::get_path_from_bytes; | 14 use crate::utils::files::get_path_from_bytes; |
14 use crate::utils::hg_path::HgPath; | 15 use crate::utils::hg_path::HgPath; |
15 use crate::BadMatch; | 16 use crate::BadMatch; |
16 use crate::DirstateStatus; | 17 use crate::DirstateStatus; |
17 use crate::HgPathCow; | 18 use crate::HgPathCow; |
65 let (ignore_fn, warnings, changed) = match dmap.dirstate_version { | 66 let (ignore_fn, warnings, changed) = match dmap.dirstate_version { |
66 DirstateVersion::V1 => { | 67 DirstateVersion::V1 => { |
67 let (ignore_fn, warnings) = get_ignore_function( | 68 let (ignore_fn, warnings) = get_ignore_function( |
68 ignore_files, | 69 ignore_files, |
69 &root_dir, | 70 &root_dir, |
70 &mut |_pattern_bytes| {}, | 71 &mut |_source, _pattern_bytes| {}, |
71 )?; | 72 )?; |
72 (ignore_fn, warnings, None) | 73 (ignore_fn, warnings, None) |
73 } | 74 } |
74 DirstateVersion::V2 => { | 75 DirstateVersion::V2 => { |
75 let mut hasher = Sha1::new(); | 76 let mut hasher = Sha1::new(); |
76 let (ignore_fn, warnings) = get_ignore_function( | 77 let (ignore_fn, warnings) = get_ignore_function( |
77 ignore_files, | 78 ignore_files, |
78 &root_dir, | 79 &root_dir, |
79 &mut |pattern_bytes| hasher.update(pattern_bytes), | 80 &mut |source, pattern_bytes| { |
81 // If inside the repo, use the relative version to | |
82 // make it deterministic inside tests. | |
83 // The performance hit should be negligible. | |
84 let source = source | |
85 .strip_prefix(&root_dir) | |
86 .unwrap_or(source); | |
87 let source = get_bytes_from_path(source); | |
88 | |
89 let mut subhasher = Sha1::new(); | |
90 subhasher.update(pattern_bytes); | |
91 let patterns_hash = subhasher.finalize(); | |
92 | |
93 hasher.update(source); | |
94 hasher.update(b" "); | |
95 hasher.update(patterns_hash); | |
96 hasher.update(b"\n"); | |
97 }, | |
80 )?; | 98 )?; |
81 let new_hash = *hasher.finalize().as_ref(); | 99 let new_hash = *hasher.finalize().as_ref(); |
82 let changed = new_hash != dmap.ignore_patterns_hash; | 100 let changed = new_hash != dmap.ignore_patterns_hash; |
83 dmap.ignore_patterns_hash = new_hash; | 101 dmap.ignore_patterns_hash = new_hash; |
84 (ignore_fn, warnings, Some(changed)) | 102 (ignore_fn, warnings, Some(changed)) |
120 options, | 138 options, |
121 matcher, | 139 matcher, |
122 ignore_fn, | 140 ignore_fn, |
123 outcome: Mutex::new(outcome), | 141 outcome: Mutex::new(outcome), |
124 ignore_patterns_have_changed: patterns_changed, | 142 ignore_patterns_have_changed: patterns_changed, |
125 new_cachable_directories: Default::default(), | 143 new_cacheable_directories: Default::default(), |
126 outated_cached_directories: Default::default(), | 144 outdated_cached_directories: Default::default(), |
127 filesystem_time_at_status_start, | 145 filesystem_time_at_status_start, |
128 }; | 146 }; |
129 let is_at_repo_root = true; | 147 let is_at_repo_root = true; |
130 let hg_path = &BorrowedPath::OnDisk(HgPath::new("")); | 148 let hg_path = &BorrowedPath::OnDisk(HgPath::new("")); |
131 let has_ignored_ancestor = HasIgnoredAncestor::create(None, hg_path); | 149 let has_ignored_ancestor = HasIgnoredAncestor::create(None, hg_path); |
145 }, | 163 }, |
146 root_cached_mtime, | 164 root_cached_mtime, |
147 is_at_repo_root, | 165 is_at_repo_root, |
148 )?; | 166 )?; |
149 let mut outcome = common.outcome.into_inner().unwrap(); | 167 let mut outcome = common.outcome.into_inner().unwrap(); |
150 let new_cachable = common.new_cachable_directories.into_inner().unwrap(); | 168 let new_cacheable = common.new_cacheable_directories.into_inner().unwrap(); |
151 let outdated = common.outated_cached_directories.into_inner().unwrap(); | 169 let outdated = common.outdated_cached_directories.into_inner().unwrap(); |
152 | 170 |
153 outcome.dirty = common.ignore_patterns_have_changed == Some(true) | 171 outcome.dirty = common.ignore_patterns_have_changed == Some(true) |
154 || !outdated.is_empty() | 172 || !outdated.is_empty() |
155 || (!new_cachable.is_empty() | 173 || (!new_cacheable.is_empty() |
156 && dmap.dirstate_version == DirstateVersion::V2); | 174 && dmap.dirstate_version == DirstateVersion::V2); |
157 | 175 |
158 // Remove outdated mtimes before adding new mtimes, in case a given | 176 // Remove outdated mtimes before adding new mtimes, in case a given |
159 // directory is both | 177 // directory is both |
160 for path in &outdated { | 178 for path in &outdated { |
161 dmap.clear_cached_mtime(path)?; | 179 dmap.clear_cached_mtime(path)?; |
162 } | 180 } |
163 for (path, mtime) in &new_cachable { | 181 for (path, mtime) in &new_cacheable { |
164 dmap.set_cached_mtime(path, *mtime)?; | 182 dmap.set_cached_mtime(path, *mtime)?; |
165 } | 183 } |
166 | 184 |
167 Ok((outcome, warnings)) | 185 Ok((outcome, warnings)) |
168 } | 186 } |
173 dmap: &'tree DirstateMap<'on_disk>, | 191 dmap: &'tree DirstateMap<'on_disk>, |
174 options: StatusOptions, | 192 options: StatusOptions, |
175 matcher: &'a (dyn Matcher + Sync), | 193 matcher: &'a (dyn Matcher + Sync), |
176 ignore_fn: IgnoreFnType<'a>, | 194 ignore_fn: IgnoreFnType<'a>, |
177 outcome: Mutex<DirstateStatus<'on_disk>>, | 195 outcome: Mutex<DirstateStatus<'on_disk>>, |
178 new_cachable_directories: | 196 /// New timestamps of directories to be used for caching their readdirs |
197 new_cacheable_directories: | |
179 Mutex<Vec<(Cow<'on_disk, HgPath>, TruncatedTimestamp)>>, | 198 Mutex<Vec<(Cow<'on_disk, HgPath>, TruncatedTimestamp)>>, |
180 outated_cached_directories: Mutex<Vec<Cow<'on_disk, HgPath>>>, | 199 /// Used to invalidate the readdir cache of directories |
200 outdated_cached_directories: Mutex<Vec<Cow<'on_disk, HgPath>>>, | |
181 | 201 |
182 /// Whether ignore files like `.hgignore` have changed since the previous | 202 /// Whether ignore files like `.hgignore` have changed since the previous |
183 /// time a `status()` call wrote their hash to the dirstate. `None` means | 203 /// time a `status()` call wrote their hash to the dirstate. `None` means |
184 /// we don’t know as this run doesn’t list either ignored or uknown files | 204 /// we don’t know as this run doesn’t list either ignored or uknown files |
185 /// and therefore isn’t reading `.hgignore`. | 205 /// and therefore isn’t reading `.hgignore`. |
303 } | 323 } |
304 | 324 |
305 fn check_for_outdated_directory_cache( | 325 fn check_for_outdated_directory_cache( |
306 &self, | 326 &self, |
307 dirstate_node: &NodeRef<'tree, 'on_disk>, | 327 dirstate_node: &NodeRef<'tree, 'on_disk>, |
308 ) -> Result<(), DirstateV2ParseError> { | 328 ) -> Result<bool, DirstateV2ParseError> { |
309 if self.ignore_patterns_have_changed == Some(true) | 329 if self.ignore_patterns_have_changed == Some(true) |
310 && dirstate_node.cached_directory_mtime()?.is_some() | 330 && dirstate_node.cached_directory_mtime()?.is_some() |
311 { | 331 { |
312 self.outated_cached_directories.lock().unwrap().push( | 332 self.outdated_cached_directories.lock().unwrap().push( |
313 dirstate_node | 333 dirstate_node |
314 .full_path_borrowed(self.dmap.on_disk)? | 334 .full_path_borrowed(self.dmap.on_disk)? |
315 .detach_from_tree(), | 335 .detach_from_tree(), |
316 ) | 336 ); |
317 } | 337 return Ok(true); |
318 Ok(()) | 338 } |
339 Ok(false) | |
319 } | 340 } |
320 | 341 |
321 /// If this returns true, we can get accurate results by only using | 342 /// If this returns true, we can get accurate results by only using |
322 /// `symlink_metadata` for child nodes that exist in the dirstate and don’t | 343 /// `symlink_metadata` for child nodes that exist in the dirstate and don’t |
323 /// need to call `read_dir`. | 344 /// need to call `read_dir`. |
485 &self, | 506 &self, |
486 fs_entry: &DirEntry, | 507 fs_entry: &DirEntry, |
487 dirstate_node: NodeRef<'tree, 'on_disk>, | 508 dirstate_node: NodeRef<'tree, 'on_disk>, |
488 has_ignored_ancestor: &'ancestor HasIgnoredAncestor<'ancestor>, | 509 has_ignored_ancestor: &'ancestor HasIgnoredAncestor<'ancestor>, |
489 ) -> Result<(), DirstateV2ParseError> { | 510 ) -> Result<(), DirstateV2ParseError> { |
490 self.check_for_outdated_directory_cache(&dirstate_node)?; | 511 let outdated_dircache = |
512 self.check_for_outdated_directory_cache(&dirstate_node)?; | |
491 let hg_path = &dirstate_node.full_path_borrowed(self.dmap.on_disk)?; | 513 let hg_path = &dirstate_node.full_path_borrowed(self.dmap.on_disk)?; |
492 let file_or_symlink = fs_entry.is_file() || fs_entry.is_symlink(); | 514 let file_or_symlink = fs_entry.is_file() || fs_entry.is_symlink(); |
493 if !file_or_symlink { | 515 if !file_or_symlink { |
494 // If we previously had a file here, it was removed (with | 516 // If we previously had a file here, it was removed (with |
495 // `hg rm` or similar) or deleted before it could be | 517 // `hg rm` or similar) or deleted before it could be |
520 )?; | 542 )?; |
521 self.maybe_save_directory_mtime( | 543 self.maybe_save_directory_mtime( |
522 children_all_have_dirstate_node_or_are_ignored, | 544 children_all_have_dirstate_node_or_are_ignored, |
523 fs_entry, | 545 fs_entry, |
524 dirstate_node, | 546 dirstate_node, |
547 outdated_dircache, | |
525 )? | 548 )? |
526 } else { | 549 } else { |
527 if file_or_symlink && self.matcher.matches(&hg_path) { | 550 if file_or_symlink && self.matcher.matches(&hg_path) { |
528 if let Some(entry) = dirstate_node.entry()? { | 551 if let Some(entry) = dirstate_node.entry()? { |
529 if !entry.any_tracked() { | 552 if !entry.any_tracked() { |
559 } | 582 } |
560 } | 583 } |
561 Ok(()) | 584 Ok(()) |
562 } | 585 } |
563 | 586 |
587 /// Save directory mtime if applicable. | |
588 /// | |
589 /// `outdated_directory_cache` is `true` if we've just invalidated the | |
590 /// cache for this directory in `check_for_outdated_directory_cache`, | |
591 /// which forces the update. | |
564 fn maybe_save_directory_mtime( | 592 fn maybe_save_directory_mtime( |
565 &self, | 593 &self, |
566 children_all_have_dirstate_node_or_are_ignored: bool, | 594 children_all_have_dirstate_node_or_are_ignored: bool, |
567 directory_entry: &DirEntry, | 595 directory_entry: &DirEntry, |
568 dirstate_node: NodeRef<'tree, 'on_disk>, | 596 dirstate_node: NodeRef<'tree, 'on_disk>, |
597 outdated_directory_cache: bool, | |
569 ) -> Result<(), DirstateV2ParseError> { | 598 ) -> Result<(), DirstateV2ParseError> { |
570 if !children_all_have_dirstate_node_or_are_ignored { | 599 if !children_all_have_dirstate_node_or_are_ignored { |
571 return Ok(()); | 600 return Ok(()); |
572 } | 601 } |
573 // All filesystem directory entries from `read_dir` have a | 602 // All filesystem directory entries from `read_dir` have a |
633 // the wrong tick. | 662 // the wrong tick. |
634 // | 663 // |
635 // We deem this scenario (unlike the previous one) to be | 664 // We deem this scenario (unlike the previous one) to be |
636 // unlikely enough in practice. | 665 // unlikely enough in practice. |
637 | 666 |
638 let is_up_to_date = | 667 let is_up_to_date = if let Some(cached) = |
639 if let Some(cached) = dirstate_node.cached_directory_mtime()? { | 668 dirstate_node.cached_directory_mtime()? |
640 cached.likely_equal(directory_mtime) | 669 { |
641 } else { | 670 !outdated_directory_cache && cached.likely_equal(directory_mtime) |
642 false | 671 } else { |
643 }; | 672 false |
673 }; | |
644 if !is_up_to_date { | 674 if !is_up_to_date { |
645 let hg_path = dirstate_node | 675 let hg_path = dirstate_node |
646 .full_path_borrowed(self.dmap.on_disk)? | 676 .full_path_borrowed(self.dmap.on_disk)? |
647 .detach_from_tree(); | 677 .detach_from_tree(); |
648 self.new_cachable_directories | 678 self.new_cacheable_directories |
649 .lock() | 679 .lock() |
650 .unwrap() | 680 .unwrap() |
651 .push((hg_path, directory_mtime)) | 681 .push((hg_path, directory_mtime)) |
652 } | 682 } |
653 Ok(()) | 683 Ok(()) |