tp_state_machine/changes_trie/
build_cache.rs1use std::collections::{HashMap, HashSet};
21
22use crate::StorageKey;
23use tet_core::storage::PrefixedStorageKey;
24
25pub struct BuildCache<H, N> {
37 roots_by_number: HashMap<N, H>,
39 changed_keys: HashMap<H, HashMap<Option<PrefixedStorageKey>, HashSet<StorageKey>>>,
44}
45
46#[derive(Debug, PartialEq)]
48pub enum CacheAction<H, N> {
49 CacheBuildData(CachedBuildData<H, N>),
51 Clear,
53}
54
55#[derive(Debug, PartialEq)]
57pub struct CachedBuildData<H, N> {
58 block: N,
59 trie_root: H,
60 digest_input_blocks: Vec<N>,
61 changed_keys: HashMap<Option<PrefixedStorageKey>, HashSet<StorageKey>>,
62}
63
64#[derive(Debug, PartialEq)]
66pub(crate) enum IncompleteCacheAction<N> {
67 CacheBuildData(IncompleteCachedBuildData<N>),
69 Clear,
71}
72
73#[derive(Debug, PartialEq)]
75pub(crate) struct IncompleteCachedBuildData<N> {
76 digest_input_blocks: Vec<N>,
77 changed_keys: HashMap<Option<PrefixedStorageKey>, HashSet<StorageKey>>,
78}
79
80impl<H, N> BuildCache<H, N>
81 where
82 N: Eq + ::std::hash::Hash,
83 H: Eq + ::std::hash::Hash + Clone,
84{
85 pub fn new() -> Self {
87 BuildCache {
88 roots_by_number: HashMap::new(),
89 changed_keys: HashMap::new(),
90 }
91 }
92
93 pub fn get(&self, root: &H) -> Option<&HashMap<Option<PrefixedStorageKey>, HashSet<StorageKey>>> {
95 self.changed_keys.get(&root)
96 }
97
98 pub fn with_changed_keys(
101 &self,
102 root: &H,
103 functor: &mut dyn FnMut(&HashMap<Option<PrefixedStorageKey>, HashSet<StorageKey>>),
104 ) -> bool {
105 match self.changed_keys.get(&root) {
106 Some(changed_keys) => {
107 functor(changed_keys);
108 true
109 },
110 None => false,
111 }
112 }
113
114 pub fn perform(&mut self, action: CacheAction<H, N>) {
116 match action {
117 CacheAction::CacheBuildData(data) => {
118 self.roots_by_number.insert(data.block, data.trie_root.clone());
119 self.changed_keys.insert(data.trie_root, data.changed_keys);
120
121 for digest_input_block in data.digest_input_blocks {
122 let digest_input_block_hash = self.roots_by_number.remove(&digest_input_block);
123 if let Some(digest_input_block_hash) = digest_input_block_hash {
124 self.changed_keys.remove(&digest_input_block_hash);
125 }
126 }
127 },
128 CacheAction::Clear => {
129 self.roots_by_number.clear();
130 self.changed_keys.clear();
131 },
132 }
133 }
134}
135
136impl<N> IncompleteCacheAction<N> {
137 pub fn collects_changed_keys(&self) -> bool {
139 match *self {
140 IncompleteCacheAction::CacheBuildData(_) => true,
141 IncompleteCacheAction::Clear => false,
142 }
143 }
144
145 pub(crate) fn complete<H: Clone>(self, block: N, trie_root: &H) -> CacheAction<H, N> {
147 match self {
148 IncompleteCacheAction::CacheBuildData(build_data) =>
149 CacheAction::CacheBuildData(build_data.complete(block, trie_root.clone())),
150 IncompleteCacheAction::Clear => CacheAction::Clear,
151 }
152 }
153
154 pub(crate) fn set_digest_input_blocks(self, digest_input_blocks: Vec<N>) -> Self {
159 match self {
160 IncompleteCacheAction::CacheBuildData(build_data) =>
161 IncompleteCacheAction::CacheBuildData(build_data.set_digest_input_blocks(digest_input_blocks)),
162 IncompleteCacheAction::Clear => IncompleteCacheAction::Clear,
163 }
164 }
165
166 pub(crate) fn insert(
168 self,
169 storage_key: Option<PrefixedStorageKey>,
170 changed_keys: HashSet<StorageKey>,
171 ) -> Self {
172 match self {
173 IncompleteCacheAction::CacheBuildData(build_data) =>
174 IncompleteCacheAction::CacheBuildData(build_data.insert(storage_key, changed_keys)),
175 IncompleteCacheAction::Clear => IncompleteCacheAction::Clear,
176 }
177 }
178}
179
180impl<N> IncompleteCachedBuildData<N> {
181 pub(crate) fn new() -> Self {
183 IncompleteCachedBuildData {
184 digest_input_blocks: Vec::new(),
185 changed_keys: HashMap::new(),
186 }
187 }
188
189 fn complete<H>(self, block: N, trie_root: H) -> CachedBuildData<H, N> {
190 CachedBuildData {
191 block,
192 trie_root,
193 digest_input_blocks: self.digest_input_blocks,
194 changed_keys: self.changed_keys,
195 }
196 }
197
198 fn set_digest_input_blocks(mut self, digest_input_blocks: Vec<N>) -> Self {
199 self.digest_input_blocks = digest_input_blocks;
200 self
201 }
202
203 fn insert(
204 mut self,
205 storage_key: Option<PrefixedStorageKey>,
206 changed_keys: HashSet<StorageKey>,
207 ) -> Self {
208 self.changed_keys.insert(storage_key, changed_keys);
209 self
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216
217 #[test]
218 fn updated_keys_are_stored_when_non_top_level_digest_is_built() {
219 let mut data = IncompleteCachedBuildData::<u32>::new();
220 data = data.insert(None, vec![vec![1]].into_iter().collect());
221 assert_eq!(data.changed_keys.len(), 1);
222
223 let mut cache = BuildCache::new();
224 cache.perform(CacheAction::CacheBuildData(data.complete(1, 1)));
225 assert_eq!(cache.changed_keys.len(), 1);
226 assert_eq!(
227 cache.get(&1).unwrap().clone(),
228 vec![(None, vec![vec![1]].into_iter().collect())].into_iter().collect(),
229 );
230 }
231
232 #[test]
233 fn obsolete_entries_are_purged_when_new_ct_is_built() {
234 let mut cache = BuildCache::<u32, u32>::new();
235 cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
236 .insert(None, vec![vec![1]].into_iter().collect())
237 .complete(1, 1)));
238 cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
239 .insert(None, vec![vec![2]].into_iter().collect())
240 .complete(2, 2)));
241 cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
242 .insert(None, vec![vec![3]].into_iter().collect())
243 .complete(3, 3)));
244
245 assert_eq!(cache.changed_keys.len(), 3);
246
247 cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
248 .set_digest_input_blocks(vec![1, 2, 3])
249 .complete(4, 4)));
250
251 assert_eq!(cache.changed_keys.len(), 1);
252
253 cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
254 .insert(None, vec![vec![8]].into_iter().collect())
255 .complete(8, 8)));
256 cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
257 .insert(None, vec![vec![12]].into_iter().collect())
258 .complete(12, 12)));
259
260 assert_eq!(cache.changed_keys.len(), 3);
261
262 cache.perform(CacheAction::Clear);
263
264 assert_eq!(cache.changed_keys.len(), 0);
265 }
266}