Show More
@@ -98,13 +98,16 b' pub(super) struct Node {' | |||
|
98 | 98 | /// and must cause a different modification time (unless the system |
|
99 | 99 | /// clock jumps back and we get unlucky, which is not impossible but |
|
100 | 100 | /// but deemed unlikely enough). |
|
101 | /// - The directory did not contain any child entry that did not have a | |
|
102 |
/// corresponding dirstate node |
|
|
101 | /// - All direct children of this directory (as returned by | |
|
102 | /// `std::fs::read_dir`) either have a corresponding dirstate node, or | |
|
103 | /// are ignored by ignore patterns whose hash is in | |
|
104 | /// `Header::ignore_patterns_hash`. | |
|
103 | 105 | /// |
|
104 | 106 | /// This means that if `std::fs::symlink_metadata` later reports the |
|
105 | /// same modification time, we don’t need to call `std::fs::read_dir` | |
|
106 | /// again for this directory and can iterate child dirstate nodes | |
|
107 | /// instead. | |
|
107 | /// same modification time and ignored patterns haven’t changed, a run | |
|
108 | /// of status that is not listing ignored files can skip calling | |
|
109 | /// `std::fs::read_dir` again for this directory, iterate child | |
|
110 | /// dirstate nodes instead. | |
|
108 | 111 | state: u8, |
|
109 | 112 | data: Entry, |
|
110 | 113 | } |
@@ -190,18 +190,21 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||
|
190 | 190 | // This happens for example with `hg status -mard`. |
|
191 | 191 | return true; |
|
192 | 192 | } |
|
193 | if let Some(cached_mtime) = cached_directory_mtime { | |
|
194 | // The dirstate contains a cached mtime for this directory, set by | |
|
195 | // a previous run of the `status` algorithm which found this | |
|
196 | // directory eligible for `read_dir` caching. | |
|
197 | if let Some(meta) = directory_metadata { | |
|
198 | if let Ok(current_mtime) = meta.modified() { | |
|
199 | if current_mtime == cached_mtime.into() { | |
|
200 | // The mtime of that directory has not changed since | |
|
201 | // then, which means that the | |
|
202 | // results of `read_dir` should also | |
|
203 |
|
|
|
204 | return true; | |
|
193 | if !self.options.list_ignored | |
|
194 | && self.ignore_patterns_have_changed == Some(false) | |
|
195 | { | |
|
196 | if let Some(cached_mtime) = cached_directory_mtime { | |
|
197 | // The dirstate contains a cached mtime for this directory, set | |
|
198 | // by a previous run of the `status` algorithm which found this | |
|
199 | // directory eligible for `read_dir` caching. | |
|
200 | if let Some(meta) = directory_metadata { | |
|
201 | if let Ok(current_mtime) = meta.modified() { | |
|
202 | if current_mtime == cached_mtime.into() { | |
|
203 | // The mtime of that directory has not changed | |
|
204 | // since then, which means that the results of | |
|
205 | // `read_dir` should also be unchanged. | |
|
206 | return true; | |
|
207 | } | |
|
205 | 208 | } |
|
206 | 209 | } |
|
207 | 210 | } |
@@ -209,8 +212,8 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||
|
209 | 212 | false |
|
210 | 213 | } |
|
211 | 214 | |
|
212 |
/// Returns whether the filesystem directory |
|
|
213 |
/// |
|
|
215 | /// Returns whether all child entries of the filesystem directory have a | |
|
216 | /// corresponding dirstate node or are ignored. | |
|
214 | 217 | fn traverse_fs_directory_and_dirstate( |
|
215 | 218 | &self, |
|
216 | 219 | has_ignored_ancestor: bool, |
@@ -248,11 +251,10 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||
|
248 | 251 | }) |
|
249 | 252 | .collect::<Result<_, _>>()?; |
|
250 | 253 | |
|
251 | // Conservatively don’t let the caller assume that there aren’t | |
|
252 | // any, since we don’t know. | |
|
253 | let directory_has_any_fs_only_entry = true; | |
|
254 | // We don’t know, so conservatively say this isn’t the case | |
|
255 | let children_all_have_dirstate_node_or_are_ignored = false; | |
|
254 | 256 | |
|
255 | return Ok(directory_has_any_fs_only_entry); | |
|
257 | return Ok(children_all_have_dirstate_node_or_are_ignored); | |
|
256 | 258 | } |
|
257 | 259 | |
|
258 | 260 | let mut fs_entries = if let Ok(entries) = self.read_dir( |
@@ -295,27 +297,32 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||
|
295 | 297 | .par_bridge() |
|
296 | 298 | .map(|pair| { |
|
297 | 299 | use itertools::EitherOrBoth::*; |
|
298 | let is_fs_only = pair.is_right(); | |
|
300 | let has_dirstate_node_or_is_ignored; | |
|
299 | 301 | match pair { |
|
300 |
Both(dirstate_node, fs_entry) => |
|
|
301 | .traverse_fs_and_dirstate( | |
|
302 | Both(dirstate_node, fs_entry) => { | |
|
303 | self.traverse_fs_and_dirstate( | |
|
302 | 304 | &fs_entry.full_path, |
|
303 | 305 | &fs_entry.metadata, |
|
304 | 306 | dirstate_node, |
|
305 | 307 | has_ignored_ancestor, |
|
306 |
)? |
|
|
308 | )?; | |
|
309 | has_dirstate_node_or_is_ignored = true | |
|
310 | } | |
|
307 | 311 | Left(dirstate_node) => { |
|
308 | self.traverse_dirstate_only(dirstate_node)? | |
|
312 | self.traverse_dirstate_only(dirstate_node)?; | |
|
313 | has_dirstate_node_or_is_ignored = true; | |
|
309 | 314 | } |
|
310 |
Right(fs_entry) => |
|
|
311 | has_ignored_ancestor, | |
|
312 |
|
|
|
313 |
|
|
|
314 |
|
|
|
315 | Right(fs_entry) => { | |
|
316 | has_dirstate_node_or_is_ignored = self.traverse_fs_only( | |
|
317 | has_ignored_ancestor, | |
|
318 | directory_hg_path, | |
|
319 | fs_entry, | |
|
320 | ) | |
|
321 | } | |
|
315 | 322 | } |
|
316 | Ok(is_fs_only) | |
|
323 | Ok(has_dirstate_node_or_is_ignored) | |
|
317 | 324 | }) |
|
318 |
.try_reduce(|| |
|
|
325 | .try_reduce(|| true, |a, b| Ok(a && b)) | |
|
319 | 326 | } |
|
320 | 327 | |
|
321 | 328 | fn traverse_fs_and_dirstate( |
@@ -348,7 +355,7 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||
|
348 | 355 | } |
|
349 | 356 | let is_ignored = has_ignored_ancestor || (self.ignore_fn)(hg_path); |
|
350 | 357 | let is_at_repo_root = false; |
|
351 | let directory_has_any_fs_only_entry = self | |
|
358 | let children_all_have_dirstate_node_or_are_ignored = self | |
|
352 | 359 | .traverse_fs_directory_and_dirstate( |
|
353 | 360 | is_ignored, |
|
354 | 361 | dirstate_node.children(self.dmap.on_disk)?, |
@@ -359,7 +366,7 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||
|
359 | 366 | is_at_repo_root, |
|
360 | 367 | )?; |
|
361 | 368 | self.maybe_save_directory_mtime( |
|
362 | directory_has_any_fs_only_entry, | |
|
369 | children_all_have_dirstate_node_or_are_ignored, | |
|
363 | 370 | fs_metadata, |
|
364 | 371 | dirstate_node, |
|
365 | 372 | )? |
@@ -394,7 +401,10 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||
|
394 | 401 | } else { |
|
395 | 402 | // `node.entry.is_none()` indicates a "directory" |
|
396 | 403 | // node, but the filesystem has a file |
|
397 |
self.mark_unknown_or_ignored( |
|
|
404 | self.mark_unknown_or_ignored( | |
|
405 | has_ignored_ancestor, | |
|
406 | hg_path, | |
|
407 | ); | |
|
398 | 408 | } |
|
399 | 409 | } |
|
400 | 410 | |
@@ -408,11 +418,11 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||
|
408 | 418 | |
|
409 | 419 | fn maybe_save_directory_mtime( |
|
410 | 420 | &self, |
|
411 | directory_has_any_fs_only_entry: bool, | |
|
421 | children_all_have_dirstate_node_or_are_ignored: bool, | |
|
412 | 422 | directory_metadata: &std::fs::Metadata, |
|
413 | 423 | dirstate_node: NodeRef<'tree, 'on_disk>, |
|
414 | 424 | ) -> Result<(), DirstateV2ParseError> { |
|
415 | if !directory_has_any_fs_only_entry { | |
|
425 | if children_all_have_dirstate_node_or_are_ignored { | |
|
416 | 426 | // All filesystem directory entries from `read_dir` have a |
|
417 | 427 | // corresponding node in the dirstate, so we can reconstitute the |
|
418 | 428 | // names of those entries without calling `read_dir` again. |
@@ -584,12 +594,14 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||
|
584 | 594 | } |
|
585 | 595 | |
|
586 | 596 | /// Something in the filesystem has no corresponding dirstate node |
|
597 | /// | |
|
598 | /// Returns whether that path is ignored | |
|
587 | 599 | fn traverse_fs_only( |
|
588 | 600 | &self, |
|
589 | 601 | has_ignored_ancestor: bool, |
|
590 | 602 | directory_hg_path: &HgPath, |
|
591 | 603 | fs_entry: &DirEntry, |
|
592 | ) { | |
|
604 | ) -> bool { | |
|
593 | 605 | let hg_path = directory_hg_path.join(&fs_entry.base_name); |
|
594 | 606 | let file_type = fs_entry.metadata.file_type(); |
|
595 | 607 | let file_or_symlink = file_type.is_file() || file_type.is_symlink(); |
@@ -616,26 +628,43 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||
|
616 | 628 | is_ignored, |
|
617 | 629 | &hg_path, |
|
618 | 630 | child_fs_entry, |
|
619 | ) | |
|
631 | ); | |
|
620 | 632 | }) |
|
621 | 633 | } |
|
622 | 634 | } |
|
623 | 635 | if self.options.collect_traversed_dirs { |
|
624 | 636 | self.outcome.lock().unwrap().traversed.push(hg_path.into()) |
|
625 | 637 | } |
|
626 | } else if file_or_symlink && self.matcher.matches(&hg_path) { | |
|
627 | self.mark_unknown_or_ignored( | |
|
628 | has_ignored_ancestor, | |
|
629 |
|
|
|
630 | ) | |
|
638 | is_ignored | |
|
639 | } else { | |
|
640 | if file_or_symlink { | |
|
641 | if self.matcher.matches(&hg_path) { | |
|
642 | self.mark_unknown_or_ignored( | |
|
643 | has_ignored_ancestor, | |
|
644 | &BorrowedPath::InMemory(&hg_path), | |
|
645 | ) | |
|
646 | } else { | |
|
647 | // We haven’t computed whether this path is ignored. It | |
|
648 | // might not be, and a future run of status might have a | |
|
649 | // different matcher that matches it. So treat it as not | |
|
650 | // ignored. That is, inhibit readdir caching of the parent | |
|
651 | // directory. | |
|
652 | false | |
|
653 | } | |
|
654 | } else { | |
|
655 | // This is neither a directory, a plain file, or a symlink. | |
|
656 | // Treat it like an ignored file. | |
|
657 | true | |
|
658 | } | |
|
631 | 659 | } |
|
632 | 660 | } |
|
633 | 661 | |
|
662 | /// Returns whether that path is ignored | |
|
634 | 663 | fn mark_unknown_or_ignored( |
|
635 | 664 | &self, |
|
636 | 665 | has_ignored_ancestor: bool, |
|
637 | 666 | hg_path: &BorrowedPath<'_, 'on_disk>, |
|
638 | ) { | |
|
667 | ) -> bool { | |
|
639 | 668 | let is_ignored = has_ignored_ancestor || (self.ignore_fn)(&hg_path); |
|
640 | 669 | if is_ignored { |
|
641 | 670 | if self.options.list_ignored { |
@@ -654,6 +683,7 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||
|
654 | 683 | .push(hg_path.detach_from_tree()) |
|
655 | 684 | } |
|
656 | 685 | } |
|
686 | is_ignored | |
|
657 | 687 | } |
|
658 | 688 | } |
|
659 | 689 |
General Comments 0
You need to be logged in to leave comments.
Login now