Skip to content

Debounce workspace fetching for workspace structure changes #19814

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions crates/rust-analyzer/src/global_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
//!
//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.

use std::{ops::Not as _, time::Instant};
use std::{
ops::Not as _,
time::{Duration, Instant},
};

use crossbeam_channel::{Receiver, Sender, unbounded};
use hir::ChangeWithProcMacros;
Expand Down Expand Up @@ -114,6 +117,11 @@ pub(crate) struct GlobalState {
pub(crate) discover_sender: Sender<discover::DiscoverProjectMessage>,
pub(crate) discover_receiver: Receiver<discover::DiscoverProjectMessage>,

// Debouncing channel for fetching the workspace
// we want to delay it until the VFS looks stable-ish (and thus is not currently in the middle
// of a VCS operation like `git switch`)
pub(crate) fetch_ws_receiver: Option<(Receiver<Instant>, FetchWorkspaceRequest)>,

// VFS
pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>,
pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
Expand Down Expand Up @@ -264,6 +272,8 @@ impl GlobalState {
discover_sender,
discover_receiver,

fetch_ws_receiver: None,

vfs: Arc::new(RwLock::new((vfs::Vfs::default(), Default::default()))),
vfs_config_version: 0,
vfs_progress_config_version: 0,
Expand Down Expand Up @@ -508,11 +518,9 @@ impl GlobalState {
if let Some((path, force_crate_graph_reload)) = workspace_structure_change {
let _p = span!(Level::INFO, "GlobalState::process_changes/ws_structure_change")
.entered();

self.fetch_workspaces_queue.request_op(
format!("workspace vfs file change: {path}"),
FetchWorkspaceRequest { path: Some(path), force_crate_graph_reload },
);
if self.fetch_workspaces_queue.should_start_op().is_none() {
self.enqueue_workspace_fetch(path, force_crate_graph_reload);
}
}
}

Expand Down Expand Up @@ -660,6 +668,19 @@ impl GlobalState {
None
})
}

fn enqueue_workspace_fetch(&mut self, path: AbsPathBuf, force_crate_graph_reload: bool) {
self.fetch_ws_receiver = Some((
crossbeam_channel::after(Duration::from_millis(100)),
FetchWorkspaceRequest { path: Some(path), force_crate_graph_reload },
));
}

pub(crate) fn debounce_workspace_fetch(&mut self) {
if let Some((fetch_receiver, _)) = &mut self.fetch_ws_receiver {
*fetch_receiver = crossbeam_channel::after(Duration::from_millis(100));
}
}
}

impl Drop for GlobalState {
Expand Down
18 changes: 16 additions & 2 deletions crates/rust-analyzer/src/main_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::{
time::{Duration, Instant},
};

use crossbeam_channel::{Receiver, select};
use crossbeam_channel::{Receiver, never, select};
use ide_db::base_db::{SourceDatabase, VfsPath, salsa::Database as _};
use lsp_server::{Connection, Notification, Request};
use lsp_types::{TextDocumentIdentifier, notification::Notification as _};
Expand Down Expand Up @@ -71,6 +71,7 @@ enum Event {
Flycheck(FlycheckMessage),
TestResult(CargoTestMessage),
DiscoverProject(DiscoverProjectMessage),
FetchWorkspaces(FetchWorkspaceRequest),
}

impl fmt::Display for Event {
Expand All @@ -83,6 +84,7 @@ impl fmt::Display for Event {
Event::QueuedTask(_) => write!(f, "Event::QueuedTask"),
Event::TestResult(_) => write!(f, "Event::TestResult"),
Event::DiscoverProject(_) => write!(f, "Event::DiscoverProject"),
Event::FetchWorkspaces(_) => write!(f, "Event::SwitchWorkspaces"),
}
}
}
Expand Down Expand Up @@ -150,6 +152,7 @@ impl fmt::Debug for Event {
}
_ => (),
}

match self {
Event::Lsp(it) => fmt::Debug::fmt(it, f),
Event::Task(it) => fmt::Debug::fmt(it, f),
Expand All @@ -158,6 +161,7 @@ impl fmt::Debug for Event {
Event::Flycheck(it) => fmt::Debug::fmt(it, f),
Event::TestResult(it) => fmt::Debug::fmt(it, f),
Event::DiscoverProject(it) => fmt::Debug::fmt(it, f),
Event::FetchWorkspaces(_) => Ok(()),
}
}
}
Expand Down Expand Up @@ -251,7 +255,7 @@ impl GlobalState {
}

fn next_event(
&self,
&mut self,
inbox: &Receiver<lsp_server::Message>,
) -> Result<Option<Event>, crossbeam_channel::RecvError> {
// Make sure we reply to formatting requests ASAP so the editor doesn't block
Expand Down Expand Up @@ -283,6 +287,10 @@ impl GlobalState {

recv(self.discover_receiver) -> task =>
task.map(Event::DiscoverProject),

recv(self.fetch_ws_receiver.as_ref().map_or(&never(), |(chan, _)| chan)) -> _instant => {
Ok(Event::FetchWorkspaces(self.fetch_ws_receiver.take().unwrap().1))
},
}
.map(Some)
}
Expand Down Expand Up @@ -412,6 +420,11 @@ impl GlobalState {
self.handle_discover_msg(message);
}
}
Event::FetchWorkspaces(req) => {
if !self.fetch_workspaces_queue.op_requested() {
self.fetch_workspaces_queue.request_op("vfs change".to_owned(), req)
}
}
}
let event_handling_duration = loop_start.elapsed();
let (state_changed, memdocs_added_or_removed) = if self.vfs_done {
Expand Down Expand Up @@ -830,6 +843,7 @@ impl GlobalState {
match message {
vfs::loader::Message::Changed { files } | vfs::loader::Message::Loaded { files } => {
let _p = tracing::info_span!("GlobalState::handle_vfs_msg{changed/load}").entered();
self.debounce_workspace_fetch();
let vfs = &mut self.vfs.write().0;
for (path, contents) in files {
let path = VfsPath::from(path);
Expand Down
Loading