mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-27 04:15:08 +00:00
Add simplisitc global modification caching
This commit is contained in:
parent
3ae3b3eb06
commit
db14b4270c
3 changed files with 111 additions and 31 deletions
|
@ -2,50 +2,95 @@ use std::{
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
|
fmt::Debug,
|
||||||
};
|
};
|
||||||
|
use parking_lot::Mutex;
|
||||||
use libsyntax2::{File};
|
use libsyntax2::{File};
|
||||||
use im;
|
use im;
|
||||||
use {
|
use {
|
||||||
FileId,
|
FileId,
|
||||||
imp::{FileResolverImp},
|
imp::{FileResolverImp},
|
||||||
|
module_map_db::ModuleDescr,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Db {
|
pub(crate) struct DbHost {
|
||||||
file_resolver: FileResolverImp,
|
db: Arc<Db>,
|
||||||
files: im::HashMap<FileId, Arc<String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Db {
|
impl DbHost {
|
||||||
pub(crate) fn new() -> Db {
|
pub(crate) fn new() -> DbHost {
|
||||||
Db {
|
let db = Db {
|
||||||
file_resolver: FileResolverImp::default(),
|
file_resolver: FileResolverImp::default(),
|
||||||
files: im::HashMap::new(),
|
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>) {
|
pub(crate) fn change_file(&mut self, file_id: FileId, text: Option<String>) {
|
||||||
|
let db = self.db_mut();
|
||||||
match text {
|
match text {
|
||||||
None => {
|
None => {
|
||||||
self.files.remove(&file_id);
|
db.files.remove(&file_id);
|
||||||
}
|
}
|
||||||
Some(text) => {
|
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) {
|
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 {
|
pub(crate) fn query_ctx(&self) -> QueryCtx {
|
||||||
QueryCtx {
|
QueryCtx {
|
||||||
db: self.clone(),
|
db: Arc::clone(&self.db),
|
||||||
trace: RefCell::new(Vec::new()),
|
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 {
|
pub(crate) struct QueryCtx {
|
||||||
db: Db,
|
db: Arc<Db>,
|
||||||
pub(crate) trace: RefCell<Vec<TraceEvent>>,
|
pub(crate) trace: RefCell<Vec<TraceEvent>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,9 +107,7 @@ pub(crate) enum TraceEventKind {
|
||||||
|
|
||||||
impl QueryCtx {
|
impl QueryCtx {
|
||||||
pub(crate) fn get<Q: Get>(&self, params: &Q::Params) -> Q::Output {
|
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);
|
let res = Q::get(self, params);
|
||||||
self.trace(TraceEvent { query_id: Q::ID, kind: TraceEventKind::Finish });
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
fn trace(&self, event: TraceEvent) {
|
fn trace(&self, event: TraceEvent) {
|
||||||
|
@ -74,26 +117,55 @@ impl QueryCtx {
|
||||||
|
|
||||||
pub(crate) trait Query {
|
pub(crate) trait Query {
|
||||||
const ID: u32;
|
const ID: u32;
|
||||||
type Params: Hash;
|
type Params: Hash + Eq + Debug;
|
||||||
type Output;
|
type Output: Debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait Get: Query {
|
pub(crate) trait Get: Query {
|
||||||
fn get(ctx: &QueryCtx, params: &Self::Params) -> Self::Output;
|
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 {
|
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;
|
fn eval(ctx: &QueryCtx, params: &Self::Params) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct DbFiles {
|
pub(crate) struct DbFiles {
|
||||||
db: Db,
|
db: Arc<Db>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DbFiles {
|
impl DbFiles {
|
||||||
|
@ -113,7 +185,7 @@ impl Query for Files {
|
||||||
}
|
}
|
||||||
impl Get for Files {
|
impl Get for Files {
|
||||||
fn get(ctx: &QueryCtx, _params: &()) -> DbFiles {
|
fn get(ctx: &QueryCtx, _params: &()) -> DbFiles {
|
||||||
DbFiles { db: ctx.db.clone() }
|
DbFiles { db: Arc::clone(&ctx.db) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ extern crate im;
|
||||||
|
|
||||||
mod symbol_index;
|
mod symbol_index;
|
||||||
mod module_map;
|
mod module_map;
|
||||||
mod module_map_db;
|
pub(crate) mod module_map_db;
|
||||||
mod imp;
|
mod imp;
|
||||||
mod job;
|
mod job;
|
||||||
mod roots;
|
mod roots;
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use {
|
use {
|
||||||
FileId,
|
FileId,
|
||||||
db::{Query, Eval, QueryCtx, FileSyntax, Files},
|
db::{
|
||||||
|
Query, Eval, QueryCtx, FileSyntax, Files,
|
||||||
|
Cache, QueryCache,
|
||||||
|
},
|
||||||
module_map::resolve_submodule,
|
module_map::resolve_submodule,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ModuleDescr {}
|
pub(crate) enum ModuleDescr {}
|
||||||
impl Query for ModuleDescr {
|
impl Query for ModuleDescr {
|
||||||
const ID: u32 = 30;
|
const ID: u32 = 30;
|
||||||
type Params = FileId;
|
type Params = FileId;
|
||||||
|
@ -27,6 +30,9 @@ impl Query for ParentModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ModuleDescr {
|
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> {
|
fn eval(ctx: &QueryCtx, file_id: &FileId) -> Arc<descr::ModuleDescr> {
|
||||||
let file = ctx.get::<FileSyntax>(file_id);
|
let file = ctx.get::<FileSyntax>(file_id);
|
||||||
Arc::new(descr::ModuleDescr::new(file.ast()))
|
Arc::new(descr::ModuleDescr::new(file.ast()))
|
||||||
|
@ -66,6 +72,7 @@ mod descr {
|
||||||
ast::{self, NameOwner},
|
ast::{self, NameOwner},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ModuleDescr {
|
pub struct ModuleDescr {
|
||||||
pub submodules: Vec<Submodule>
|
pub submodules: Vec<Submodule>
|
||||||
}
|
}
|
||||||
|
@ -85,7 +92,7 @@ mod descr {
|
||||||
ModuleDescr { submodules } }
|
ModuleDescr { submodules } }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
|
||||||
pub struct Submodule {
|
pub struct Submodule {
|
||||||
pub name: SmolStr,
|
pub name: SmolStr,
|
||||||
}
|
}
|
||||||
|
@ -98,7 +105,7 @@ mod tests {
|
||||||
use im;
|
use im;
|
||||||
use relative_path::{RelativePath, RelativePathBuf};
|
use relative_path::{RelativePath, RelativePathBuf};
|
||||||
use {
|
use {
|
||||||
db::{Query, Db, TraceEventKind},
|
db::{Query, DbHost, TraceEventKind},
|
||||||
imp::FileResolverImp,
|
imp::FileResolverImp,
|
||||||
FileId, FileResolver,
|
FileId, FileResolver,
|
||||||
};
|
};
|
||||||
|
@ -122,7 +129,7 @@ mod tests {
|
||||||
struct Fixture {
|
struct Fixture {
|
||||||
next_file_id: u32,
|
next_file_id: u32,
|
||||||
fm: im::HashMap<FileId, RelativePathBuf>,
|
fm: im::HashMap<FileId, RelativePathBuf>,
|
||||||
db: Db,
|
db: DbHost,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fixture {
|
impl Fixture {
|
||||||
|
@ -130,7 +137,7 @@ mod tests {
|
||||||
Fixture {
|
Fixture {
|
||||||
next_file_id: 1,
|
next_file_id: 1,
|
||||||
fm: im::HashMap::new(),
|
fm: im::HashMap::new(),
|
||||||
db: Db::new(),
|
db: DbHost::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn add_file(&mut self, path: &str, text: &str) -> FileId {
|
fn add_file(&mut self, path: &str, text: &str) -> FileId {
|
||||||
|
@ -185,10 +192,11 @@ mod tests {
|
||||||
fn test_parent_module() {
|
fn test_parent_module() {
|
||||||
let mut f = Fixture::new();
|
let mut f = Fixture::new();
|
||||||
let foo = f.add_file("/foo.rs", "");
|
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;");
|
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.change_file(lib, "");
|
||||||
f.check_parent_modules(foo, &[], &[(ModuleDescr::ID, 2)]);
|
f.check_parent_modules(foo, &[], &[(ModuleDescr::ID, 2)]);
|
||||||
|
|
Loading…
Reference in a new issue