simpler update

This commit is contained in:
Aleksey Kladov 2018-08-21 22:24:59 +03:00
parent b937262c9b
commit ecc9df5f00
4 changed files with 149 additions and 73 deletions

View file

@ -17,7 +17,6 @@ use rayon::prelude::*;
use std::{ use std::{
fmt, fmt,
mem,
path::{Path}, path::{Path},
sync::{ sync::{
Arc, Arc,
@ -36,18 +35,16 @@ use libeditor::{LineIndex, FileSymbol, find_node};
use self::{ use self::{
symbol_index::FileSymbols, symbol_index::FileSymbols,
module_map::ModuleMap, module_map::{ModuleMap, ChangeKind},
}; };
pub use self::symbol_index::Query; pub use self::symbol_index::Query;
pub type Result<T> = ::std::result::Result<T, ::failure::Error>; pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
const INDEXING_THRESHOLD: usize = 128;
pub type FileResolver = dyn Fn(FileId, &Path) -> Option<FileId> + Send + Sync; pub type FileResolver = dyn Fn(FileId, &Path) -> Option<FileId> + Send + Sync;
#[derive(Debug)] #[derive(Debug)]
pub struct WorldState { pub struct WorldState {
updates: Vec<FileId>,
data: Arc<WorldData> data: Arc<WorldData>
} }
@ -79,32 +76,16 @@ pub struct FileId(pub u32);
impl WorldState { impl WorldState {
pub fn new() -> WorldState { pub fn new() -> WorldState {
WorldState { WorldState {
updates: Vec::new(),
data: Arc::new(WorldData::default()), data: Arc::new(WorldData::default()),
} }
} }
pub fn snapshot( pub fn snapshot(
&mut self, &self,
file_resolver: impl Fn(FileId, &Path) -> Option<FileId> + 'static + Send + Sync, file_resolver: impl Fn(FileId, &Path) -> Option<FileId> + 'static + Send + Sync,
) -> World { ) -> World {
let needs_reindex = self.updates.len() >= INDEXING_THRESHOLD;
if !self.updates.is_empty() {
let updates = mem::replace(&mut self.updates, Vec::new());
let data = self.data_mut();
for file_id in updates {
let syntax = data.file_map
.get(&file_id)
.map(|it| it.syntax());
data.module_map.update_file(
file_id,
syntax,
&file_resolver,
);
}
}
World { World {
needs_reindex: AtomicBool::new(needs_reindex), needs_reindex: AtomicBool::new(false),
file_resolver: Arc::new(file_resolver), file_resolver: Arc::new(file_resolver),
data: self.data.clone() data: self.data.clone()
} }
@ -115,21 +96,26 @@ impl WorldState {
} }
pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) { pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) {
let mut updates = Vec::new(); let data = self.data_mut();
{ for (file_id, text) in changes {
let data = self.data_mut(); let change_kind = if data.file_map.remove(&file_id).is_some() {
for (file_id, text) in changes { if text.is_some() {
data.file_map.remove(&file_id); ChangeKind::Update
if let Some(text) = text {
let file_data = FileData::new(text);
data.file_map.insert(file_id, Arc::new(file_data));
} else { } else {
data.file_map.remove(&file_id); ChangeKind::Delete
} }
updates.push(file_id); } else {
ChangeKind::Insert
};
data.module_map.update_file(file_id, change_kind);
data.file_map.remove(&file_id);
if let Some(text) = text {
let file_data = FileData::new(text);
data.file_map.insert(file_id, Arc::new(file_data));
} else {
data.file_map.remove(&file_id);
} }
} }
self.updates.extend(updates)
} }
fn data_mut(&mut self) -> &mut WorldData { fn data_mut(&mut self) -> &mut WorldData {
@ -171,13 +157,17 @@ impl World {
let module_map = &self.data.module_map; let module_map = &self.data.module_map;
let id = module_map.file2module(id); let id = module_map.file2module(id);
module_map module_map
.parent_modules(id) .parent_modules(
id,
&*self.file_resolver,
&|file_id| self.file_syntax(file_id).unwrap(),
)
.into_iter() .into_iter()
.map(|(id, m)| { .map(|(id, name, node)| {
let id = module_map.module2file(id); let id = module_map.module2file(id);
let sym = FileSymbol { let sym = FileSymbol {
name: m.name().unwrap().text(), name,
node_range: m.syntax().range(), node_range: node.range(),
kind: MODULE, kind: MODULE,
}; };
(id, sym) (id, sym)
@ -235,7 +225,11 @@ impl World {
let module_map = &self.data.module_map; let module_map = &self.data.module_map;
let id = module_map.file2module(id); let id = module_map.file2module(id);
module_map module_map
.child_module_by_name(id, name.as_str()) .child_module_by_name(
id, name.as_str(),
&*self.file_resolver,
&|file_id| self.file_syntax(file_id).unwrap(),
)
.into_iter() .into_iter()
.map(|id| module_map.module2file(id)) .map(|id| module_map.module2file(id))
.collect() .collect()

View file

@ -2,17 +2,38 @@ use std::{
path::{PathBuf}, path::{PathBuf},
}; };
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use libsyntax2::{ use libsyntax2::{
ast::{self, AstNode, NameOwner}, ast::{self, AstNode, NameOwner, ParsedFile},
SyntaxNode, ParsedFile, SmolStr, SyntaxNode, SmolStr,
}; };
use {FileId, FileResolver}; use {FileId, FileResolver};
type SyntaxProvider<'a> = dyn Fn(FileId) -> ParsedFile + 'a;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct ModuleId(FileId); pub struct ModuleId(FileId);
#[derive(Clone, Debug, Default)] #[derive(Debug, Default)]
pub struct ModuleMap { pub struct ModuleMap {
state: RwLock<State>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ChangeKind {
Delete, Insert, Update
}
impl Clone for ModuleMap {
fn clone(&self) -> ModuleMap {
let state = self.state.read().clone();
ModuleMap { state: RwLock::new(state) }
}
}
#[derive(Clone, Debug, Default)]
struct State {
changes: Vec<(FileId, ChangeKind)>,
links: Vec<Link>, links: Vec<Link>,
} }
@ -24,31 +45,8 @@ struct Link {
} }
impl ModuleMap { impl ModuleMap {
pub fn update_file( pub fn update_file(&mut self, file: FileId, change_kind: ChangeKind) {
&mut self, self.state.get_mut().changes.push((file, change_kind));
file_id: FileId,
syntax: Option<&ParsedFile>,
file_resolver: &FileResolver,
) {
let mod_id = ModuleId(file_id);
self.links.retain(|link| link.owner != mod_id);
match syntax {
None => {
for link in self.links.iter_mut() {
link.points_to.retain(|&x| x != mod_id);
}
}
Some(syntax) => {
self.links.extend(
syntax.ast().modules().filter_map(|it| {
Link::new(mod_id, it)
})
)
}
}
self.links.iter_mut().for_each(|link| {
link.resolve(file_resolver)
})
} }
pub fn module2file(&self, m: ModuleId) -> FileId { pub fn module2file(&self, m: ModuleId) -> FileId {
@ -59,8 +57,15 @@ impl ModuleMap {
ModuleId(file_id) ModuleId(file_id)
} }
pub fn child_module_by_name(&self, parent_mod: ModuleId, child_mod: &str) -> Vec<ModuleId> { pub fn child_module_by_name<'a>(
self.links &self,
parent_mod: ModuleId,
child_mod: &str,
file_resolver: &FileResolver,
syntax_provider: &SyntaxProvider,
) -> Vec<ModuleId> {
self.links(file_resolver, syntax_provider)
.links
.iter() .iter()
.filter(|link| link.owner == parent_mod) .filter(|link| link.owner == parent_mod)
.filter(|link| link.name() == child_mod) .filter(|link| link.name() == child_mod)
@ -69,13 +74,90 @@ impl ModuleMap {
.collect() .collect()
} }
pub fn parent_modules<'a>(&'a self, m: ModuleId) -> impl Iterator<Item=(ModuleId, ast::Module<'a>)> + 'a { pub fn parent_modules(
self.links &self,
m: ModuleId,
file_resolver: &FileResolver,
syntax_provider: &SyntaxProvider,
) -> Vec<(ModuleId, SmolStr, SyntaxNode)> {
let links = self.links(file_resolver, syntax_provider);
let res = links
.links
.iter() .iter()
.filter(move |link| link.points_to.iter().any(|&it| it == m)) .filter(move |link| link.points_to.iter().any(|&it| it == m))
.map(|link| { .map(|link| {
(link.owner, link.ast()) (link.owner, link.name().clone(), link.syntax.clone())
}) })
.collect();
res
}
fn links(
&self,
file_resolver: &FileResolver,
syntax_provider: &SyntaxProvider,
) -> RwLockReadGuard<State> {
{
let guard = self.state.read();
if guard.changes.is_empty() {
return guard;
}
}
let mut guard = self.state.write();
if !guard.changes.is_empty() {
guard.apply_changes(file_resolver, syntax_provider);
}
assert!(guard.changes.is_empty());
RwLockWriteGuard::downgrade(guard)
}
}
impl State {
pub fn apply_changes(
&mut self,
file_resolver: &FileResolver,
syntax_provider: &SyntaxProvider,
) {
let mut reresolve = false;
for (file_id, kind) in self.changes.drain(..) {
let mod_id = ModuleId(file_id);
self.links.retain(|link| link.owner != mod_id);
match kind {
ChangeKind::Delete => {
for link in self.links.iter_mut() {
link.points_to.retain(|&x| x != mod_id);
}
}
ChangeKind::Insert => {
let file = syntax_provider(file_id);
self.links.extend(
file
.ast()
.modules()
.filter_map(|it| Link::new(mod_id, it))
);
reresolve = true;
}
ChangeKind::Update => {
let file = syntax_provider(file_id);
self.links.extend(
file
.ast()
.modules()
.filter_map(|it| Link::new(mod_id, it))
.map(|mut link| {
link.resolve(file_resolver);
link
})
);
}
}
}
if reresolve {
for link in self.links.iter_mut() {
link.resolve(file_resolver)
}
}
} }
} }

View file

@ -252,7 +252,7 @@ fn on_notification(
fn handle_request_on_threadpool<R: req::ClientRequest>( fn handle_request_on_threadpool<R: req::ClientRequest>(
req: &mut Option<RawRequest>, req: &mut Option<RawRequest>,
pool: &ThreadPool, pool: &ThreadPool,
world: &mut ServerWorldState, world: &ServerWorldState,
sender: &Sender<Task>, sender: &Sender<Task>,
f: fn(ServerWorld, R::Params) -> Result<R::Result>, f: fn(ServerWorld, R::Params) -> Result<R::Result>,
) -> Result<()> ) -> Result<()>

View file

@ -86,7 +86,7 @@ impl ServerWorldState {
Ok(()) Ok(())
} }
pub fn snapshot(&mut self) -> ServerWorld { pub fn snapshot(&self) -> ServerWorld {
let pm = self.path_map.clone(); let pm = self.path_map.clone();
ServerWorld { ServerWorld {
analysis: self.analysis.snapshot(move |id, path| { analysis: self.analysis.snapshot(move |id, path| {