From 556b84b88a65c3df53ad35ca75b2c1a8fa360040 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Sun, 1 Oct 2023 23:51:31 +0200 Subject: move caching to its own file --- base/src/cache.rs | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 base/src/cache.rs (limited to 'base/src/cache.rs') diff --git a/base/src/cache.rs b/base/src/cache.rs new file mode 100644 index 0000000..2fa2680 --- /dev/null +++ b/base/src/cache.rs @@ -0,0 +1,60 @@ +use crate::AssetLocationExt; +use base64::Engine; +use jellycommon::AssetLocation; +use std::{future::Future, sync::LazyLock}; +use tokio::sync::Mutex; + +pub fn cache_location(seed: &[&str]) -> (usize, AssetLocation) { + use sha2::Digest; + let mut d = sha2::Sha512::new(); + for s in seed { + d.update(s.as_bytes()); + d.update(b"\0"); + } + let d = d.finalize(); + let n = d[0] as usize | (d[1] as usize) << 8 | (d[2] as usize) << 16 | (d[3] as usize) << 24; + let fname = base64::engine::general_purpose::URL_SAFE.encode(d); + let fname = &fname[..22]; // about 128 bits + (n, AssetLocation::Cache(fname.into())) +} + +const CACHE_GENERATION_BUCKET_COUNT: usize = 1024; +pub static CACHE_GENERATION_LOCKS: LazyLock<[Mutex<()>; CACHE_GENERATION_BUCKET_COUNT]> = + LazyLock::new(|| [(); CACHE_GENERATION_BUCKET_COUNT].map(|_| Mutex::new(()))); + +pub async fn async_cache_file( + seed: &[&str], + generate: Fun, +) -> Result +where + Fun: FnOnce(tokio::fs::File) -> Fut, + Fut: Future>, +{ + let (bucket, location) = cache_location(seed); + // we need a lock even if it exists since somebody might be still in the process of writing. + let _guard = CACHE_GENERATION_LOCKS[bucket % CACHE_GENERATION_BUCKET_COUNT].lock(); + let exists = tokio::fs::try_exists(location.path()).await?; + if !exists { + let f = tokio::fs::File::create(location.path()).await?; + generate(f).await?; + } + drop(_guard); + Ok(location) +} + +pub fn cache_file(seed: &[&str], mut generate: Fun) -> Result +where + Fun: FnMut(std::fs::File) -> Result<(), anyhow::Error>, +{ + let (bucket, location) = cache_location(seed); + // we need a lock even if it exists since somebody might be still in the process of writing. + let _guard = CACHE_GENERATION_LOCKS[bucket % CACHE_GENERATION_BUCKET_COUNT].blocking_lock(); + let exists = location.path().exists(); + if !exists { + let f = std::fs::File::create(location.path())?; + generate(f)?; + } + drop(_guard); + Ok(location) +} + -- cgit v1.2.3-70-g09d2