aboutsummaryrefslogtreecommitdiff
path: root/base/src/cache.rs
diff options
context:
space:
mode:
Diffstat (limited to 'base/src/cache.rs')
-rw-r--r--base/src/cache.rs66
1 files changed, 65 insertions, 1 deletions
diff --git a/base/src/cache.rs b/base/src/cache.rs
index e580130..d1c3e4d 100644
--- a/base/src/cache.rs
+++ b/base/src/cache.rs
@@ -24,7 +24,10 @@ use std::{
},
time::Instant,
};
-use tokio::sync::Mutex;
+use tokio::{
+ io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt},
+ sync::Mutex,
+};
pub fn cache_location(seed: &[&str]) -> (usize, AssetLocation) {
use sha2::Digest;
@@ -169,6 +172,67 @@ where
Ok(object)
}
+pub async fn async_cache_memory<Fun, Fut, T>(
+ seed: &[&str],
+ mut generate: Fun,
+) -> Result<Arc<T>, anyhow::Error>
+where
+ Fun: FnMut() -> Fut,
+ Fut: Future<Output = Result<T, anyhow::Error>>,
+ T: Encode + Decode + Send + Sync + 'static,
+{
+ let (_, location) = cache_location(seed);
+ {
+ let mut g = CACHE_IN_MEMORY_OBJECTS.write().unwrap();
+ if let Some(entry) = g.get_mut(&location) {
+ entry.last_access = Instant::now();
+ let object = entry
+ .object
+ .clone()
+ .downcast::<T>()
+ .map_err(|_| anyhow!("inconsistent types for in-memory cache"))?;
+ return Ok(object);
+ }
+ }
+
+ let location = async_cache_file(seed, move |mut file| async move {
+ let object = generate().await?;
+ let data = bincode::encode_to_vec(&object, bincode::config::standard())
+ .context("encoding cache object")?;
+
+ file.write_all(&data).await?;
+
+ Ok(())
+ })
+ .await?;
+ let mut file = tokio::fs::File::open(location.path()).await?;
+ let mut data = Vec::new();
+ file.read_to_end(&mut data)
+ .await
+ .context("reading cache object")?;
+ let (object, _) = bincode::decode_from_slice::<T, _>(&data, bincode::config::standard())
+ .context("decoding cache object")?;
+ let object = Arc::new(object);
+ let size = file.stream_position().await? as usize; // this is an approximation mainly since varint is used in bincode
+
+ {
+ let mut g = CACHE_IN_MEMORY_OBJECTS.write().unwrap();
+ g.insert(
+ location,
+ InMemoryCacheEntry {
+ size,
+ last_access: Instant::now(),
+ object: object.clone(),
+ },
+ );
+ CACHE_IN_MEMORY_SIZE.fetch_add(size, Ordering::Relaxed);
+ }
+
+ cleanup_cache();
+
+ Ok(object)
+}
+
pub fn cleanup_cache() {
let current_size = CACHE_IN_MEMORY_SIZE.load(Ordering::Relaxed);
if current_size < CONF.max_in_memory_cache_size {