Skip to content
Open
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
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
# Change Log

# 0.9.15

- Optimizations in how the server resolves file paths, should reduce
time-to-ready for the server when first starting by about 50%, depending
on the complexity of the include tree.

## 0.9.14
- Slight optimization to the memory usage of device-level analysis which
Expand Down
23 changes: 20 additions & 3 deletions src/actions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@ pub struct InitActionContext<O: Output> {
// the root workspaces
pub workspace_roots: Arc<Mutex<Vec<Workspace>>>,

pub cached_path_resolver: Arc<Mutex<Option<PathResolver>>>,

// directly opened files
pub direct_opens: Arc<Mutex<HashSet<CanonPath>>>,
pub compilation_info: Arc<Mutex<CompilationInfoStorage>>,
Expand Down Expand Up @@ -378,6 +380,7 @@ impl <O: Output> InitActionContext<O> {
config,
lint_config: Arc::new(Mutex::new(LintCfg::default())),
jobs: Arc::default(),
cached_path_resolver: Arc::default(),
direct_opens: Arc::default(),
quiescent: Arc::new(AtomicBool::new(false)),
prev_changes: Arc::default(),
Expand Down Expand Up @@ -419,12 +422,17 @@ impl <O: Output> InitActionContext<O> {

pub fn update_workspaces(&self,
mut add: Vec<Workspace>,
remove: Vec<Workspace>) {
remove: Vec<Workspace>,
out: &O) {
let any_change = !(add.is_empty() && remove.is_empty());
if let Ok(mut workspaces) = self.workspace_roots.lock() {
workspaces.retain(|workspace|
remove.iter().all(|rem|rem != workspace));
workspaces.append(&mut add);
}
if any_change {
self.update_compilation_info(out);
}
}

fn update_linter_config(&self, out: &O) {
Expand All @@ -445,6 +453,11 @@ impl <O: Output> InitActionContext<O> {
trace!("Updating compile info");
if let Ok(config) = self.config.lock() {
if let Some(compile_info) = &config.compile_info_path {
// Ensure resolver exists
self.construct_resolver();
// And then remove it from storage (invalidates it)
let old_resolver = self.cached_path_resolver.lock()
.expect("Failed to grab resolver").take().unwrap();
if let Some(canon_path) = CanonPath::from_path_buf(
compile_info.clone()) {
let workspaces = self.workspace_roots.lock().unwrap();
Expand All @@ -468,8 +481,7 @@ impl <O: Output> InitActionContext<O> {
*ci = compilation_info;
}
self.analysis.lock().unwrap()
.update_all_context_dependencies(
self.construct_resolver());
.update_all_context_dependencies(old_resolver);
},
Err(e) => {
error!("Failed to update compilation info: {}", e);
Expand Down Expand Up @@ -776,6 +788,10 @@ impl <O: Output> InitActionContext<O> {
}

pub fn construct_resolver(&self) -> PathResolver {
if let Some(resolver) = self.cached_path_resolver.lock()
.unwrap().as_ref() {
return resolver.clone();
}
trace!("About to construct resolver");
let mut toret: PathResolver =
self.client_capabilities.root.clone().into();
Expand All @@ -788,6 +804,7 @@ impl <O: Output> InitActionContext<O> {
.into_iter().collect()))
.collect());
trace!("Constructed resolver: {:?}", toret);
*self.cached_path_resolver.lock().unwrap() = Some(toret.clone());
toret
}

Expand Down
4 changes: 2 additions & 2 deletions src/actions/notifications.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,11 +262,11 @@ impl BlockingNotificationAction for DidChangeWorkspaceFolders {
fn handle<O: Output>(
params: DidChangeWorkspaceFoldersParams,
ctx: &mut InitActionContext<O>,
_out: O,
out: O,
) -> Result<(), ResponseError> {
let added = params.event.added;
let removed = params.event.removed;
ctx.update_workspaces(added, removed);
ctx.update_workspaces(added, removed, &out);
Ok(())
}
}
Expand Down
16 changes: 15 additions & 1 deletion src/file_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::fs;

use std::path::{Path, PathBuf};
use std::ops::Deref;
use std::cell::RefCell;

// A path which we know to be canonical in the filesystem
#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
Expand Down Expand Up @@ -52,12 +53,14 @@ impl CanonPath {
}

/// This is how we resolve relative paths to in-workspace full paths
#[derive(Eq, PartialEq, Debug, Clone)]
#[derive(Debug, Clone)]
pub struct PathResolver {
// Root is provided by context, who will pass this struct to threads for
// import resolution
roots: Vec<PathBuf>,
include_paths: HashMap<CanonPath, Vec<PathBuf>>,
#[allow(clippy::type_complexity)]
cache: RefCell<HashMap<(PathBuf, Option<CanonPath>), Option<CanonPath>>>,
}

impl From<Option<PathBuf>> for PathResolver {
Expand All @@ -69,6 +72,7 @@ impl From<Option<PathBuf>> for PathResolver {
PathResolver {
roots,
include_paths: HashMap::default(),
cache: RefCell::default(),
}
}
}
Expand Down Expand Up @@ -117,6 +121,16 @@ impl PathResolver {
path: &Path,
context: Option<&CanonPath>)
-> Option<CanonPath> {
self.cache.borrow_mut().entry((path.to_path_buf(), context.cloned()))
.or_insert_with(
||self.resolve_with_maybe_context_impl(path, context))
.clone()
}

fn resolve_with_maybe_context_impl(&self,
path: &Path,
context: Option<&CanonPath>)
-> Option<CanonPath> {
// Given some relative info, find a canonical file path
// NOTE: Right now the relative info is a pathbuf, but this might
// change later
Expand Down
2 changes: 1 addition & 1 deletion src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ impl BlockingRequestAction for InitializeRequest {
});
}
if let ActionContext::Init(ref mut initctx) = ctx {
initctx.update_workspaces(workspaces, vec![]);
initctx.update_workspaces(workspaces, vec![], &out);
let temp_resolver = initctx.construct_resolver();
for file in IMPLICIT_IMPORTS {
debug!("Requesting analysis of builtin file {}", file);
Expand Down