diff options
author | Aleksey Kladov <[email protected]> | 2018-09-10 19:53:33 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-09-15 22:00:05 +0100 |
commit | db14b4270c0b328f89a3a2262f2814b2f80b083c (patch) | |
tree | 828807a713f8acb5543e2a12768b4e6accba2491 | |
parent | 3ae3b3eb0682a4550578b4c35dc6e099d8a04e66 (diff) |
Add simplisitc global modification caching
-rw-r--r-- | crates/libanalysis/src/db.rs | 116 | ||||
-rw-r--r-- | crates/libanalysis/src/lib.rs | 2 | ||||
-rw-r--r-- | 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::{ | |||
2 | hash::Hash, | 2 | hash::Hash, |
3 | sync::Arc, | 3 | sync::Arc, |
4 | cell::RefCell, | 4 | cell::RefCell, |
5 | fmt::Debug, | ||
5 | }; | 6 | }; |
7 | use parking_lot::Mutex; | ||
6 | use libsyntax2::{File}; | 8 | use libsyntax2::{File}; |
7 | use im; | 9 | use im; |
8 | use { | 10 | use { |
9 | FileId, | 11 | FileId, |
10 | imp::{FileResolverImp}, | 12 | imp::{FileResolverImp}, |
13 | module_map_db::ModuleDescr, | ||
11 | }; | 14 | }; |
12 | 15 | ||
13 | #[derive(Clone)] | 16 | #[derive(Debug)] |
14 | pub(crate) struct Db { | 17 | pub(crate) struct DbHost { |
15 | file_resolver: FileResolverImp, | 18 | db: Arc<Db>, |
16 | files: im::HashMap<FileId, Arc<String>>, | ||
17 | } | 19 | } |
18 | 20 | ||
19 | impl Db { | 21 | impl DbHost { |
20 | pub(crate) fn new() -> Db { | 22 | pub(crate) fn new() -> DbHost { |
21 | Db { | 23 | let db = Db { |
22 | file_resolver: FileResolverImp::default(), | 24 | file_resolver: FileResolverImp::default(), |
23 | files: im::HashMap::new(), | 25 | files: im::HashMap::new(), |
24 | } | 26 | cache: Mutex::new(Cache::new()) |
27 | }; | ||
28 | DbHost { db: Arc::new(db) } | ||
25 | } | 29 | } |
26 | pub(crate) fn change_file(&mut self, file_id: FileId, text: Option<String>) { | 30 | pub(crate) fn change_file(&mut self, file_id: FileId, text: Option<String>) { |
31 | let db = self.db_mut(); | ||
27 | match text { | 32 | match text { |
28 | None => { | 33 | None => { |
29 | self.files.remove(&file_id); | 34 | db.files.remove(&file_id); |
30 | } | 35 | } |
31 | Some(text) => { | 36 | Some(text) => { |
32 | self.files.insert(file_id, Arc::new(text)); | 37 | db.files.insert(file_id, Arc::new(text)); |
33 | } | 38 | } |
34 | } | 39 | } |
35 | } | 40 | } |
36 | pub(crate) fn set_file_resolver(&mut self, file_resolver: FileResolverImp) { | 41 | pub(crate) fn set_file_resolver(&mut self, file_resolver: FileResolverImp) { |
37 | self.file_resolver = file_resolver | 42 | let db = self.db_mut(); |
43 | db.file_resolver = file_resolver | ||
38 | } | 44 | } |
39 | pub(crate) fn query_ctx(&self) -> QueryCtx { | 45 | pub(crate) fn query_ctx(&self) -> QueryCtx { |
40 | QueryCtx { | 46 | QueryCtx { |
41 | db: self.clone(), | 47 | db: Arc::clone(&self.db), |
42 | trace: RefCell::new(Vec::new()), | 48 | trace: RefCell::new(Vec::new()), |
43 | } | 49 | } |
44 | } | 50 | } |
51 | fn db_mut(&mut self) -> &mut Db { | ||
52 | // NB: this "forks" the database & clears the cache | ||
53 | let db = Arc::make_mut(&mut self.db); | ||
54 | *db.cache.get_mut() = Default::default(); | ||
55 | db | ||
56 | } | ||
57 | } | ||
58 | |||
59 | #[derive(Debug)] | ||
60 | pub(crate) struct Db { | ||
61 | file_resolver: FileResolverImp, | ||
62 | files: im::HashMap<FileId, Arc<String>>, | ||
63 | cache: Mutex<Cache>, | ||
64 | } | ||
65 | |||
66 | impl Clone for Db { | ||
67 | fn clone(&self) -> Db { | ||
68 | Db { | ||
69 | file_resolver: self.file_resolver.clone(), | ||
70 | files: self.files.clone(), | ||
71 | cache: Mutex::new(Cache::new()), | ||
72 | } | ||
73 | } | ||
74 | } | ||
75 | |||
76 | #[derive(Clone, Default, Debug)] | ||
77 | pub(crate) struct Cache { | ||
78 | pub(crate) module_descr: QueryCache<ModuleDescr> | ||
79 | } | ||
80 | #[allow(type_alias_bounds)] | ||
81 | pub(crate) type QueryCache<Q: Query> = im::HashMap< | ||
82 | <Q as Query>::Params, | ||
83 | <Q as Query>::Output | ||
84 | >; | ||
85 | |||
86 | impl Cache { | ||
87 | fn new() -> Cache { | ||
88 | Default::default() | ||
89 | } | ||
45 | } | 90 | } |
46 | 91 | ||
47 | pub(crate) struct QueryCtx { | 92 | pub(crate) struct QueryCtx { |
48 | db: Db, | 93 | db: Arc<Db>, |
49 | pub(crate) trace: RefCell<Vec<TraceEvent>>, | 94 | pub(crate) trace: RefCell<Vec<TraceEvent>>, |
50 | } | 95 | } |
51 | 96 | ||
@@ -62,9 +107,7 @@ pub(crate) enum TraceEventKind { | |||
62 | 107 | ||
63 | impl QueryCtx { | 108 | impl QueryCtx { |
64 | pub(crate) fn get<Q: Get>(&self, params: &Q::Params) -> Q::Output { | 109 | pub(crate) fn get<Q: Get>(&self, params: &Q::Params) -> Q::Output { |
65 | self.trace(TraceEvent { query_id: Q::ID, kind: TraceEventKind::Start }); | ||
66 | let res = Q::get(self, params); | 110 | let res = Q::get(self, params); |
67 | self.trace(TraceEvent { query_id: Q::ID, kind: TraceEventKind::Finish }); | ||
68 | res | 111 | res |
69 | } | 112 | } |
70 | fn trace(&self, event: TraceEvent) { | 113 | fn trace(&self, event: TraceEvent) { |
@@ -74,26 +117,55 @@ impl QueryCtx { | |||
74 | 117 | ||
75 | pub(crate) trait Query { | 118 | pub(crate) trait Query { |
76 | const ID: u32; | 119 | const ID: u32; |
77 | type Params: Hash; | 120 | type Params: Hash + Eq + Debug; |
78 | type Output; | 121 | type Output: Debug; |
79 | } | 122 | } |
80 | 123 | ||
81 | pub(crate) trait Get: Query { | 124 | pub(crate) trait Get: Query { |
82 | fn get(ctx: &QueryCtx, params: &Self::Params) -> Self::Output; | 125 | fn get(ctx: &QueryCtx, params: &Self::Params) -> Self::Output; |
83 | } | 126 | } |
84 | 127 | ||
85 | impl<T: Eval> Get for T { | 128 | impl<T: Eval> Get for T |
129 | where | ||
130 | T::Params: Clone, | ||
131 | T::Output: Clone, | ||
132 | { | ||
86 | fn get(ctx: &QueryCtx, params: &Self::Params) -> Self::Output { | 133 | fn get(ctx: &QueryCtx, params: &Self::Params) -> Self::Output { |
87 | Self::eval(ctx, params) | 134 | { |
135 | let mut cache = ctx.db.cache.lock(); | ||
136 | if let Some(cache) = Self::cache(&mut cache) { | ||
137 | if let Some(res) = cache.get(params) { | ||
138 | return res.clone(); | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | ctx.trace(TraceEvent { query_id: Self::ID, kind: TraceEventKind::Start }); | ||
143 | let res = Self::eval(ctx, params); | ||
144 | ctx.trace(TraceEvent { query_id: Self::ID, kind: TraceEventKind::Finish }); | ||
145 | |||
146 | let mut cache = ctx.db.cache.lock(); | ||
147 | if let Some(cache) = Self::cache(&mut cache) { | ||
148 | cache.insert(params.clone(), res.clone()); | ||
149 | } | ||
150 | |||
151 | res | ||
88 | } | 152 | } |
89 | } | 153 | } |
90 | 154 | ||
91 | pub(crate) trait Eval: Query { | 155 | pub(crate) trait Eval: Query |
156 | where | ||
157 | Self::Params: Clone, | ||
158 | Self::Output: Clone, | ||
159 | { | ||
160 | fn cache(_cache: &mut Cache) -> Option<&mut QueryCache<Self>> { | ||
161 | None | ||
162 | } | ||
92 | fn eval(ctx: &QueryCtx, params: &Self::Params) -> Self::Output; | 163 | fn eval(ctx: &QueryCtx, params: &Self::Params) -> Self::Output; |
93 | } | 164 | } |
94 | 165 | ||
166 | #[derive(Debug)] | ||
95 | pub(crate) struct DbFiles { | 167 | pub(crate) struct DbFiles { |
96 | db: Db, | 168 | db: Arc<Db>, |
97 | } | 169 | } |
98 | 170 | ||
99 | impl DbFiles { | 171 | impl DbFiles { |
@@ -113,7 +185,7 @@ impl Query for Files { | |||
113 | } | 185 | } |
114 | impl Get for Files { | 186 | impl Get for Files { |
115 | fn get(ctx: &QueryCtx, _params: &()) -> DbFiles { | 187 | fn get(ctx: &QueryCtx, _params: &()) -> DbFiles { |
116 | DbFiles { db: ctx.db.clone() } | 188 | DbFiles { db: Arc::clone(&ctx.db) } |
117 | } | 189 | } |
118 | } | 190 | } |
119 | 191 | ||
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; | |||
13 | 13 | ||
14 | mod symbol_index; | 14 | mod symbol_index; |
15 | mod module_map; | 15 | mod module_map; |
16 | mod module_map_db; | 16 | pub(crate) mod module_map_db; |
17 | mod imp; | 17 | mod imp; |
18 | mod job; | 18 | mod job; |
19 | mod roots; | 19 | 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 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | use { | 2 | use { |
3 | FileId, | 3 | FileId, |
4 | db::{Query, Eval, QueryCtx, FileSyntax, Files}, | 4 | db::{ |
5 | Query, Eval, QueryCtx, FileSyntax, Files, | ||
6 | Cache, QueryCache, | ||
7 | }, | ||
5 | module_map::resolve_submodule, | 8 | module_map::resolve_submodule, |
6 | }; | 9 | }; |
7 | 10 | ||
8 | enum ModuleDescr {} | 11 | pub(crate) enum ModuleDescr {} |
9 | impl Query for ModuleDescr { | 12 | impl Query for ModuleDescr { |
10 | const ID: u32 = 30; | 13 | const ID: u32 = 30; |
11 | type Params = FileId; | 14 | type Params = FileId; |
@@ -27,6 +30,9 @@ impl Query for ParentModule { | |||
27 | } | 30 | } |
28 | 31 | ||
29 | impl Eval for ModuleDescr { | 32 | impl Eval for ModuleDescr { |
33 | fn cache(cache: &mut Cache) -> Option<&mut QueryCache<Self>> { | ||
34 | Some(&mut cache.module_descr) | ||
35 | } | ||
30 | fn eval(ctx: &QueryCtx, file_id: &FileId) -> Arc<descr::ModuleDescr> { | 36 | fn eval(ctx: &QueryCtx, file_id: &FileId) -> Arc<descr::ModuleDescr> { |
31 | let file = ctx.get::<FileSyntax>(file_id); | 37 | let file = ctx.get::<FileSyntax>(file_id); |
32 | Arc::new(descr::ModuleDescr::new(file.ast())) | 38 | Arc::new(descr::ModuleDescr::new(file.ast())) |
@@ -66,6 +72,7 @@ mod descr { | |||
66 | ast::{self, NameOwner}, | 72 | ast::{self, NameOwner}, |
67 | }; | 73 | }; |
68 | 74 | ||
75 | #[derive(Debug)] | ||
69 | pub struct ModuleDescr { | 76 | pub struct ModuleDescr { |
70 | pub submodules: Vec<Submodule> | 77 | pub submodules: Vec<Submodule> |
71 | } | 78 | } |
@@ -85,7 +92,7 @@ mod descr { | |||
85 | ModuleDescr { submodules } } | 92 | ModuleDescr { submodules } } |
86 | } | 93 | } |
87 | 94 | ||
88 | #[derive(Clone, Hash)] | 95 | #[derive(Clone, Hash, PartialEq, Eq, Debug)] |
89 | pub struct Submodule { | 96 | pub struct Submodule { |
90 | pub name: SmolStr, | 97 | pub name: SmolStr, |
91 | } | 98 | } |
@@ -98,7 +105,7 @@ mod tests { | |||
98 | use im; | 105 | use im; |
99 | use relative_path::{RelativePath, RelativePathBuf}; | 106 | use relative_path::{RelativePath, RelativePathBuf}; |
100 | use { | 107 | use { |
101 | db::{Query, Db, TraceEventKind}, | 108 | db::{Query, DbHost, TraceEventKind}, |
102 | imp::FileResolverImp, | 109 | imp::FileResolverImp, |
103 | FileId, FileResolver, | 110 | FileId, FileResolver, |
104 | }; | 111 | }; |
@@ -122,7 +129,7 @@ mod tests { | |||
122 | struct Fixture { | 129 | struct Fixture { |
123 | next_file_id: u32, | 130 | next_file_id: u32, |
124 | fm: im::HashMap<FileId, RelativePathBuf>, | 131 | fm: im::HashMap<FileId, RelativePathBuf>, |
125 | db: Db, | 132 | db: DbHost, |
126 | } | 133 | } |
127 | 134 | ||
128 | impl Fixture { | 135 | impl Fixture { |
@@ -130,7 +137,7 @@ mod tests { | |||
130 | Fixture { | 137 | Fixture { |
131 | next_file_id: 1, | 138 | next_file_id: 1, |
132 | fm: im::HashMap::new(), | 139 | fm: im::HashMap::new(), |
133 | db: Db::new(), | 140 | db: DbHost::new(), |
134 | } | 141 | } |
135 | } | 142 | } |
136 | fn add_file(&mut self, path: &str, text: &str) -> FileId { | 143 | fn add_file(&mut self, path: &str, text: &str) -> FileId { |
@@ -185,10 +192,11 @@ mod tests { | |||
185 | fn test_parent_module() { | 192 | fn test_parent_module() { |
186 | let mut f = Fixture::new(); | 193 | let mut f = Fixture::new(); |
187 | let foo = f.add_file("/foo.rs", ""); | 194 | let foo = f.add_file("/foo.rs", ""); |
188 | f.check_parent_modules(foo, &[], &[(FileSyntax::ID, 1)]); | 195 | f.check_parent_modules(foo, &[], &[(ModuleDescr::ID, 1)]); |
189 | 196 | ||
190 | let lib = f.add_file("/lib.rs", "mod foo;"); | 197 | let lib = f.add_file("/lib.rs", "mod foo;"); |
191 | f.check_parent_modules(foo, &[lib], &[(FileSyntax::ID, 2)]); | 198 | f.check_parent_modules(foo, &[lib], &[(ModuleDescr::ID, 2)]); |
199 | f.check_parent_modules(foo, &[lib], &[(ModuleDescr::ID, 0)]); | ||
192 | 200 | ||
193 | f.change_file(lib, ""); | 201 | f.change_file(lib, ""); |
194 | f.check_parent_modules(foo, &[], &[(ModuleDescr::ID, 2)]); | 202 | f.check_parent_modules(foo, &[], &[(ModuleDescr::ID, 2)]); |