Add simplisitc global modification caching

This commit is contained in:
Aleksey Kladov 2018-09-10 21:53:33 +03:00
parent 3ae3b3eb06
commit db14b4270c
3 changed files with 111 additions and 31 deletions

View file

@ -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<FileId, Arc<String>>,
#[derive(Debug)]
pub(crate) struct DbHost {
db: Arc<Db>,
}
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<String>) {
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<FileId, Arc<String>>,
cache: Mutex<Cache>,
}
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<ModuleDescr>
}
#[allow(type_alias_bounds)]
pub(crate) type QueryCache<Q: Query> = im::HashMap<
<Q as Query>::Params,
<Q as Query>::Output
>;
impl Cache {
fn new() -> Cache {
Default::default()
}
}
pub(crate) struct QueryCtx {
db: Db,
db: Arc<Db>,
pub(crate) trace: RefCell<Vec<TraceEvent>>,
}
@ -62,9 +107,7 @@ pub(crate) enum TraceEventKind {
impl QueryCtx {
pub(crate) fn get<Q: 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<T: Eval> Get for T {
impl<T: Eval> 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<Self>> {
None
}
fn eval(ctx: &QueryCtx, params: &Self::Params) -> Self::Output;
}
#[derive(Debug)]
pub(crate) struct DbFiles {
db: Db,
db: Arc<Db>,
}
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) }
}
}

View file

@ -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;

View file

@ -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<Self>> {
Some(&mut cache.module_descr)
}
fn eval(ctx: &QueryCtx, file_id: &FileId) -> Arc<descr::ModuleDescr> {
let file = ctx.get::<FileSyntax>(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<Submodule>
}
@ -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<FileId, RelativePathBuf>,
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)]);