oasis_core_runtime/
cache.rs1use std::{
3 cell::RefCell,
4 num::NonZeroUsize,
5 rc::Rc,
6 sync::{Arc, Mutex, MutexGuard},
7};
8
9use crate::{
10 common::crypto::hash::Hash,
11 protocol::Protocol,
12 storage::mkvs::{sync::HostReadSyncer, Root, Tree},
13 types::HostStorageEndpoint,
14};
15
16thread_local! {
17 static QUERY_CACHE: RefCell<lru::LruCache<u64, Rc<RefCell<Cache>>>> = RefCell::new(lru::LruCache::new(NonZeroUsize::new(10).unwrap()));
18}
19
20#[derive(Clone)]
28pub struct CacheSet {
29 protocol: Arc<Protocol>,
30 execute: Arc<Mutex<Cache>>,
31 check: Arc<Mutex<Cache>>,
32}
33
34impl CacheSet {
35 pub fn new(protocol: Arc<Protocol>) -> Self {
37 Self {
38 execute: Arc::new(Mutex::new(Cache::new(&protocol))),
39 check: Arc::new(Mutex::new(Cache::new(&protocol))),
40 protocol,
41 }
42 }
43
44 pub fn execute(&self, root: Root) -> MutexGuard<'_, Cache> {
46 let mut cache = self.execute.lock().unwrap();
47 cache.maybe_replace(&self.protocol, root);
48 cache
49 }
50
51 pub fn check(&self, root: Root) -> MutexGuard<'_, Cache> {
53 let mut cache = self.check.lock().unwrap();
54 cache.maybe_replace(&self.protocol, root);
55 cache
56 }
57
58 pub fn query(&self, root: Root) -> Rc<RefCell<Cache>> {
60 let cache = QUERY_CACHE.with(|caches| {
61 let mut caches = caches.borrow_mut();
62 if let Some(cache) = caches.get(&root.version) {
63 return cache.clone();
64 }
65
66 let cache = Rc::new(RefCell::new(Cache::new(&self.protocol)));
67 caches.put(root.version, cache.clone());
68 cache
69 });
70 cache.borrow_mut().maybe_replace(&self.protocol, root);
71 cache
72 }
73}
74
75pub struct Cache {
77 root: Root,
78 tree: Tree,
79}
80
81impl Cache {
82 fn new(protocol: &Arc<Protocol>) -> Self {
83 Self {
84 root: Default::default(),
85 tree: Self::build(protocol, Default::default()),
86 }
87 }
88
89 fn build(protocol: &Arc<Protocol>, root: Root) -> Tree {
90 let config = protocol.get_config();
91 let read_syncer = HostReadSyncer::new(protocol.clone(), HostStorageEndpoint::Runtime);
92 Tree::builder()
93 .with_capacity(
94 config.storage.cache_node_capacity,
95 config.storage.cache_value_capacity,
96 )
97 .with_root(root)
98 .build(Box::new(read_syncer))
99 }
100
101 fn maybe_replace(&mut self, protocol: &Arc<Protocol>, root: Root) {
102 if self.root == root {
103 return;
104 }
105
106 self.tree = Self::build(protocol, root);
107 self.root = root;
108 }
109
110 pub fn tree(&self) -> &Tree {
112 &self.tree
113 }
114
115 pub fn tree_mut(&mut self) -> &mut Tree {
117 &mut self.tree
118 }
119
120 pub fn commit(&mut self, version: u64, hash: Hash) {
122 self.root.version = version;
123 self.root.hash = hash;
124 }
125}