From 43e52ac9e2b26ec287b1778823bad10851cfd44e Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 9 Feb 2019 13:06:12 +0100 Subject: Implement BatchDatabase construction --- Cargo.lock | 11 +--- crates/ra_batch/Cargo.toml | 12 ++-- crates/ra_batch/src/lib.rs | 99 +++++++++++++++++++++++++++++++- crates/ra_lsp_server/src/server_world.rs | 4 +- crates/ra_vfs/src/lib.rs | 12 ++++ 5 files changed, 116 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53c2498f1..74a77ddc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -913,20 +913,15 @@ dependencies = [ name = "ra_batch" version = "0.1.0" dependencies = [ - "fst 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "insta 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "ra_db 0.1.0", "ra_hir 0.1.0", + "ra_project_model 0.1.0", "ra_syntax 0.1.0", - "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ra_vfs 0.1.0", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "test_utils 0.1.0", - "unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/crates/ra_batch/Cargo.toml b/crates/ra_batch/Cargo.toml index 3e83f8388..30a0749c7 100644 --- a/crates/ra_batch/Cargo.toml +++ b/crates/ra_batch/Cargo.toml @@ -5,20 +5,16 @@ version = "0.1.0" authors = ["Aleksey Kladov "] [dependencies] -itertools = "0.8.0" -join_to_string = "0.1.3" log = "0.4.5" -relative-path = "0.4.0" -rayon = "1.0.2" -fst = "0.3.1" rustc-hash = "1.0" -parking_lot = "0.7.0" -unicase = "2.2.0" + +failure = "0.1.4" ra_syntax = { path = "../ra_syntax" } ra_db = { path = "../ra_db" } ra_hir = { path = "../ra_hir" } +ra_vfs = { path = "../ra_vfs" } +ra_project_model = { path = "../ra_project_model" } [dev-dependencies] test_utils = { path = "../test_utils" } -insta = "0.6.1" diff --git a/crates/ra_batch/src/lib.rs b/crates/ra_batch/src/lib.rs index 25f1f7357..ea91d88b7 100644 --- a/crates/ra_batch/src/lib.rs +++ b/crates/ra_batch/src/lib.rs @@ -1,9 +1,17 @@ use std::sync::Arc; +use std::path::Path; +use std::collections::HashSet; + +use rustc_hash::FxHashMap; use ra_db::{ - FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId, SourceDatabase, salsa, + CrateGraph, FileId, SourceRoot, SourceRootId, SourceDatabase, salsa, }; use ra_hir::{db, HirInterner}; +use ra_project_model::ProjectWorkspace; +use ra_vfs::{Vfs, VfsChange}; + +type Result = std::result::Result; #[salsa::database( ra_db::SourceDatabaseStorage, @@ -11,10 +19,10 @@ use ra_hir::{db, HirInterner}; db::PersistentHirDatabaseStorage )] #[derive(Debug)] -pub(crate) struct BatchDatabase { +pub struct BatchDatabase { runtime: salsa::Runtime, interner: Arc, - file_counter: u32, + // file_counter: u32, } impl salsa::Database for BatchDatabase { @@ -28,3 +36,88 @@ impl AsRef for BatchDatabase { &self.interner } } + +fn vfs_file_to_id(f: ra_vfs::VfsFile) -> FileId { + FileId(f.0.into()) +} +fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId { + SourceRootId(r.0.into()) +} + +impl BatchDatabase { + pub fn load(crate_graph: CrateGraph, vfs: &mut Vfs) -> BatchDatabase { + let mut db = + BatchDatabase { runtime: salsa::Runtime::default(), interner: Default::default() }; + db.set_crate_graph(Arc::new(crate_graph)); + + // wait until Vfs has loaded all roots + let receiver = vfs.task_receiver().clone(); + let mut roots_loaded = HashSet::new(); + for task in receiver { + vfs.handle_task(task); + let mut done = false; + for change in vfs.commit_changes() { + match change { + VfsChange::AddRoot { root, files } => { + let source_root_id = vfs_root_to_id(root); + log::debug!("loaded source root {:?} with path {:?}", source_root_id, vfs.root2path(root)); + let mut file_map = FxHashMap::default(); + for (vfs_file, path, text) in files { + let file_id = vfs_file_to_id(vfs_file); + db.set_file_text(file_id, text); + db.set_file_relative_path(file_id, path.clone()); + db.set_file_source_root(file_id, source_root_id); + file_map.insert(path, file_id); + } + let source_root = SourceRoot { files: file_map }; + db.set_source_root(source_root_id, Arc::new(source_root)); + roots_loaded.insert(source_root_id); + if roots_loaded.len() == vfs.num_roots() { + done = true; + } + } + VfsChange::AddFile { .. } + | VfsChange::RemoveFile { .. } + | VfsChange::ChangeFile { .. } => { + // log::warn!("VFS changed while loading"); + } + } + } + if done { + break; + } + } + + db + } + + pub fn load_cargo(root: impl AsRef) -> Result<(BatchDatabase, Vec)> { + let root = root.as_ref().canonicalize()?; + let ws = ProjectWorkspace::discover(root.as_ref())?; + let mut roots = Vec::new(); + roots.push(root.clone()); + for pkg in ws.cargo.packages() { + roots.push(pkg.root(&ws.cargo).to_path_buf()); + } + for krate in ws.sysroot.crates() { + roots.push(krate.root_dir(&ws.sysroot).to_path_buf()) + } + let (mut vfs, roots) = Vfs::new(roots); + let mut load = |path: &Path| { + let vfs_file = vfs.load(path); + log::debug!("vfs file {:?} -> {:?}", path, vfs_file); + vfs_file.map(vfs_file_to_id) + }; + let crate_graph = ws.to_crate_graph(&mut load); + log::debug!("crate graph: {:?}", crate_graph); + + let local_roots = roots.into_iter() + .filter(|r| vfs.root2path(*r).starts_with(&root)) + .map(vfs_root_to_id) + .collect(); + + let db = BatchDatabase::load(crate_graph, &mut vfs); + let _ = vfs.shutdown(); + Ok((db, local_roots)) + } +} diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index f97d240fa..4a68c019f 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs @@ -47,10 +47,8 @@ impl ServerWorldState { roots.push(krate.root_dir(&ws.sysroot).to_path_buf()) } } - roots.sort(); - roots.dedup(); - let roots_to_scan = roots.len(); let (mut vfs, roots) = Vfs::new(roots); + let roots_to_scan = roots.len(); for r in roots { let is_local = vfs.root2path(r).starts_with(&root); change.add_root(SourceRootId(r.0.into()), is_local); diff --git a/crates/ra_vfs/src/lib.rs b/crates/ra_vfs/src/lib.rs index 6b4eb6842..2d861f832 100644 --- a/crates/ra_vfs/src/lib.rs +++ b/crates/ra_vfs/src/lib.rs @@ -94,6 +94,7 @@ impl Roots { let mut roots = Arena::default(); // A hack to make nesting work. paths.sort_by_key(|it| Reverse(it.as_os_str().len())); + paths.dedup(); for (i, path) in paths.iter().enumerate() { let nested_roots = paths[..i] .iter() @@ -161,6 +162,13 @@ impl Vfs { self.roots[root].root.clone() } + pub fn path2root(&self, path: &Path) -> Option { + match self.find_root(path) { + Some((root, _path, _file)) => Some(root), + _ => None, + } + } + pub fn path2file(&self, path: &Path) -> Option { if let Some((_root, _path, Some(file))) = self.find_root(path) { return Some(file); @@ -181,6 +189,10 @@ impl Vfs { None } + pub fn num_roots(&self) -> usize { + self.roots.len() + } + pub fn load(&mut self, path: &Path) -> Option { if let Some((root, rel_path, file)) = self.find_root(path) { return if let Some(file) = file { -- cgit v1.2.3