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 /crates/libanalysis/src/db.rs | |
parent | 3ae3b3eb0682a4550578b4c35dc6e099d8a04e66 (diff) |
Add simplisitc global modification caching
Diffstat (limited to 'crates/libanalysis/src/db.rs')
-rw-r--r-- | crates/libanalysis/src/db.rs | 116 |
1 files changed, 94 insertions, 22 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 | ||