##// END OF EJS Templates
dirstate-v2: skip evaluation of hgignore regex on cached directories...
Arseniy Alekseyev -
r50415:eb02decd default
parent child Browse files
Show More
@@ -468,6 +468,7 b' dependencies = ['
468 "log",
468 "log",
469 "memmap2",
469 "memmap2",
470 "micro-timer",
470 "micro-timer",
471 "once_cell",
471 "ouroboros",
472 "ouroboros",
472 "pretty_assertions",
473 "pretty_assertions",
473 "rand 0.8.5",
474 "rand 0.8.5",
@@ -687,6 +688,12 b' dependencies = ['
687 ]
688 ]
688
689
689 [[package]]
690 [[package]]
691 name = "once_cell"
692 version = "1.14.0"
693 source = "registry+https://github.com/rust-lang/crates.io-index"
694 checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0"
695
696 [[package]]
690 name = "opaque-debug"
697 name = "opaque-debug"
691 version = "0.3.0"
698 version = "0.3.0"
692 source = "registry+https://github.com/rust-lang/crates.io-index"
699 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -35,6 +35,9 b' log = "0.4.8"'
35 memmap2 = { version = "0.5.3", features = ["stable_deref_trait"] }
35 memmap2 = { version = "0.5.3", features = ["stable_deref_trait"] }
36 zstd = "0.5.3"
36 zstd = "0.5.3"
37 format-bytes = "0.3.0"
37 format-bytes = "0.3.0"
38 # once_cell 1.15 uses edition 2021, while the heptapod CI
39 # uses an old version of Cargo that doesn't support it.
40 once_cell = "=1.14.0"
38
41
39 # We don't use the `miniz-oxide` backend to not change rhg benchmarks and until
42 # We don't use the `miniz-oxide` backend to not change rhg benchmarks and until
40 # we have a clearer view of which backend is the fastest.
43 # we have a clearer view of which backend is the fastest.
@@ -20,6 +20,7 b' 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 once_cell::sync::OnceCell;
23 use rayon::prelude::*;
24 use rayon::prelude::*;
24 use sha1::{Digest, Sha1};
25 use sha1::{Digest, Sha1};
25 use std::borrow::Cow;
26 use std::borrow::Cow;
@@ -126,14 +127,14 b" pub fn status<'dirstate>("
126 };
127 };
127 let is_at_repo_root = true;
128 let is_at_repo_root = true;
128 let hg_path = &BorrowedPath::OnDisk(HgPath::new(""));
129 let hg_path = &BorrowedPath::OnDisk(HgPath::new(""));
129 let has_ignored_ancestor = false;
130 let has_ignored_ancestor = HasIgnoredAncestor::create(None, hg_path);
130 let root_cached_mtime = None;
131 let root_cached_mtime = None;
131 let root_dir_metadata = None;
132 let root_dir_metadata = None;
132 // If the path we have for the repository root is a symlink, do follow it.
133 // If the path we have for the repository root is a symlink, do follow it.
133 // (As opposed to symlinks within the working directory which are not
134 // (As opposed to symlinks within the working directory which are not
134 // followed, using `std::fs::symlink_metadata`.)
135 // followed, using `std::fs::symlink_metadata`.)
135 common.traverse_fs_directory_and_dirstate(
136 common.traverse_fs_directory_and_dirstate(
136 has_ignored_ancestor,
137 &has_ignored_ancestor,
137 dmap.root.as_ref(),
138 dmap.root.as_ref(),
138 hg_path,
139 hg_path,
139 &root_dir,
140 &root_dir,
@@ -196,6 +197,40 b' enum Outcome {'
196 Unsure,
197 Unsure,
197 }
198 }
198
199
200 /// Lazy computation of whether a given path has a hgignored
201 /// ancestor.
202 struct HasIgnoredAncestor<'a> {
203 /// `path` and `parent` constitute the inputs to the computation,
204 /// `cache` stores the outcome.
205 path: &'a HgPath,
206 parent: Option<&'a HasIgnoredAncestor<'a>>,
207 cache: OnceCell<bool>,
208 }
209
210 impl<'a> HasIgnoredAncestor<'a> {
211 fn create(
212 parent: Option<&'a HasIgnoredAncestor<'a>>,
213 path: &'a HgPath,
214 ) -> HasIgnoredAncestor<'a> {
215 Self {
216 path,
217 parent,
218 cache: OnceCell::new(),
219 }
220 }
221
222 fn force<'b>(&self, ignore_fn: &IgnoreFnType<'b>) -> bool {
223 match self.parent {
224 None => false,
225 Some(parent) => {
226 *(parent.cache.get_or_init(|| {
227 parent.force(ignore_fn) || ignore_fn(&self.path)
228 }))
229 }
230 }
231 }
232 }
233
199 impl<'a, 'tree, 'on_disk> StatusCommon<'a, 'tree, 'on_disk> {
234 impl<'a, 'tree, 'on_disk> StatusCommon<'a, 'tree, 'on_disk> {
200 fn push_outcome(
235 fn push_outcome(
201 &self,
236 &self,
@@ -318,9 +353,9 b" impl<'a, 'tree, 'on_disk> StatusCommon<'"
318
353
319 /// Returns whether all child entries of the filesystem directory have a
354 /// Returns whether all child entries of the filesystem directory have a
320 /// corresponding dirstate node or are ignored.
355 /// corresponding dirstate node or are ignored.
321 fn traverse_fs_directory_and_dirstate(
356 fn traverse_fs_directory_and_dirstate<'ancestor>(
322 &self,
357 &self,
323 has_ignored_ancestor: bool,
358 has_ignored_ancestor: &'ancestor HasIgnoredAncestor<'ancestor>,
324 dirstate_nodes: ChildNodesRef<'tree, 'on_disk>,
359 dirstate_nodes: ChildNodesRef<'tree, 'on_disk>,
325 directory_hg_path: &BorrowedPath<'tree, 'on_disk>,
360 directory_hg_path: &BorrowedPath<'tree, 'on_disk>,
326 directory_fs_path: &Path,
361 directory_fs_path: &Path,
@@ -418,7 +453,7 b" impl<'a, 'tree, 'on_disk> StatusCommon<'"
418 }
453 }
419 Right(fs_entry) => {
454 Right(fs_entry) => {
420 has_dirstate_node_or_is_ignored = self.traverse_fs_only(
455 has_dirstate_node_or_is_ignored = self.traverse_fs_only(
421 has_ignored_ancestor,
456 has_ignored_ancestor.force(&self.ignore_fn),
422 directory_hg_path,
457 directory_hg_path,
423 fs_entry,
458 fs_entry,
424 )
459 )
@@ -429,12 +464,12 b" impl<'a, 'tree, 'on_disk> StatusCommon<'"
429 .try_reduce(|| true, |a, b| Ok(a && b))
464 .try_reduce(|| true, |a, b| Ok(a && b))
430 }
465 }
431
466
432 fn traverse_fs_and_dirstate(
467 fn traverse_fs_and_dirstate<'ancestor>(
433 &self,
468 &self,
434 fs_path: &Path,
469 fs_path: &Path,
435 fs_metadata: &std::fs::Metadata,
470 fs_metadata: &std::fs::Metadata,
436 dirstate_node: NodeRef<'tree, 'on_disk>,
471 dirstate_node: NodeRef<'tree, 'on_disk>,
437 has_ignored_ancestor: bool,
472 has_ignored_ancestor: &'ancestor HasIgnoredAncestor<'ancestor>,
438 ) -> Result<(), DirstateV2ParseError> {
473 ) -> Result<(), DirstateV2ParseError> {
439 self.check_for_outdated_directory_cache(&dirstate_node)?;
474 self.check_for_outdated_directory_cache(&dirstate_node)?;
440 let hg_path = &dirstate_node.full_path_borrowed(self.dmap.on_disk)?;
475 let hg_path = &dirstate_node.full_path_borrowed(self.dmap.on_disk)?;
@@ -454,11 +489,14 b" impl<'a, 'tree, 'on_disk> StatusCommon<'"
454 .traversed
489 .traversed
455 .push(hg_path.detach_from_tree())
490 .push(hg_path.detach_from_tree())
456 }
491 }
457 let is_ignored = has_ignored_ancestor || (self.ignore_fn)(hg_path);
492 let is_ignored = HasIgnoredAncestor::create(
493 Some(&has_ignored_ancestor),
494 hg_path,
495 );
458 let is_at_repo_root = false;
496 let is_at_repo_root = false;
459 let children_all_have_dirstate_node_or_are_ignored = self
497 let children_all_have_dirstate_node_or_are_ignored = self
460 .traverse_fs_directory_and_dirstate(
498 .traverse_fs_directory_and_dirstate(
461 is_ignored,
499 &is_ignored,
462 dirstate_node.children(self.dmap.on_disk)?,
500 dirstate_node.children(self.dmap.on_disk)?,
463 hg_path,
501 hg_path,
464 fs_path,
502 fs_path,
@@ -472,14 +510,14 b" impl<'a, 'tree, 'on_disk> StatusCommon<'"
472 dirstate_node,
510 dirstate_node,
473 )?
511 )?
474 } else {
512 } else {
475 if file_or_symlink && self.matcher.matches(hg_path) {
513 if file_or_symlink && self.matcher.matches(&hg_path) {
476 if let Some(entry) = dirstate_node.entry()? {
514 if let Some(entry) = dirstate_node.entry()? {
477 if !entry.any_tracked() {
515 if !entry.any_tracked() {
478 // Forward-compat if we start tracking unknown/ignored
516 // Forward-compat if we start tracking unknown/ignored
479 // files for caching reasons
517 // files for caching reasons
480 self.mark_unknown_or_ignored(
518 self.mark_unknown_or_ignored(
481 has_ignored_ancestor,
519 has_ignored_ancestor.force(&self.ignore_fn),
482 hg_path,
520 &hg_path,
483 );
521 );
484 }
522 }
485 if entry.added() {
523 if entry.added() {
@@ -495,7 +533,7 b" impl<'a, 'tree, 'on_disk> StatusCommon<'"
495 // `node.entry.is_none()` indicates a "directory"
533 // `node.entry.is_none()` indicates a "directory"
496 // node, but the filesystem has a file
534 // node, but the filesystem has a file
497 self.mark_unknown_or_ignored(
535 self.mark_unknown_or_ignored(
498 has_ignored_ancestor,
536 has_ignored_ancestor.force(&self.ignore_fn),
499 hg_path,
537 hg_path,
500 );
538 );
501 }
539 }
General Comments 0
You need to be logged in to leave comments. Login now