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