mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-26 03:59:55 +00:00
🎨 Don't store path changes statefully on the background scanner
This commit is contained in:
parent
3ff5aee4a1
commit
89e99d2902
1 changed files with 54 additions and 61 deletions
|
@ -1,12 +1,12 @@
|
|||
use super::{ignore::IgnoreStack, DiagnosticSummary};
|
||||
use crate::{copy_recursive, ProjectEntryId, RemoveOptions};
|
||||
use crate::{
|
||||
copy_recursive, ignore::IgnoreStack, DiagnosticSummary, ProjectEntryId, RemoveOptions,
|
||||
};
|
||||
use ::ignore::gitignore::{Gitignore, GitignoreBuilder};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use client::{proto, Client};
|
||||
use clock::ReplicaId;
|
||||
use collections::{HashMap, VecDeque};
|
||||
use fs::LineEnding;
|
||||
use fs::{repository::GitRepository, Fs};
|
||||
use fs::{repository::GitRepository, Fs, LineEnding};
|
||||
use futures::{
|
||||
channel::{
|
||||
mpsc::{self, UnboundedReceiver, UnboundedSender},
|
||||
|
@ -20,17 +20,16 @@ use gpui::{
|
|||
executor, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext,
|
||||
Task,
|
||||
};
|
||||
use language::File as _;
|
||||
use language::{
|
||||
proto::{
|
||||
deserialize_fingerprint, deserialize_version, serialize_fingerprint, serialize_line_ending,
|
||||
serialize_version,
|
||||
},
|
||||
Buffer, DiagnosticEntry, PointUtf16, Rope, RopeFingerprint, Unclipped,
|
||||
Buffer, DiagnosticEntry, File as _, PointUtf16, Rope, RopeFingerprint, Unclipped,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use postage::barrier;
|
||||
use postage::{
|
||||
barrier,
|
||||
prelude::{Sink as _, Stream as _},
|
||||
watch,
|
||||
};
|
||||
|
@ -50,8 +49,7 @@ use std::{
|
|||
time::{Duration, SystemTime},
|
||||
};
|
||||
use sum_tree::{Bias, Edit, SeekTarget, SumTree, TreeMap, TreeSet};
|
||||
use util::paths::HOME;
|
||||
use util::{ResultExt, TryFutureExt};
|
||||
use util::{paths::HOME, ResultExt, TryFutureExt};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
|
||||
pub struct WorktreeId(usize);
|
||||
|
@ -2141,7 +2139,6 @@ impl<'a> sum_tree::Dimension<'a, EntrySummary> for PathKey {
|
|||
struct BackgroundScanner {
|
||||
fs: Arc<dyn Fs>,
|
||||
snapshot: Mutex<LocalSnapshot>,
|
||||
changes: HashMap<Arc<Path>, PathChange>,
|
||||
notify: UnboundedSender<ScanState>,
|
||||
executor: Arc<executor::Background>,
|
||||
}
|
||||
|
@ -2158,7 +2155,6 @@ impl BackgroundScanner {
|
|||
snapshot: Mutex::new(snapshot),
|
||||
notify,
|
||||
executor,
|
||||
changes: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2167,7 +2163,7 @@ impl BackgroundScanner {
|
|||
}
|
||||
|
||||
async fn run(
|
||||
mut self,
|
||||
self,
|
||||
events_rx: impl Stream<Item = Vec<fsevent::Event>>,
|
||||
mut changed_paths: UnboundedReceiver<(Vec<PathBuf>, barrier::Sender)>,
|
||||
) {
|
||||
|
@ -2312,32 +2308,31 @@ impl BackgroundScanner {
|
|||
while let Poll::Ready(Some(additional_events)) = futures::poll!(events_rx.next()) {
|
||||
events.extend(additional_events);
|
||||
}
|
||||
let abs_paths = events.into_iter().map(|e| e.path).collect();
|
||||
if self.notify.unbounded_send(ScanState::Updating).is_err() {
|
||||
return;
|
||||
}
|
||||
if !self
|
||||
.process_events(events.into_iter().map(|e| e.path).collect(), true)
|
||||
.await
|
||||
{
|
||||
return;
|
||||
}
|
||||
if self
|
||||
.notify
|
||||
.unbounded_send(ScanState::Updated {
|
||||
snapshot: self.snapshot.lock().clone(),
|
||||
changes: mem::take(&mut self.changes),
|
||||
barrier: None,
|
||||
})
|
||||
.is_err()
|
||||
{
|
||||
if let Some(changes) = self.process_events(abs_paths, true).await {
|
||||
if self
|
||||
.notify
|
||||
.unbounded_send(ScanState::Updated {
|
||||
snapshot: self.snapshot.lock().clone(),
|
||||
changes,
|
||||
barrier: None,
|
||||
})
|
||||
.is_err()
|
||||
{
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Continue processing events until the worktree is dropped.
|
||||
loop {
|
||||
let abs_paths;
|
||||
let barrier;
|
||||
let abs_paths;
|
||||
select_biased! {
|
||||
request = changed_paths.next().fuse() => {
|
||||
let Some((paths, b)) = request else { break };
|
||||
|
@ -2354,18 +2349,19 @@ impl BackgroundScanner {
|
|||
if self.notify.unbounded_send(ScanState::Updating).is_err() {
|
||||
return;
|
||||
}
|
||||
if !self.process_events(abs_paths, false).await {
|
||||
return;
|
||||
}
|
||||
if self
|
||||
.notify
|
||||
.unbounded_send(ScanState::Updated {
|
||||
snapshot: self.snapshot.lock().clone(),
|
||||
changes: mem::take(&mut self.changes),
|
||||
barrier,
|
||||
})
|
||||
.is_err()
|
||||
{
|
||||
if let Some(changes) = self.process_events(abs_paths, false).await {
|
||||
if self
|
||||
.notify
|
||||
.unbounded_send(ScanState::Updated {
|
||||
snapshot: self.snapshot.lock().clone(),
|
||||
changes,
|
||||
barrier,
|
||||
})
|
||||
.is_err()
|
||||
{
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2505,10 +2501,10 @@ impl BackgroundScanner {
|
|||
}
|
||||
|
||||
async fn process_events(
|
||||
&mut self,
|
||||
&self,
|
||||
abs_paths: Vec<PathBuf>,
|
||||
received_before_initialized: bool,
|
||||
) -> bool {
|
||||
) -> Option<HashMap<Arc<Path>, PathChange>> {
|
||||
let (scan_queue_tx, scan_queue_rx) = channel::unbounded();
|
||||
|
||||
let prev_snapshot = {
|
||||
|
@ -2517,14 +2513,9 @@ impl BackgroundScanner {
|
|||
snapshot.clone()
|
||||
};
|
||||
|
||||
let event_paths = if let Some(event_paths) = self
|
||||
let event_paths = self
|
||||
.update_entries_for_paths(abs_paths, Some(scan_queue_tx))
|
||||
.await
|
||||
{
|
||||
event_paths
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
.await?;
|
||||
|
||||
// Scan any directories that were created as part of this event batch.
|
||||
self.executor
|
||||
|
@ -2553,13 +2544,13 @@ impl BackgroundScanner {
|
|||
|
||||
self.update_ignore_statuses().await;
|
||||
self.update_git_repositories();
|
||||
self.build_change_set(
|
||||
let changes = self.build_change_set(
|
||||
prev_snapshot.snapshot,
|
||||
event_paths,
|
||||
received_before_initialized,
|
||||
);
|
||||
self.snapshot.lock().scan_completed();
|
||||
true
|
||||
Some(changes)
|
||||
}
|
||||
|
||||
async fn update_entries_for_paths(
|
||||
|
@ -2763,17 +2754,18 @@ impl BackgroundScanner {
|
|||
}
|
||||
|
||||
fn build_change_set(
|
||||
&mut self,
|
||||
&self,
|
||||
old_snapshot: Snapshot,
|
||||
event_paths: Vec<Arc<Path>>,
|
||||
received_before_initialized: bool,
|
||||
) {
|
||||
) -> HashMap<Arc<Path>, PathChange> {
|
||||
use PathChange::{Added, AddedOrUpdated, Removed, Updated};
|
||||
|
||||
let new_snapshot = self.snapshot.lock();
|
||||
let mut changes = HashMap::default();
|
||||
let mut old_paths = old_snapshot.entries_by_path.cursor::<PathKey>();
|
||||
let mut new_paths = new_snapshot.entries_by_path.cursor::<PathKey>();
|
||||
|
||||
use PathChange::{Added, AddedOrUpdated, Removed, Updated};
|
||||
|
||||
for path in event_paths {
|
||||
let path = PathKey(path);
|
||||
old_paths.seek(&path, Bias::Left, &());
|
||||
|
@ -2792,7 +2784,7 @@ impl BackgroundScanner {
|
|||
|
||||
match Ord::cmp(&old_entry.path, &new_entry.path) {
|
||||
Ordering::Less => {
|
||||
self.changes.insert(old_entry.path.clone(), Removed);
|
||||
changes.insert(old_entry.path.clone(), Removed);
|
||||
old_paths.next(&());
|
||||
}
|
||||
Ordering::Equal => {
|
||||
|
@ -2800,31 +2792,32 @@ impl BackgroundScanner {
|
|||
// 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.
|
||||
self.changes.insert(old_entry.path.clone(), AddedOrUpdated);
|
||||
changes.insert(old_entry.path.clone(), AddedOrUpdated);
|
||||
} else if old_entry.mtime != new_entry.mtime {
|
||||
self.changes.insert(old_entry.path.clone(), Updated);
|
||||
changes.insert(old_entry.path.clone(), Updated);
|
||||
}
|
||||
old_paths.next(&());
|
||||
new_paths.next(&());
|
||||
}
|
||||
Ordering::Greater => {
|
||||
self.changes.insert(new_entry.path.clone(), Added);
|
||||
changes.insert(new_entry.path.clone(), Added);
|
||||
new_paths.next(&());
|
||||
}
|
||||
}
|
||||
}
|
||||
(Some(old_entry), None) => {
|
||||
self.changes.insert(old_entry.path.clone(), Removed);
|
||||
changes.insert(old_entry.path.clone(), Removed);
|
||||
old_paths.next(&());
|
||||
}
|
||||
(None, Some(new_entry)) => {
|
||||
self.changes.insert(new_entry.path.clone(), Added);
|
||||
changes.insert(new_entry.path.clone(), Added);
|
||||
new_paths.next(&());
|
||||
}
|
||||
(None, None) => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
changes
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue