aboutsummaryrefslogtreecommitdiff
path: root/cache/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cache/src/lib.rs')
-rw-r--r--cache/src/lib.rs47
1 files changed, 29 insertions, 18 deletions
diff --git a/cache/src/lib.rs b/cache/src/lib.rs
index fbda2cf..20e1424 100644
--- a/cache/src/lib.rs
+++ b/cache/src/lib.rs
@@ -3,17 +3,17 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2025 metamuffin <metamuffin.org>
*/
-pub mod backends;
-pub mod key;
+mod backends;
+mod helper;
use crate::backends::{CacheStorage, filesystem::Filesystem};
use anyhow::{Context, Result, anyhow};
-pub use key::*;
-use log::info;
+use log::{info, warn};
use serde::{Deserialize, Serialize};
use std::{
any::Any,
collections::{BTreeMap, HashMap},
+ hash::{DefaultHasher, Hash, Hasher},
path::PathBuf,
sync::{
Arc, LazyLock, Mutex, OnceLock, RwLock,
@@ -22,11 +22,12 @@ use std::{
time::Instant,
};
+pub use helper::{EscapeKey, HashKey};
+
#[derive(Debug, Deserialize)]
pub struct Config {
path: PathBuf,
max_in_memory_cache_size: usize,
- secret: String,
}
const CACHE_GENERATION_BUCKET_COUNT: usize = 1024;
@@ -54,23 +55,29 @@ pub fn init_cache() -> Result<()> {
Ok(())
}
-pub fn cache(key: CacheKey, generate: impl FnOnce() -> Result<Vec<u8>>) -> Result<Vec<u8>> {
+fn bucket(key: &str) -> usize {
+ let mut h = DefaultHasher::new();
+ key.hash(&mut h);
+ h.finish() as usize % CACHE_GENERATION_BUCKET_COUNT
+}
+
+pub fn cache(key: &str, generate: impl FnOnce() -> Result<Vec<u8>>) -> Result<Vec<u8>> {
// we need a lock even if it exists since somebody might be still in the process of writing.
let already_within = WITHIN_CACHE_FILE.with(|a| a.swap(true, Ordering::Relaxed));
let _guard = if already_within {
// TODO stupid hack to avoid deadlock for nested calls; not locking is fine but might cause double-generating
- CACHE_GENERATION_LOCKS[key.bucket()].try_lock().ok()
+ CACHE_GENERATION_LOCKS[bucket(key)].try_lock().ok()
} else {
- CACHE_GENERATION_LOCKS[key.bucket()].lock().ok()
+ CACHE_GENERATION_LOCKS[bucket(key)].lock().ok()
};
let store = CACHE_STORE.get().unwrap();
- let out = match store.read(key)? {
+ let out = match store.read(&key)? {
Some(x) => x,
None => {
let value = generate()?;
- store.store(key, &value)?;
+ store.store(key.to_owned(), &value)?;
value
}
};
@@ -82,11 +89,11 @@ pub fn cache(key: CacheKey, generate: impl FnOnce() -> Result<Vec<u8>>) -> Resul
Ok(out)
}
-pub fn cache_read(key: CacheKey) -> Result<Option<Vec<u8>>> {
+pub fn cache_read(key: &str) -> Result<Option<Vec<u8>>> {
CACHE_STORE.get().unwrap().read(key)
}
-pub fn cache_store(key: CacheKey, generate: impl FnOnce() -> Result<Vec<u8>>) -> Result<CacheKey> {
- cache(key, generate)?;
+pub fn cache_store(key: String, generate: impl FnOnce() -> Result<Vec<u8>>) -> Result<String> {
+ cache(&key, generate)?;
Ok(key)
}
@@ -95,18 +102,22 @@ pub struct InMemoryCacheEntry {
last_access: Instant,
object: Arc<dyn Any + Send + Sync + 'static>,
}
-pub static CACHE_IN_MEMORY_OBJECTS: LazyLock<RwLock<HashMap<CacheKey, InMemoryCacheEntry>>> =
+pub static CACHE_IN_MEMORY_OBJECTS: LazyLock<RwLock<HashMap<String, InMemoryCacheEntry>>> =
LazyLock::new(|| RwLock::new(HashMap::new()));
pub static CACHE_IN_MEMORY_SIZE: AtomicUsize = AtomicUsize::new(0);
-pub fn cache_memory<Fun, T>(key: CacheKey, mut generate: Fun) -> Result<Arc<T>, anyhow::Error>
+pub fn cache_memory<Fun, T>(key: &str, mut generate: Fun) -> Result<Arc<T>, anyhow::Error>
where
Fun: FnMut() -> Result<T, anyhow::Error>,
T: Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static,
{
+ if !key.ends_with(".json") {
+ warn!("cache_memory key not ending in .json: {key:?}")
+ }
+
{
let mut g = CACHE_IN_MEMORY_OBJECTS.write().unwrap();
- if let Some(entry) = g.get_mut(&key) {
+ if let Some(entry) = g.get_mut(key) {
entry.last_access = Instant::now();
let object = entry
.object
@@ -117,7 +128,7 @@ where
}
}
- let data = cache(key, move || {
+ let data = cache(&key, move || {
let object = generate()?;
Ok(serde_json::to_vec(&object)?)
})?;
@@ -128,7 +139,7 @@ where
{
let mut g = CACHE_IN_MEMORY_OBJECTS.write().unwrap();
g.insert(
- key,
+ key.to_owned(),
InMemoryCacheEntry {
size,
last_access: Instant::now(),