use crate::bytecode::{FunctionBlob, FunctionHash};
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
pub struct BlobCache {
memory: HashMap<FunctionHash, FunctionBlob>,
disk_root: Option<PathBuf>,
stats: CacheStats,
}
#[derive(Debug, Default, Clone)]
pub struct CacheStats {
pub memory_hits: u64,
pub disk_hits: u64,
pub misses: u64,
pub insertions: u64,
pub evictions: u64,
}
impl BlobCache {
pub fn memory_only() -> Self {
Self {
memory: HashMap::new(),
disk_root: None,
stats: CacheStats::default(),
}
}
pub fn with_disk(root: PathBuf) -> std::io::Result<Self> {
fs::create_dir_all(&root)?;
Ok(Self {
memory: HashMap::new(),
disk_root: Some(root),
stats: CacheStats::default(),
})
}
pub fn has_blob(&self, hash: &FunctionHash) -> bool {
if self.memory.contains_key(hash) {
return true;
}
if let Some(ref root) = self.disk_root {
let path = Self::blob_path(root, hash);
return path.exists();
}
false
}
pub fn get_blob(&mut self, hash: &FunctionHash) -> Option<FunctionBlob> {
if let Some(blob) = self.memory.get(hash) {
self.stats.memory_hits += 1;
return Some(blob.clone());
}
if let Some(ref root) = self.disk_root {
let path = Self::blob_path(root, hash);
if let Ok(data) = fs::read(&path) {
if let Ok(blob) = rmp_serde::from_slice::<FunctionBlob>(&data) {
self.stats.disk_hits += 1;
self.memory.insert(*hash, blob.clone());
return Some(blob);
}
}
}
self.stats.misses += 1;
None
}
pub fn put_blob(&mut self, blob: &FunctionBlob) {
let hash = blob.content_hash;
self.memory.insert(hash, blob.clone());
self.stats.insertions += 1;
if let Some(ref root) = self.disk_root {
let path = Self::blob_path(root, &hash);
if let Some(parent) = path.parent() {
let _ = fs::create_dir_all(parent);
}
if let Ok(data) = rmp_serde::to_vec(blob) {
let _ = fs::write(&path, data);
}
}
}
pub fn stats(&self) -> &CacheStats {
&self.stats
}
pub fn clear_memory(&mut self) {
self.memory.clear();
}
pub fn memory_size(&self) -> usize {
self.memory.len()
}
fn blob_path(root: &PathBuf, hash: &FunctionHash) -> PathBuf {
let hex = hex::encode(hash.0);
root.join(&hex[..2]).join(format!("{}.blob", &hex[2..]))
}
}
pub struct JitCodeCache {
entries: HashMap<FunctionHash, *const u8>,
}
unsafe impl Send for JitCodeCache {}
unsafe impl Sync for JitCodeCache {}
impl JitCodeCache {
pub fn new() -> Self {
Self {
entries: HashMap::new(),
}
}
pub fn get(&self, hash: &FunctionHash) -> Option<*const u8> {
self.entries.get(hash).copied()
}
pub fn insert(&mut self, hash: FunctionHash, ptr: *const u8) {
self.entries.insert(hash, ptr);
}
pub fn contains(&self, hash: &FunctionHash) -> bool {
self.entries.contains_key(hash)
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}