working_copy: update file states in bulk

This helps migrate BTreeMap<RepoPath, _> to sorted Vec.
This commit is contained in:
Yuya Nishihara 2023-11-27 13:55:40 +09:00
parent c9150d02fc
commit 9292af5e52

View file

@ -672,12 +672,12 @@ impl TreeState {
) )
})?; })?;
let file_states = self.file_states.make_mut();
let mut tree_builder = MergedTreeBuilder::new(self.tree_id.clone()); let mut tree_builder = MergedTreeBuilder::new(self.tree_id.clone());
let mut deleted_files: HashSet<_> = let mut deleted_files: HashSet<_> =
trace_span!("collecting existing files").in_scope(|| { trace_span!("collecting existing files").in_scope(|| {
// Since file_states shouldn't contain files excluded by the sparse patterns, // Since file_states shouldn't contain files excluded by the sparse patterns,
// fsmonitor_matcher here is identical to the intersected matcher. // fsmonitor_matcher here is identical to the intersected matcher.
let file_states = self.file_states.get_or_load();
file_states file_states
.iter() .iter()
.filter(|&(path, state)| { .filter(|&(path, state)| {
@ -692,24 +692,26 @@ impl TreeState {
} }
Ok(()) Ok(())
})?; })?;
trace_span!("process file states").in_scope(|| {
while let Ok((path, file_state)) = file_states_rx.recv() {
is_dirty = true;
file_states.insert(path, file_state);
}
});
trace_span!("process present files").in_scope(|| { trace_span!("process present files").in_scope(|| {
while let Ok(path) = present_files_rx.recv() { while let Ok(path) = present_files_rx.recv() {
deleted_files.remove(&path); deleted_files.remove(&path);
} }
}); });
trace_span!("process deleted files").in_scope(|| { trace_span!("process deleted tree entries").in_scope(|| {
is_dirty |= !deleted_files.is_empty();
for file in &deleted_files { for file in &deleted_files {
is_dirty = true;
file_states.remove(file);
tree_builder.set_or_remove(file.clone(), Merge::absent()); tree_builder.set_or_remove(file.clone(), Merge::absent());
} }
}); });
trace_span!("process file states").in_scope(|| {
let changed_file_states = file_states_rx.iter().collect_vec();
is_dirty |= !changed_file_states.is_empty();
let file_states = self.file_states.make_mut();
file_states.extend(changed_file_states);
for file in &deleted_files {
file_states.remove(file);
}
});
trace_span!("write tree").in_scope(|| { trace_span!("write tree").in_scope(|| {
let new_tree_id = tree_builder.write_tree(&self.store).unwrap(); let new_tree_id = tree_builder.write_tree(&self.store).unwrap();
is_dirty |= new_tree_id != self.tree_id; is_dirty |= new_tree_id != self.tree_id;
@ -1205,6 +1207,8 @@ impl TreeState {
removed_files: 0, removed_files: 0,
skipped_files: 0, skipped_files: 0,
}; };
let mut changed_file_states = Vec::new();
let mut deleted_files = HashSet::new();
let mut diff_stream = old_tree.diff_stream(new_tree, matcher); let mut diff_stream = old_tree.diff_stream(new_tree, matcher);
while let Some((path, diff)) = diff_stream.next().await { while let Some((path, diff)) = diff_stream.next().await {
let (before, after) = diff?; let (before, after) = diff?;
@ -1221,18 +1225,14 @@ impl TreeState {
fs::remove_file(&disk_path).ok(); fs::remove_file(&disk_path).ok();
} }
if before.is_absent() && disk_path.exists() { if before.is_absent() && disk_path.exists() {
self.file_states changed_file_states.push((path, FileState::placeholder()));
.make_mut()
.insert(path, FileState::placeholder());
stats.skipped_files += 1; stats.skipped_files += 1;
continue; continue;
} }
if after.is_present() { if after.is_present() {
let skip = create_parent_dirs(&self.working_copy_path, &path)?; let skip = create_parent_dirs(&self.working_copy_path, &path)?;
if skip { if skip {
self.file_states changed_file_states.push((path, FileState::placeholder()));
.make_mut()
.insert(path, FileState::placeholder());
stats.skipped_files += 1; stats.skipped_files += 1;
continue; continue;
} }
@ -1248,7 +1248,7 @@ impl TreeState {
} }
parent_dir = parent_dir.parent().unwrap(); parent_dir = parent_dir.parent().unwrap();
} }
self.file_states.make_mut().remove(&path); deleted_files.insert(path);
continue; continue;
} }
MaterializedTreeValue::File { MaterializedTreeValue::File {
@ -1270,7 +1270,12 @@ impl TreeState {
self.write_conflict(&disk_path, contents)? self.write_conflict(&disk_path, contents)?
} }
}; };
self.file_states.make_mut().insert(path, file_state); changed_file_states.push((path, file_state));
}
let file_states = self.file_states.make_mut();
file_states.extend(changed_file_states);
for file in &deleted_files {
file_states.remove(file);
} }
Ok(stats) Ok(stats)
} }
@ -1284,11 +1289,13 @@ impl TreeState {
})?; })?;
let matcher = self.sparse_matcher(); let matcher = self.sparse_matcher();
let mut changed_file_states = Vec::new();
let mut deleted_files = HashSet::new();
let mut diff_stream = old_tree.diff_stream(new_tree, matcher.as_ref()); let mut diff_stream = old_tree.diff_stream(new_tree, matcher.as_ref());
while let Some((path, diff)) = diff_stream.next().await { while let Some((path, diff)) = diff_stream.next().await {
let (_before, after) = diff?; let (_before, after) = diff?;
if after.is_absent() { if after.is_absent() {
self.file_states.make_mut().remove(&path); deleted_files.insert(path);
} else { } else {
let file_type = match after.into_resolved() { let file_type = match after.into_resolved() {
Ok(value) => match value.unwrap() { Ok(value) => match value.unwrap() {
@ -1320,9 +1327,14 @@ impl TreeState {
mtime: MillisSinceEpoch(0), mtime: MillisSinceEpoch(0),
size: 0, size: 0,
}; };
self.file_states.make_mut().insert(path.clone(), file_state); changed_file_states.push((path, file_state));
} }
} }
let file_states = self.file_states.make_mut();
file_states.extend(changed_file_states);
for file in &deleted_files {
file_states.remove(file);
}
self.tree_id = new_tree.id(); self.tree_id = new_tree.id();
Ok(()) Ok(())
} }