aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-01-30 15:47:05 +0100
committermetamuffin <metamuffin@disroot.org>2025-01-30 15:47:05 +0100
commite588d058ec3d13501edd0b4a3ac86604934c78c5 (patch)
treece839add00106615d8d4192b825e275a7b303f6f
parent02bbb2741f2c463aadf9d07493ebaeac1d73c11a (diff)
downloadjellything-e588d058ec3d13501edd0b4a3ac86604934c78c5.tar
jellything-e588d058ec3d13501edd0b4a3ac86604934c78c5.tar.bz2
jellything-e588d058ec3d13501edd0b4a3ac86604934c78c5.tar.zst
fix cache deadlock
-rw-r--r--base/src/cache.rs17
1 files changed, 15 insertions, 2 deletions
diff --git a/base/src/cache.rs b/base/src/cache.rs
index 7888042..e2b540b 100644
--- a/base/src/cache.rs
+++ b/base/src/cache.rs
@@ -18,7 +18,7 @@ use std::{
io::Seek,
path::PathBuf,
sync::{
- atomic::{AtomicUsize, Ordering},
+ atomic::{AtomicBool, AtomicUsize, Ordering},
Arc, LazyLock, RwLock,
},
time::Instant,
@@ -92,13 +92,23 @@ where
Ok(location)
}
+thread_local! { pub static WITHIN_CACHE_FILE: AtomicBool = AtomicBool::new(false); }
+
pub fn cache_file<Fun>(seed: &[&str], mut generate: Fun) -> Result<CachePath, anyhow::Error>
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 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 cache_file. proper solution needed
+ CACHE_GENERATION_LOCKS[bucket % CACHE_GENERATION_BUCKET_COUNT]
+ .try_lock()
+ .ok()
+ } else {
+ Some(CACHE_GENERATION_LOCKS[bucket % CACHE_GENERATION_BUCKET_COUNT].blocking_lock())
+ };
if !location.abs().exists() {
let temp_path = CONF.cache_path.join(format!("temp-{:x}", random::<u128>()));
let f = std::fs::File::create(&temp_path).context("creating new cache file")?;
@@ -112,6 +122,9 @@ where
}
rename(temp_path, location.abs()).context("rename cache")?;
}
+ if !already_within {
+ WITHIN_CACHE_FILE.with(|a| a.swap(false, Ordering::Relaxed));
+ }
drop(_guard);
Ok(location)
}