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:
Florian Diebold 2021-02-12 15:58:29 +01:00
parent dee5aba43a
commit a7387cae2c
6 changed files with 51 additions and 14 deletions

View file

@ -59,7 +59,11 @@ pub fn load_cargo(root: &Path, config: &LoadCargoConfig) -> Result<(AnalysisHost
);
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);
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
for task in receiver {
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 {
break;
}

View file

@ -67,6 +67,7 @@ pub(crate) struct GlobalState {
req_queue: ReqQueue,
pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
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_sender: Sender<flycheck::Message>,
pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
@ -120,6 +121,7 @@ impl GlobalState {
GlobalState {
sender,
req_queue: ReqQueue::default(),
vfs_config_version: 0,
task_pool,
loader,
flycheck: Vec::new(),

View file

@ -5,6 +5,7 @@ use std::{
time::{Duration, Instant},
};
use always_assert::always;
use crossbeam_channel::{select, Receiver};
use ide::PrimeCachesProgress;
use ide::{Canceled, FileId};
@ -186,7 +187,7 @@ impl GlobalState {
log::info!("task queue len: {}", task_queue_len);
}
let prev_status = self.status;
let mut new_status = self.status;
match event {
Event::Lsp(msg) => match msg {
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 {
self.transition(Status::Invalid);
new_status = Status::Invalid;
} else {
let state = if n_done == 0 {
self.transition(Status::Loading);
new_status = Status::Loading;
Progress::Begin
} else if n_done < n_total {
Progress::Report
} else {
assert_eq!(n_done, n_total);
let status = Status::Ready {
new_status = Status::Ready {
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
};
self.report_progress(
@ -398,6 +400,10 @@ impl GlobalState {
}
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 { .. });
if prev_status == Status::Loading && is_ready {
for flycheck in &self.flycheck {

View file

@ -50,6 +50,16 @@ impl GlobalState {
Status::Loading | Status::NeedsReload => return,
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() {
self.fetch_workspaces_request();
} else {
@ -290,7 +300,12 @@ impl GlobalState {
FilesWatcher::Client => vec![],
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
let crate_graph = {

View file

@ -86,8 +86,10 @@ impl NotifyActor {
self.watcher = watcher.map(|it| (it, watcher_receiver));
}
let config_version = config.version;
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();
@ -98,7 +100,11 @@ impl NotifyActor {
}
let files = self.load_entry(entry, watch);
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) => {

View file

@ -32,6 +32,9 @@ pub struct Directories {
/// [`Handle`]'s configuration.
#[derive(Debug)]
pub struct Config {
/// Version number to associate progress updates to the right config
/// version.
pub version: u32,
/// Set of initially loaded files.
pub load: Vec<Entry>,
/// Index of watched entries in `load`.
@ -45,7 +48,7 @@ pub enum Message {
/// Indicate a gradual progress.
///
/// 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.
Loaded { files: Vec<(AbsPathBuf, Option<Vec<u8>>)> },
}
@ -196,10 +199,11 @@ impl fmt::Debug for Message {
Message::Loaded { files } => {
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")
.field("n_total", n_total)
.field("n_done", n_done)
.field("config_version", config_version)
.finish(),
}
}