Skip to main content

xet_client/chunk_cache/
cache_manager.rs

1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::path::PathBuf;
4use std::sync::{Arc, LazyLock, Mutex, Weak};
5
6use super::error::ChunkCacheError;
7use super::{CacheConfig, ChunkCache, DiskCache};
8
9// single instance of CACHE_MANAGER not exposed to outside users that
10// dedupes cache instances based on configurations
11static CACHE_MANAGER: LazyLock<CacheManager> = LazyLock::new(CacheManager::new);
12
13/// get_cache attempts to return a cache given the provided config parameter
14pub fn get_cache(config: &CacheConfig) -> Result<Arc<dyn ChunkCache>, ChunkCacheError> {
15    CACHE_MANAGER.get(config)
16}
17
18struct CacheManager {
19    vals: Mutex<HashMap<PathBuf, RefCell<Weak<dyn ChunkCache>>>>,
20}
21
22impl CacheManager {
23    fn new() -> Self {
24        Self {
25            vals: Mutex::new(HashMap::new()),
26        }
27    }
28
29    /// get takes a CacheConfig and checks if there exists a valid `DiskCache` with a matching
30    /// cache_directory then it will return an Arc to that `DiskCache` instance. If it doesn't exist
31    /// or the `DiskCache` instance has been deallocated (CacheManager only holds a weak pointer)
32    /// then it creates a new instance based on the provided config.
33    fn get(&self, config: &CacheConfig) -> Result<Arc<dyn ChunkCache>, ChunkCacheError> {
34        let mut vals = self.vals.lock()?;
35        if let Some(v) = vals.get_mut(&config.cache_directory) {
36            let weak = v.borrow().clone();
37            // if upgrade from Weak to Arc is successful, returns the upgraded pointer
38            if let Some(value) = weak.upgrade() {
39                return Ok(value);
40            }
41            // since upgrading failed, creates a new DiskCache, replaces the weak pointer with a
42            // weak pointer to the new instance and then returns the Arc to the new cache instance
43            let result: Arc<dyn ChunkCache> = Arc::new(DiskCache::initialize(config)?);
44            v.replace(Arc::downgrade(&result));
45            Ok(result)
46        } else {
47            // create a new Cache and insert weak pointer to managed map
48            let result: Arc<dyn ChunkCache> = Arc::new(DiskCache::initialize(config)?);
49            vals.insert(config.cache_directory.clone(), RefCell::new(Arc::downgrade(&result)));
50            Ok(result)
51        }
52    }
53}