From db14b4270c0b328f89a3a2262f2814b2f80b083c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 10 Sep 2018 21:53:33 +0300 Subject: Add simplisitc global modification caching --- crates/libanalysis/src/db.rs | 116 ++++++++++++++++++++++++++------ crates/libanalysis/src/lib.rs | 2 +- crates/libanalysis/src/module_map_db.rs | 24 ++++--- 3 files changed, 111 insertions(+), 31 deletions(-) diff --git a/crates/libanalysis/src/db.rs b/crates/libanalysis/src/db.rs index 5e3c8fb7a..31c73c402 100644 --- a/crates/libanalysis/src/db.rs +++ b/crates/libanalysis/src/db.rs @@ -2,50 +2,95 @@ use std::{ hash::Hash, sync::Arc, cell::RefCell, + fmt::Debug, }; +use parking_lot::Mutex; use libsyntax2::{File}; use im; use { FileId, imp::{FileResolverImp}, + module_map_db::ModuleDescr, }; -#[derive(Clone)] -pub(crate) struct Db { - file_resolver: FileResolverImp, - files: im::HashMap>, +#[derive(Debug)] +pub(crate) struct DbHost { + db: Arc, } -impl Db { - pub(crate) fn new() -> Db { - Db { +impl DbHost { + pub(crate) fn new() -> DbHost { + let db = Db { file_resolver: FileResolverImp::default(), files: im::HashMap::new(), - } + cache: Mutex::new(Cache::new()) + }; + DbHost { db: Arc::new(db) } } pub(crate) fn change_file(&mut self, file_id: FileId, text: Option) { + let db = self.db_mut(); match text { None => { - self.files.remove(&file_id); + db.files.remove(&file_id); } Some(text) => { - self.files.insert(file_id, Arc::new(text)); + db.files.insert(file_id, Arc::new(text)); } } } pub(crate) fn set_file_resolver(&mut self, file_resolver: FileResolverImp) { - self.file_resolver = file_resolver + let db = self.db_mut(); + db.file_resolver = file_resolver } pub(crate) fn query_ctx(&self) -> QueryCtx { QueryCtx { - db: self.clone(), + db: Arc::clone(&self.db), trace: RefCell::new(Vec::new()), } } + fn db_mut(&mut self) -> &mut Db { + // NB: this "forks" the database & clears the cache + let db = Arc::make_mut(&mut self.db); + *db.cache.get_mut() = Default::default(); + db + } +} + +#[derive(Debug)] +pub(crate) struct Db { + file_resolver: FileResolverImp, + files: im::HashMap>, + cache: Mutex, +} + +impl Clone for Db { + fn clone(&self) -> Db { + Db { + file_resolver: self.file_resolver.clone(), + files: self.files.clone(), + cache: Mutex::new(Cache::new()), + } + } +} + +#[derive(Clone, Default, Debug)] +pub(crate) struct Cache { + pub(crate) module_descr: QueryCache +} +#[allow(type_alias_bounds)] +pub(crate) type QueryCache = im::HashMap< + ::Params, + ::Output +>; + +impl Cache { + fn new() -> Cache { + Default::default() + } } pub(crate) struct QueryCtx { - db: Db, + db: Arc, pub(crate) trace: RefCell>, } @@ -62,9 +107,7 @@ pub(crate) enum TraceEventKind { impl QueryCtx { pub(crate) fn get(&self, params: &Q::Params) -> Q::Output { - self.trace(TraceEvent { query_id: Q::ID, kind: TraceEventKind::Start }); let res = Q::get(self, params); - self.trace(TraceEvent { query_id: Q::ID, kind: TraceEventKind::Finish }); res } fn trace(&self, event: TraceEvent) { @@ -74,26 +117,55 @@ impl QueryCtx { pub(crate) trait Query { const ID: u32; - type Params: Hash; - type Output; + type Params: Hash + Eq + Debug; + type Output: Debug; } pub(crate) trait Get: Query { fn get(ctx: &QueryCtx, params: &Self::Params) -> Self::Output; } -impl Get for T { +impl Get for T +where + T::Params: Clone, + T::Output: Clone, +{ fn get(ctx: &QueryCtx, params: &Self::Params) -> Self::Output { - Self::eval(ctx, params) + { + let mut cache = ctx.db.cache.lock(); + if let Some(cache) = Self::cache(&mut cache) { + if let Some(res) = cache.get(params) { + return res.clone(); + } + } + } + ctx.trace(TraceEvent { query_id: Self::ID, kind: TraceEventKind::Start }); + let res = Self::eval(ctx, params); + ctx.trace(TraceEvent { query_id: Self::ID, kind: TraceEventKind::Finish }); + + let mut cache = ctx.db.cache.lock(); + if let Some(cache) = Self::cache(&mut cache) { + cache.insert(params.clone(), res.clone()); + } + + res } } -pub(crate) trait Eval: Query { +pub(crate) trait Eval: Query +where + Self::Params: Clone, + Self::Output: Clone, + { + fn cache(_cache: &mut Cache) -> Option<&mut QueryCache> { + None + } fn eval(ctx: &QueryCtx, params: &Self::Params) -> Self::Output; } +#[derive(Debug)] pub(crate) struct DbFiles { - db: Db, + db: Arc, } impl DbFiles { @@ -113,7 +185,7 @@ impl Query for Files { } impl Get for Files { fn get(ctx: &QueryCtx, _params: &()) -> DbFiles { - DbFiles { db: ctx.db.clone() } + DbFiles { db: Arc::clone(&ctx.db) } } } diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs index 68cf31e08..3e77006c5 100644 --- a/crates/libanalysis/src/lib.rs +++ b/crates/libanalysis/src/lib.rs @@ -13,7 +13,7 @@ extern crate im; mod symbol_index; mod module_map; -mod module_map_db; +pub(crate) mod module_map_db; mod imp; mod job; mod roots; diff --git a/crates/libanalysis/src/module_map_db.rs b/crates/libanalysis/src/module_map_db.rs index 25dbe8dd4..14b156b43 100644 --- a/crates/libanalysis/src/module_map_db.rs +++ b/crates/libanalysis/src/module_map_db.rs @@ -1,11 +1,14 @@ use std::sync::Arc; use { FileId, - db::{Query, Eval, QueryCtx, FileSyntax, Files}, + db::{ + Query, Eval, QueryCtx, FileSyntax, Files, + Cache, QueryCache, + }, module_map::resolve_submodule, }; -enum ModuleDescr {} +pub(crate) enum ModuleDescr {} impl Query for ModuleDescr { const ID: u32 = 30; type Params = FileId; @@ -27,6 +30,9 @@ impl Query for ParentModule { } impl Eval for ModuleDescr { + fn cache(cache: &mut Cache) -> Option<&mut QueryCache> { + Some(&mut cache.module_descr) + } fn eval(ctx: &QueryCtx, file_id: &FileId) -> Arc { let file = ctx.get::(file_id); Arc::new(descr::ModuleDescr::new(file.ast())) @@ -66,6 +72,7 @@ mod descr { ast::{self, NameOwner}, }; + #[derive(Debug)] pub struct ModuleDescr { pub submodules: Vec } @@ -85,7 +92,7 @@ mod descr { ModuleDescr { submodules } } } - #[derive(Clone, Hash)] + #[derive(Clone, Hash, PartialEq, Eq, Debug)] pub struct Submodule { pub name: SmolStr, } @@ -98,7 +105,7 @@ mod tests { use im; use relative_path::{RelativePath, RelativePathBuf}; use { - db::{Query, Db, TraceEventKind}, + db::{Query, DbHost, TraceEventKind}, imp::FileResolverImp, FileId, FileResolver, }; @@ -122,7 +129,7 @@ mod tests { struct Fixture { next_file_id: u32, fm: im::HashMap, - db: Db, + db: DbHost, } impl Fixture { @@ -130,7 +137,7 @@ mod tests { Fixture { next_file_id: 1, fm: im::HashMap::new(), - db: Db::new(), + db: DbHost::new(), } } fn add_file(&mut self, path: &str, text: &str) -> FileId { @@ -185,10 +192,11 @@ mod tests { fn test_parent_module() { let mut f = Fixture::new(); let foo = f.add_file("/foo.rs", ""); - f.check_parent_modules(foo, &[], &[(FileSyntax::ID, 1)]); + f.check_parent_modules(foo, &[], &[(ModuleDescr::ID, 1)]); let lib = f.add_file("/lib.rs", "mod foo;"); - f.check_parent_modules(foo, &[lib], &[(FileSyntax::ID, 2)]); + f.check_parent_modules(foo, &[lib], &[(ModuleDescr::ID, 2)]); + f.check_parent_modules(foo, &[lib], &[(ModuleDescr::ID, 0)]); f.change_file(lib, ""); f.check_parent_modules(foo, &[], &[(ModuleDescr::ID, 2)]); -- cgit v1.2.3