mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Fix slow tests sometimes failing
In some situations we reloaded the workspace in the tests after having reported to be ready. There's two fixes here: 1. Add a version to the VFS config and include that version in progress reports, so that we don't think we're done prematurely; 2. Delay status transitions until after changes are applied. Otherwise the last change during loading can potentially trigger a workspace reload, if it contains interesting changes.
This commit is contained in:
parent
dee5aba43a
commit
a7387cae2c
6 changed files with 51 additions and 14 deletions
|
@ -59,7 +59,11 @@ pub fn load_cargo(root: &Path, config: &LoadCargoConfig) -> Result<(AnalysisHost
|
||||||
);
|
);
|
||||||
|
|
||||||
let project_folders = ProjectFolders::new(&[ws], &[], build_data.as_ref());
|
let project_folders = ProjectFolders::new(&[ws], &[], build_data.as_ref());
|
||||||
loader.set_config(vfs::loader::Config { load: project_folders.load, watch: vec![] });
|
loader.set_config(vfs::loader::Config {
|
||||||
|
load: project_folders.load,
|
||||||
|
watch: vec![],
|
||||||
|
version: 0,
|
||||||
|
});
|
||||||
|
|
||||||
log::debug!("crate graph: {:?}", crate_graph);
|
log::debug!("crate graph: {:?}", crate_graph);
|
||||||
let host = load(crate_graph, project_folders.source_root_config, &mut vfs, &receiver);
|
let host = load(crate_graph, project_folders.source_root_config, &mut vfs, &receiver);
|
||||||
|
@ -79,7 +83,7 @@ fn load(
|
||||||
// wait until Vfs has loaded all roots
|
// wait until Vfs has loaded all roots
|
||||||
for task in receiver {
|
for task in receiver {
|
||||||
match task {
|
match task {
|
||||||
vfs::loader::Message::Progress { n_done, n_total } => {
|
vfs::loader::Message::Progress { n_done, n_total, config_version: _ } => {
|
||||||
if n_done == n_total {
|
if n_done == n_total {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ pub(crate) struct GlobalState {
|
||||||
req_queue: ReqQueue,
|
req_queue: ReqQueue,
|
||||||
pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
|
pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
|
||||||
pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>,
|
pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>,
|
||||||
|
pub(crate) vfs_config_version: u32,
|
||||||
pub(crate) flycheck: Vec<FlycheckHandle>,
|
pub(crate) flycheck: Vec<FlycheckHandle>,
|
||||||
pub(crate) flycheck_sender: Sender<flycheck::Message>,
|
pub(crate) flycheck_sender: Sender<flycheck::Message>,
|
||||||
pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
|
pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
|
||||||
|
@ -120,6 +121,7 @@ impl GlobalState {
|
||||||
GlobalState {
|
GlobalState {
|
||||||
sender,
|
sender,
|
||||||
req_queue: ReqQueue::default(),
|
req_queue: ReqQueue::default(),
|
||||||
|
vfs_config_version: 0,
|
||||||
task_pool,
|
task_pool,
|
||||||
loader,
|
loader,
|
||||||
flycheck: Vec::new(),
|
flycheck: Vec::new(),
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::{
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use always_assert::always;
|
||||||
use crossbeam_channel::{select, Receiver};
|
use crossbeam_channel::{select, Receiver};
|
||||||
use ide::PrimeCachesProgress;
|
use ide::PrimeCachesProgress;
|
||||||
use ide::{Canceled, FileId};
|
use ide::{Canceled, FileId};
|
||||||
|
@ -186,7 +187,7 @@ impl GlobalState {
|
||||||
log::info!("task queue len: {}", task_queue_len);
|
log::info!("task queue len: {}", task_queue_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
let prev_status = self.status;
|
let mut new_status = self.status;
|
||||||
match event {
|
match event {
|
||||||
Event::Lsp(msg) => match msg {
|
Event::Lsp(msg) => match msg {
|
||||||
lsp_server::Message::Request(req) => self.on_request(loop_start, req)?,
|
lsp_server::Message::Request(req) => self.on_request(loop_start, req)?,
|
||||||
|
@ -298,22 +299,23 @@ impl GlobalState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vfs::loader::Message::Progress { n_total, n_done } => {
|
vfs::loader::Message::Progress { n_total, n_done, config_version } => {
|
||||||
|
always!(config_version <= self.vfs_config_version);
|
||||||
if n_total == 0 {
|
if n_total == 0 {
|
||||||
self.transition(Status::Invalid);
|
new_status = Status::Invalid;
|
||||||
} else {
|
} else {
|
||||||
let state = if n_done == 0 {
|
let state = if n_done == 0 {
|
||||||
self.transition(Status::Loading);
|
new_status = Status::Loading;
|
||||||
Progress::Begin
|
Progress::Begin
|
||||||
} else if n_done < n_total {
|
} else if n_done < n_total {
|
||||||
Progress::Report
|
Progress::Report
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(n_done, n_total);
|
assert_eq!(n_done, n_total);
|
||||||
let status = Status::Ready {
|
new_status = Status::Ready {
|
||||||
partial: self.config.load_out_dirs_from_check()
|
partial: self.config.load_out_dirs_from_check()
|
||||||
&& self.workspace_build_data.is_none(),
|
&& self.workspace_build_data.is_none()
|
||||||
|
|| config_version < self.vfs_config_version,
|
||||||
};
|
};
|
||||||
self.transition(status);
|
|
||||||
Progress::End
|
Progress::End
|
||||||
};
|
};
|
||||||
self.report_progress(
|
self.report_progress(
|
||||||
|
@ -398,6 +400,10 @@ impl GlobalState {
|
||||||
}
|
}
|
||||||
|
|
||||||
let state_changed = self.process_changes();
|
let state_changed = self.process_changes();
|
||||||
|
let prev_status = self.status;
|
||||||
|
if prev_status != new_status {
|
||||||
|
self.transition(new_status);
|
||||||
|
}
|
||||||
let is_ready = matches!(self.status, Status::Ready { .. });
|
let is_ready = matches!(self.status, Status::Ready { .. });
|
||||||
if prev_status == Status::Loading && is_ready {
|
if prev_status == Status::Loading && is_ready {
|
||||||
for flycheck in &self.flycheck {
|
for flycheck in &self.flycheck {
|
||||||
|
|
|
@ -50,6 +50,16 @@ impl GlobalState {
|
||||||
Status::Loading | Status::NeedsReload => return,
|
Status::Loading | Status::NeedsReload => return,
|
||||||
Status::Ready { .. } | Status::Invalid => (),
|
Status::Ready { .. } | Status::Invalid => (),
|
||||||
}
|
}
|
||||||
|
log::info!(
|
||||||
|
"Reloading workspace because of the following changes: {}",
|
||||||
|
itertools::join(
|
||||||
|
changes
|
||||||
|
.iter()
|
||||||
|
.filter(|(path, kind)| is_interesting(path, *kind))
|
||||||
|
.map(|(path, kind)| format!("{}/{:?}", path.display(), kind)),
|
||||||
|
", "
|
||||||
|
)
|
||||||
|
);
|
||||||
if self.config.cargo_autoreload() {
|
if self.config.cargo_autoreload() {
|
||||||
self.fetch_workspaces_request();
|
self.fetch_workspaces_request();
|
||||||
} else {
|
} else {
|
||||||
|
@ -290,7 +300,12 @@ impl GlobalState {
|
||||||
FilesWatcher::Client => vec![],
|
FilesWatcher::Client => vec![],
|
||||||
FilesWatcher::Notify => project_folders.watch,
|
FilesWatcher::Notify => project_folders.watch,
|
||||||
};
|
};
|
||||||
self.loader.handle.set_config(vfs::loader::Config { load: project_folders.load, watch });
|
self.vfs_config_version += 1;
|
||||||
|
self.loader.handle.set_config(vfs::loader::Config {
|
||||||
|
load: project_folders.load,
|
||||||
|
watch,
|
||||||
|
version: self.vfs_config_version,
|
||||||
|
});
|
||||||
|
|
||||||
// Create crate graph from all the workspaces
|
// Create crate graph from all the workspaces
|
||||||
let crate_graph = {
|
let crate_graph = {
|
||||||
|
|
|
@ -86,8 +86,10 @@ impl NotifyActor {
|
||||||
self.watcher = watcher.map(|it| (it, watcher_receiver));
|
self.watcher = watcher.map(|it| (it, watcher_receiver));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let config_version = config.version;
|
||||||
|
|
||||||
let n_total = config.load.len();
|
let n_total = config.load.len();
|
||||||
self.send(loader::Message::Progress { n_total, n_done: 0 });
|
self.send(loader::Message::Progress { n_total, n_done: 0, config_version });
|
||||||
|
|
||||||
self.watched_entries.clear();
|
self.watched_entries.clear();
|
||||||
|
|
||||||
|
@ -98,7 +100,11 @@ impl NotifyActor {
|
||||||
}
|
}
|
||||||
let files = self.load_entry(entry, watch);
|
let files = self.load_entry(entry, watch);
|
||||||
self.send(loader::Message::Loaded { files });
|
self.send(loader::Message::Loaded { files });
|
||||||
self.send(loader::Message::Progress { n_total, n_done: i + 1 });
|
self.send(loader::Message::Progress {
|
||||||
|
n_total,
|
||||||
|
n_done: i + 1,
|
||||||
|
config_version,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Invalidate(path) => {
|
Message::Invalidate(path) => {
|
||||||
|
|
|
@ -32,6 +32,9 @@ pub struct Directories {
|
||||||
/// [`Handle`]'s configuration.
|
/// [`Handle`]'s configuration.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
/// Version number to associate progress updates to the right config
|
||||||
|
/// version.
|
||||||
|
pub version: u32,
|
||||||
/// Set of initially loaded files.
|
/// Set of initially loaded files.
|
||||||
pub load: Vec<Entry>,
|
pub load: Vec<Entry>,
|
||||||
/// Index of watched entries in `load`.
|
/// Index of watched entries in `load`.
|
||||||
|
@ -45,7 +48,7 @@ pub enum Message {
|
||||||
/// Indicate a gradual progress.
|
/// Indicate a gradual progress.
|
||||||
///
|
///
|
||||||
/// This is supposed to be the number of loaded files.
|
/// This is supposed to be the number of loaded files.
|
||||||
Progress { n_total: usize, n_done: usize },
|
Progress { n_total: usize, n_done: usize, config_version: u32 },
|
||||||
/// The handle loaded the following files' content.
|
/// The handle loaded the following files' content.
|
||||||
Loaded { files: Vec<(AbsPathBuf, Option<Vec<u8>>)> },
|
Loaded { files: Vec<(AbsPathBuf, Option<Vec<u8>>)> },
|
||||||
}
|
}
|
||||||
|
@ -196,10 +199,11 @@ impl fmt::Debug for Message {
|
||||||
Message::Loaded { files } => {
|
Message::Loaded { files } => {
|
||||||
f.debug_struct("Loaded").field("n_files", &files.len()).finish()
|
f.debug_struct("Loaded").field("n_files", &files.len()).finish()
|
||||||
}
|
}
|
||||||
Message::Progress { n_total, n_done } => f
|
Message::Progress { n_total, n_done, config_version } => f
|
||||||
.debug_struct("Progress")
|
.debug_struct("Progress")
|
||||||
.field("n_total", n_total)
|
.field("n_total", n_total)
|
||||||
.field("n_done", n_done)
|
.field("n_done", n_done)
|
||||||
|
.field("config_version", config_version)
|
||||||
.finish(),
|
.finish(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue