use std::{
cell::RefCell,
num::NonZeroUsize,
rc::Rc,
sync::{Arc, Mutex, MutexGuard},
};
use crate::{
common::crypto::hash::Hash,
protocol::Protocol,
storage::mkvs::{sync::HostReadSyncer, Root, Tree},
types::HostStorageEndpoint,
};
thread_local! {
static QUERY_CACHE: RefCell<lru::LruCache<u64, Rc<RefCell<Cache>>>> = RefCell::new(lru::LruCache::new(NonZeroUsize::new(10).unwrap()));
}
#[derive(Clone)]
pub struct CacheSet {
protocol: Arc<Protocol>,
execute: Arc<Mutex<Cache>>,
check: Arc<Mutex<Cache>>,
}
impl CacheSet {
pub fn new(protocol: Arc<Protocol>) -> Self {
Self {
execute: Arc::new(Mutex::new(Cache::new(&protocol))),
check: Arc::new(Mutex::new(Cache::new(&protocol))),
protocol,
}
}
pub fn execute(&self, root: Root) -> MutexGuard<'_, Cache> {
let mut cache = self.execute.lock().unwrap();
cache.maybe_replace(&self.protocol, root);
cache
}
pub fn check(&self, root: Root) -> MutexGuard<'_, Cache> {
let mut cache = self.check.lock().unwrap();
cache.maybe_replace(&self.protocol, root);
cache
}
pub fn query(&self, root: Root) -> Rc<RefCell<Cache>> {
let cache = QUERY_CACHE.with(|caches| {
let mut caches = caches.borrow_mut();
if let Some(cache) = caches.get(&root.version) {
return cache.clone();
}
let cache = Rc::new(RefCell::new(Cache::new(&self.protocol)));
caches.put(root.version, cache.clone());
cache
});
cache.borrow_mut().maybe_replace(&self.protocol, root);
cache
}
}
pub struct Cache {
root: Root,
tree: Tree,
}
impl Cache {
fn new(protocol: &Arc<Protocol>) -> Self {
Self {
root: Default::default(),
tree: Self::build(protocol, Default::default()),
}
}
fn build(protocol: &Arc<Protocol>, root: Root) -> Tree {
let config = protocol.get_config();
let read_syncer = HostReadSyncer::new(protocol.clone(), HostStorageEndpoint::Runtime);
Tree::builder()
.with_capacity(
config.storage.cache_node_capacity,
config.storage.cache_value_capacity,
)
.with_root(root)
.build(Box::new(read_syncer))
}
fn maybe_replace(&mut self, protocol: &Arc<Protocol>, root: Root) {
if self.root == root {
return;
}
self.tree = Self::build(protocol, root);
self.root = root;
}
pub fn tree(&self) -> &Tree {
&self.tree
}
pub fn tree_mut(&mut self) -> &mut Tree {
&mut self.tree
}
pub fn commit(&mut self, version: u64, hash: Hash) {
self.root.version = version;
self.root.hash = hash;
}
}