diff options
author | metamuffin <metamuffin@disroot.org> | 2025-01-30 15:47:05 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-01-30 15:47:05 +0100 |
commit | e588d058ec3d13501edd0b4a3ac86604934c78c5 (patch) | |
tree | ce839add00106615d8d4192b825e275a7b303f6f | |
parent | 02bbb2741f2c463aadf9d07493ebaeac1d73c11a (diff) | |
download | jellything-e588d058ec3d13501edd0b4a3ac86604934c78c5.tar jellything-e588d058ec3d13501edd0b4a3ac86604934c78c5.tar.bz2 jellything-e588d058ec3d13501edd0b4a3ac86604934c78c5.tar.zst |
fix cache deadlock
-rw-r--r-- | base/src/cache.rs | 17 |
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) } |