Conservatively report fs events that occurred during initial worktree scan
Co-authored-by: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
61172c8478
commit
be5868e1c0
2 changed files with 49 additions and 16 deletions
|
@ -4604,7 +4604,10 @@ impl Project {
|
|||
typ: match change {
|
||||
PathChange::Added => lsp::FileChangeType::CREATED,
|
||||
PathChange::Removed => lsp::FileChangeType::DELETED,
|
||||
PathChange::Updated => lsp::FileChangeType::CHANGED,
|
||||
PathChange::Updated
|
||||
| PathChange::AddedOrUpdated => {
|
||||
lsp::FileChangeType::CHANGED
|
||||
}
|
||||
},
|
||||
})
|
||||
.collect(),
|
||||
|
|
|
@ -610,8 +610,6 @@ impl LocalWorktree {
|
|||
}
|
||||
}));
|
||||
|
||||
cx.emit(Event::UpdatedEntries(Default::default()));
|
||||
|
||||
if !updated_repos.is_empty() {
|
||||
cx.emit(Event::UpdatedGitRepositories(updated_repos));
|
||||
}
|
||||
|
@ -2072,6 +2070,7 @@ pub enum PathChange {
|
|||
Added,
|
||||
Removed,
|
||||
Updated,
|
||||
AddedOrUpdated,
|
||||
}
|
||||
|
||||
impl Entry {
|
||||
|
@ -2283,21 +2282,37 @@ impl BackgroundScanner {
|
|||
|
||||
futures::pin_mut!(events_rx);
|
||||
|
||||
// Process any events that occurred while performing the initial scan. These
|
||||
// events can't be reported as precisely, because there is no snapshot of the
|
||||
// worktree before they occurred.
|
||||
if let Some(mut events) = events_rx.next().await {
|
||||
while let Poll::Ready(Some(additional_events)) = futures::poll!(events_rx.next()) {
|
||||
events.extend(additional_events);
|
||||
}
|
||||
if self.notify.unbounded_send(ScanState::Updating).is_err() {
|
||||
return;
|
||||
}
|
||||
if !self.process_events(events, true).await {
|
||||
return;
|
||||
}
|
||||
if self.notify.unbounded_send(ScanState::Idle).is_err() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Continue processing events until the worktree is dropped.
|
||||
while let Some(mut events) = events_rx.next().await {
|
||||
while let Poll::Ready(Some(additional_events)) = futures::poll!(events_rx.next()) {
|
||||
events.extend(additional_events);
|
||||
}
|
||||
|
||||
if self.notify.unbounded_send(ScanState::Updating).is_err() {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.process_events(events).await {
|
||||
break;
|
||||
if !self.process_events(events, false).await {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.notify.unbounded_send(ScanState::Idle).is_err() {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2508,7 +2523,11 @@ impl BackgroundScanner {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn process_events(&mut self, mut events: Vec<fsevent::Event>) -> bool {
|
||||
async fn process_events(
|
||||
&mut self,
|
||||
mut events: Vec<fsevent::Event>,
|
||||
received_before_initialized: bool,
|
||||
) -> bool {
|
||||
events.sort_unstable_by(|a, b| a.path.cmp(&b.path));
|
||||
events.dedup_by(|a, b| a.path.starts_with(&b.path));
|
||||
|
||||
|
@ -2632,7 +2651,7 @@ impl BackgroundScanner {
|
|||
|
||||
self.update_ignore_statuses().await;
|
||||
self.update_git_repositories();
|
||||
self.build_change_set(prev_snapshot, event_paths);
|
||||
self.build_change_set(prev_snapshot, event_paths, received_before_initialized);
|
||||
self.snapshot.lock().scan_completed();
|
||||
true
|
||||
}
|
||||
|
@ -2749,7 +2768,12 @@ impl BackgroundScanner {
|
|||
snapshot.entries_by_id.edit(entries_by_id_edits, &());
|
||||
}
|
||||
|
||||
fn build_change_set(&self, old_snapshot: Snapshot, event_paths: Vec<Arc<Path>>) {
|
||||
fn build_change_set(
|
||||
&self,
|
||||
old_snapshot: Snapshot,
|
||||
event_paths: Vec<Arc<Path>>,
|
||||
received_before_initialized: bool,
|
||||
) {
|
||||
let new_snapshot = self.snapshot.lock();
|
||||
let mut old_paths = old_snapshot.entries_by_path.cursor::<PathKey>();
|
||||
let mut new_paths = new_snapshot.entries_by_path.cursor::<PathKey>();
|
||||
|
@ -2777,7 +2801,13 @@ impl BackgroundScanner {
|
|||
old_paths.next(&());
|
||||
}
|
||||
Ordering::Equal => {
|
||||
if old_entry.mtime != new_entry.mtime {
|
||||
if received_before_initialized {
|
||||
// If the worktree was not fully initialized when this event was generated,
|
||||
// we can't know whether this entry was added during the scan or whether
|
||||
// it was merely updated.
|
||||
change_set
|
||||
.insert(old_entry.path.clone(), PathChange::AddedOrUpdated);
|
||||
} else if old_entry.mtime != new_entry.mtime {
|
||||
change_set.insert(old_entry.path.clone(), PathChange::Updated);
|
||||
}
|
||||
old_paths.next(&());
|
||||
|
@ -3604,7 +3634,7 @@ mod tests {
|
|||
let len = rng.gen_range(0..=events.len());
|
||||
let to_deliver = events.drain(0..len).collect::<Vec<_>>();
|
||||
log::info!("Delivering events: {:#?}", to_deliver);
|
||||
smol::block_on(scanner.process_events(to_deliver));
|
||||
smol::block_on(scanner.process_events(to_deliver, false));
|
||||
scanner.snapshot().check_invariants();
|
||||
} else {
|
||||
events.extend(randomly_mutate_tree(root_dir.path(), 0.6, &mut rng).unwrap());
|
||||
|
@ -3616,7 +3646,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
log::info!("Quiescing: {:#?}", events);
|
||||
smol::block_on(scanner.process_events(events));
|
||||
smol::block_on(scanner.process_events(events, false));
|
||||
scanner.snapshot().check_invariants();
|
||||
|
||||
let (notify_tx, _notify_rx) = mpsc::unbounded();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue