Remove worktree and project notifies (#26244)
This reduces the number of multibuffer syncs from 100,000 to 20,000. Before this change each editor individually observed the project, so literally any project change was amplified by the number of editors you had open. Now editors listen to their buffers instead of the project, and other users of `cx.observe` on the project have been updated to use specific events to reduce churn. Follow up to #26237 Release Notes: - Improved performance of Zed in large repos with lots of file system events. --------- Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
co-authored by
Max Brunsfeld
parent
aef84d453a
commit
80fb88520f
@@ -3,7 +3,7 @@ use std::{path::Path, sync::Arc};
|
||||
use util::ResultExt;
|
||||
|
||||
use collections::HashMap;
|
||||
use gpui::{App, AppContext as _, Context, Entity, Task};
|
||||
use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Task};
|
||||
use settings::Settings as _;
|
||||
use worktree::WorktreeId;
|
||||
|
||||
@@ -19,6 +19,12 @@ pub struct ProjectEnvironment {
|
||||
environment_error_messages: HashMap<WorktreeId, EnvironmentErrorMessage>,
|
||||
}
|
||||
|
||||
pub enum ProjectEnvironmentEvent {
|
||||
ErrorsUpdated,
|
||||
}
|
||||
|
||||
impl EventEmitter<ProjectEnvironmentEvent> for ProjectEnvironment {}
|
||||
|
||||
impl ProjectEnvironment {
|
||||
pub fn new(
|
||||
worktree_store: &Entity<WorktreeStore>,
|
||||
@@ -65,8 +71,13 @@ impl ProjectEnvironment {
|
||||
self.environment_error_messages.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn remove_environment_error(&mut self, worktree_id: WorktreeId) {
|
||||
pub(crate) fn remove_environment_error(
|
||||
&mut self,
|
||||
worktree_id: WorktreeId,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.environment_error_messages.remove(&worktree_id);
|
||||
cx.emit(ProjectEnvironmentEvent::ErrorsUpdated);
|
||||
}
|
||||
|
||||
/// Returns the project environment, if possible.
|
||||
@@ -158,8 +169,9 @@ impl ProjectEnvironment {
|
||||
}
|
||||
|
||||
if let Some(error) = error_message {
|
||||
this.update(&mut cx, |this, _| {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.environment_error_messages.insert(worktree_id, error);
|
||||
cx.emit(ProjectEnvironmentEvent::ErrorsUpdated)
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
|
||||
@@ -6667,33 +6667,19 @@ impl LspStore {
|
||||
cx,
|
||||
);
|
||||
}
|
||||
lsp::WorkDoneProgress::Report(report) => {
|
||||
if self.on_lsp_work_progress(
|
||||
language_server_id,
|
||||
token.clone(),
|
||||
LanguageServerProgress {
|
||||
title: None,
|
||||
is_disk_based_diagnostics_progress,
|
||||
is_cancellable: report.cancellable.unwrap_or(false),
|
||||
message: report.message.clone(),
|
||||
percentage: report.percentage.map(|p| p as usize),
|
||||
last_update_at: cx.background_executor().now(),
|
||||
},
|
||||
cx,
|
||||
) {
|
||||
cx.emit(LspStoreEvent::LanguageServerUpdate {
|
||||
language_server_id,
|
||||
message: proto::update_language_server::Variant::WorkProgress(
|
||||
proto::LspWorkProgress {
|
||||
token,
|
||||
message: report.message,
|
||||
percentage: report.percentage,
|
||||
is_cancellable: report.cancellable,
|
||||
},
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
|
||||
language_server_id,
|
||||
token,
|
||||
LanguageServerProgress {
|
||||
title: None,
|
||||
is_disk_based_diagnostics_progress,
|
||||
is_cancellable: report.cancellable.unwrap_or(false),
|
||||
message: report.message,
|
||||
percentage: report.percentage.map(|p| p as usize),
|
||||
last_update_at: cx.background_executor().now(),
|
||||
},
|
||||
cx,
|
||||
),
|
||||
lsp::WorkDoneProgress::End(_) => {
|
||||
language_server_status.progress_tokens.remove(&token);
|
||||
self.on_lsp_work_end(language_server_id, token.clone(), cx);
|
||||
@@ -6733,13 +6719,13 @@ impl LspStore {
|
||||
token: String,
|
||||
progress: LanguageServerProgress,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
) {
|
||||
let mut did_update = false;
|
||||
if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
|
||||
match status.pending_work.entry(token) {
|
||||
match status.pending_work.entry(token.clone()) {
|
||||
btree_map::Entry::Vacant(entry) => {
|
||||
entry.insert(progress);
|
||||
cx.notify();
|
||||
return true;
|
||||
entry.insert(progress.clone());
|
||||
did_update = true;
|
||||
}
|
||||
btree_map::Entry::Occupied(mut entry) => {
|
||||
let entry = entry.get_mut();
|
||||
@@ -6748,7 +6734,7 @@ impl LspStore {
|
||||
{
|
||||
entry.last_update_at = progress.last_update_at;
|
||||
if progress.message.is_some() {
|
||||
entry.message = progress.message;
|
||||
entry.message = progress.message.clone();
|
||||
}
|
||||
if progress.percentage.is_some() {
|
||||
entry.percentage = progress.percentage;
|
||||
@@ -6756,14 +6742,25 @@ impl LspStore {
|
||||
if progress.is_cancellable != entry.is_cancellable {
|
||||
entry.is_cancellable = progress.is_cancellable;
|
||||
}
|
||||
cx.notify();
|
||||
return true;
|
||||
did_update = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
if did_update {
|
||||
cx.emit(LspStoreEvent::LanguageServerUpdate {
|
||||
language_server_id,
|
||||
message: proto::update_language_server::Variant::WorkProgress(
|
||||
proto::LspWorkProgress {
|
||||
token,
|
||||
message: progress.message,
|
||||
percentage: progress.percentage.map(|p| p as u32),
|
||||
is_cancellable: Some(progress.is_cancellable),
|
||||
},
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn on_lsp_work_end(
|
||||
|
||||
@@ -22,7 +22,7 @@ mod project_tests;
|
||||
mod direnv;
|
||||
mod environment;
|
||||
use buffer_diff::BufferDiff;
|
||||
pub use environment::EnvironmentErrorMessage;
|
||||
pub use environment::{EnvironmentErrorMessage, ProjectEnvironmentEvent};
|
||||
use git::Repository;
|
||||
pub mod search_history;
|
||||
mod yarn;
|
||||
@@ -886,7 +886,6 @@ impl Project {
|
||||
});
|
||||
|
||||
cx.subscribe(&ssh, Self::on_ssh_event).detach();
|
||||
cx.observe(&ssh, |_, _, cx| cx.notify()).detach();
|
||||
|
||||
let this = Self {
|
||||
buffer_ordered_messages_tx: tx,
|
||||
@@ -1371,9 +1370,9 @@ impl Project {
|
||||
self.environment.read(cx).environment_errors()
|
||||
}
|
||||
|
||||
pub fn remove_environment_error(&mut self, cx: &mut Context<Self>, worktree_id: WorktreeId) {
|
||||
self.environment.update(cx, |environment, _| {
|
||||
environment.remove_environment_error(worktree_id);
|
||||
pub fn remove_environment_error(&mut self, worktree_id: WorktreeId, cx: &mut Context<Self>) {
|
||||
self.environment.update(cx, |environment, cx| {
|
||||
environment.remove_environment_error(worktree_id, cx);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1764,7 +1763,6 @@ impl Project {
|
||||
};
|
||||
|
||||
cx.emit(Event::RemoteIdChanged(Some(project_id)));
|
||||
cx.notify();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1780,7 +1778,6 @@ impl Project {
|
||||
self.worktree_store.update(cx, |worktree_store, cx| {
|
||||
worktree_store.send_project_updates(cx);
|
||||
});
|
||||
cx.notify();
|
||||
cx.emit(Event::Reshared);
|
||||
Ok(())
|
||||
}
|
||||
@@ -1810,13 +1807,12 @@ impl Project {
|
||||
self.enqueue_buffer_ordered_message(BufferOrderedMessage::Resync)
|
||||
.unwrap();
|
||||
cx.emit(Event::Rejoined);
|
||||
cx.notify();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn unshare(&mut self, cx: &mut Context<Self>) -> Result<()> {
|
||||
self.unshare_internal(cx)?;
|
||||
cx.notify();
|
||||
cx.emit(Event::RemoteIdChanged(None));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1860,7 +1856,6 @@ impl Project {
|
||||
}
|
||||
self.disconnected_from_host_internal(cx);
|
||||
cx.emit(Event::DisconnectedFromHost);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn set_role(&mut self, role: proto::ChannelRole, cx: &mut Context<Self>) {
|
||||
@@ -2509,15 +2504,11 @@ impl Project {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_worktree_added(&mut self, worktree: &Entity<Worktree>, cx: &mut Context<Self>) {
|
||||
{
|
||||
let mut remotely_created_models = self.remotely_created_models.lock();
|
||||
if remotely_created_models.retain_count > 0 {
|
||||
remotely_created_models.worktrees.push(worktree.clone())
|
||||
}
|
||||
fn on_worktree_added(&mut self, worktree: &Entity<Worktree>, _: &mut Context<Self>) {
|
||||
let mut remotely_created_models = self.remotely_created_models.lock();
|
||||
if remotely_created_models.retain_count > 0 {
|
||||
remotely_created_models.worktrees.push(worktree.clone())
|
||||
}
|
||||
cx.observe(worktree, |_, _, cx| cx.notify()).detach();
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn on_worktree_released(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
|
||||
@@ -2529,8 +2520,6 @@ impl Project {
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn on_buffer_event(
|
||||
@@ -3804,7 +3793,6 @@ impl Project {
|
||||
cx.emit(Event::CollaboratorJoined(collaborator.peer_id));
|
||||
this.collaborators
|
||||
.insert(collaborator.peer_id, collaborator);
|
||||
cx.notify();
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
@@ -3848,7 +3836,6 @@ impl Project {
|
||||
old_peer_id,
|
||||
new_peer_id,
|
||||
});
|
||||
cx.notify();
|
||||
Ok(())
|
||||
})?
|
||||
}
|
||||
@@ -3876,7 +3863,6 @@ impl Project {
|
||||
});
|
||||
|
||||
cx.emit(Event::CollaboratorLeft(peer_id));
|
||||
cx.notify();
|
||||
Ok(())
|
||||
})?
|
||||
}
|
||||
@@ -4292,7 +4278,6 @@ impl Project {
|
||||
worktrees: Vec<proto::WorktreeMetadata>,
|
||||
cx: &mut Context<Project>,
|
||||
) -> Result<()> {
|
||||
cx.notify();
|
||||
self.worktree_store.update(cx, |worktree_store, cx| {
|
||||
worktree_store.set_worktrees_from_proto(worktrees, self.replica_id(), cx)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user