forked from mirrors/jj
perf: instrument some steps in snapshot
This commit is contained in:
parent
018bb88ec6
commit
1e28b312c6
1 changed files with 86 additions and 76 deletions
|
@ -34,7 +34,7 @@ use once_cell::unsync::OnceCell;
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tracing::instrument;
|
use tracing::{instrument, trace_span};
|
||||||
|
|
||||||
use crate::backend::{
|
use crate::backend::{
|
||||||
BackendError, ConflictId, FileId, MillisSinceEpoch, ObjectId, SymlinkId, TreeId, TreeValue,
|
BackendError, ConflictId, FileId, MillisSinceEpoch, ObjectId, SymlinkId, TreeId, TreeValue,
|
||||||
|
@ -602,13 +602,15 @@ impl TreeState {
|
||||||
let sparse_matcher = self.sparse_matcher();
|
let sparse_matcher = self.sparse_matcher();
|
||||||
let current_tree = self.store.get_tree(&RepoPath::root(), &self.tree_id)?;
|
let current_tree = self.store.get_tree(&RepoPath::root(), &self.tree_id)?;
|
||||||
let mut tree_builder = self.store.tree_builder(self.tree_id.clone());
|
let mut tree_builder = self.store.tree_builder(self.tree_id.clone());
|
||||||
let mut deleted_files: HashSet<_> = self
|
let mut deleted_files: HashSet<_> =
|
||||||
.file_states
|
trace_span!("collecting existing files").in_scope(|| {
|
||||||
.iter()
|
self.file_states
|
||||||
.filter_map(|(path, state)| {
|
.iter()
|
||||||
(state.file_type != FileType::GitSubmodule).then(|| path.clone())
|
.filter_map(|(path, state)| {
|
||||||
})
|
(state.file_type != FileType::GitSubmodule).then(|| path.clone())
|
||||||
.collect();
|
})
|
||||||
|
.collect()
|
||||||
|
});
|
||||||
|
|
||||||
let fsmonitor_clock_needs_save = fsmonitor_kind.is_some();
|
let fsmonitor_clock_needs_save = fsmonitor_kind.is_some();
|
||||||
let FsmonitorMatcher {
|
let FsmonitorMatcher {
|
||||||
|
@ -633,67 +635,71 @@ impl TreeState {
|
||||||
disk_dir: self.working_copy_path.clone(),
|
disk_dir: self.working_copy_path.clone(),
|
||||||
git_ignore: base_ignores,
|
git_ignore: base_ignores,
|
||||||
}];
|
}];
|
||||||
while let Some(WorkItem {
|
trace_span!("traverse filesystem").in_scope(|| -> Result<(), SnapshotError> {
|
||||||
dir,
|
while let Some(WorkItem {
|
||||||
disk_dir,
|
dir,
|
||||||
git_ignore,
|
disk_dir,
|
||||||
}) = work.pop()
|
git_ignore,
|
||||||
{
|
}) = work.pop()
|
||||||
if matcher.visit(&dir).is_nothing() {
|
{
|
||||||
continue;
|
if matcher.visit(&dir).is_nothing() {
|
||||||
}
|
|
||||||
let git_ignore = git_ignore
|
|
||||||
.chain_with_file(&dir.to_internal_dir_string(), disk_dir.join(".gitignore"));
|
|
||||||
for maybe_entry in disk_dir.read_dir().unwrap() {
|
|
||||||
let entry = maybe_entry.unwrap();
|
|
||||||
let file_type = entry.file_type().unwrap();
|
|
||||||
let file_name = entry.file_name();
|
|
||||||
let name = file_name
|
|
||||||
.to_str()
|
|
||||||
.ok_or_else(|| SnapshotError::InvalidUtf8Path {
|
|
||||||
path: file_name.clone(),
|
|
||||||
})?;
|
|
||||||
if name == ".jj" || name == ".git" {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let sub_path = dir.join(&RepoPathComponent::from(name));
|
let git_ignore = git_ignore
|
||||||
if let Some(file_state) = self.file_states.get(&sub_path) {
|
.chain_with_file(&dir.to_internal_dir_string(), disk_dir.join(".gitignore"));
|
||||||
if file_state.file_type == FileType::GitSubmodule {
|
for maybe_entry in disk_dir.read_dir().unwrap() {
|
||||||
|
let entry = maybe_entry.unwrap();
|
||||||
|
let file_type = entry.file_type().unwrap();
|
||||||
|
let file_name = entry.file_name();
|
||||||
|
let name =
|
||||||
|
file_name
|
||||||
|
.to_str()
|
||||||
|
.ok_or_else(|| SnapshotError::InvalidUtf8Path {
|
||||||
|
path: file_name.clone(),
|
||||||
|
})?;
|
||||||
|
if name == ".jj" || name == ".git" {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
let sub_path = dir.join(&RepoPathComponent::from(name));
|
||||||
|
if let Some(file_state) = self.file_states.get(&sub_path) {
|
||||||
if file_type.is_dir() {
|
if file_state.file_type == FileType::GitSubmodule {
|
||||||
// If the whole directory is ignored, skip it unless we're already tracking
|
continue;
|
||||||
// some file in it.
|
}
|
||||||
if git_ignore.matches_all_files_in(&sub_path.to_internal_dir_string())
|
}
|
||||||
&& !self.has_files_under(&sub_path)
|
|
||||||
{
|
if file_type.is_dir() {
|
||||||
continue;
|
// If the whole directory is ignored, skip it unless we're already tracking
|
||||||
}
|
// some file in it.
|
||||||
|
if git_ignore.matches_all_files_in(&sub_path.to_internal_dir_string())
|
||||||
work.push(WorkItem {
|
&& !self.has_files_under(&sub_path)
|
||||||
dir: sub_path,
|
{
|
||||||
disk_dir: entry.path(),
|
continue;
|
||||||
git_ignore: git_ignore.clone(),
|
}
|
||||||
});
|
|
||||||
} else {
|
work.push(WorkItem {
|
||||||
deleted_files.remove(&sub_path);
|
dir: sub_path,
|
||||||
if matcher.matches(&sub_path) {
|
disk_dir: entry.path(),
|
||||||
if let Some(progress) = progress {
|
git_ignore: git_ignore.clone(),
|
||||||
progress(&sub_path);
|
});
|
||||||
|
} else {
|
||||||
|
deleted_files.remove(&sub_path);
|
||||||
|
if matcher.matches(&sub_path) {
|
||||||
|
if let Some(progress) = progress {
|
||||||
|
progress(&sub_path);
|
||||||
|
}
|
||||||
|
self.update_file_state(
|
||||||
|
sub_path,
|
||||||
|
&entry,
|
||||||
|
git_ignore.as_ref(),
|
||||||
|
¤t_tree,
|
||||||
|
&mut tree_builder,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
self.update_file_state(
|
|
||||||
sub_path,
|
|
||||||
&entry,
|
|
||||||
git_ignore.as_ref(),
|
|
||||||
¤t_tree,
|
|
||||||
&mut tree_builder,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
for file in &deleted_files {
|
for file in &deleted_files {
|
||||||
self.file_states.remove(file);
|
self.file_states.remove(file);
|
||||||
|
@ -734,22 +740,26 @@ impl TreeState {
|
||||||
let matcher: Option<Box<dyn Matcher>> = match changed_files {
|
let matcher: Option<Box<dyn Matcher>> = match changed_files {
|
||||||
None => None,
|
None => None,
|
||||||
Some(changed_files) => {
|
Some(changed_files) => {
|
||||||
let repo_paths = changed_files
|
let repo_paths = trace_span!("processing fsmonitor paths").in_scope(|| {
|
||||||
.into_iter()
|
changed_files
|
||||||
.filter_map(|path| {
|
.into_iter()
|
||||||
match RepoPath::parse_fs_path(
|
.filter_map(|path| {
|
||||||
&self.working_copy_path,
|
match RepoPath::parse_fs_path(
|
||||||
&self.working_copy_path,
|
&self.working_copy_path,
|
||||||
path,
|
&self.working_copy_path,
|
||||||
) {
|
path,
|
||||||
Ok(repo_path) => Some(repo_path),
|
) {
|
||||||
Err(FsPathParseError::InputNotInRepo(_)) => None,
|
Ok(repo_path) => Some(repo_path),
|
||||||
}
|
Err(FsPathParseError::InputNotInRepo(_)) => None,
|
||||||
})
|
}
|
||||||
.collect_vec();
|
})
|
||||||
|
.collect_vec()
|
||||||
|
});
|
||||||
|
|
||||||
let repo_path_set: HashSet<_> = repo_paths.iter().collect();
|
trace_span!("retaining fsmonitor paths").in_scope(|| {
|
||||||
deleted_files.retain(|path| repo_path_set.contains(path));
|
let repo_path_set: HashSet<_> = repo_paths.iter().collect();
|
||||||
|
deleted_files.retain(|path| repo_path_set.contains(path));
|
||||||
|
});
|
||||||
|
|
||||||
Some(Box::new(PrefixMatcher::new(&repo_paths)))
|
Some(Box::new(PrefixMatcher::new(&repo_paths)))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue