How to avoid cloning the cached type in guarded HashMap

Please consider the following example:

pub struct Cache<T: CacheConfig> {
    cache: RwLock<HashMap<String, T>>,
}

impl<T: CacheConfig> CacheMap<T> {
    pub fn get<F>(&self, key: String) -> Result<T, CacheError> {
        if let Ok(cache) = self.cache.read() {
            if let Some(elem) = cache.get(key.as_str()) {
                return Ok(elem.clone()); // CLONE_1
            }
        }
        let conf = T::new();
        self.cache.write().insert(key, conf.clone()); // CLONE_2
        Ok(conf)
    }
}

Is there a solution to avoid clone()s?

If you insist on returning elements by value, then there's no way of getting rid of the second clone. Similarly, because of the need to only access values while the lock is held for reading, there's no way to get rid of the first clone.

I can imagine two changes to the design in order to help with these problems:

  1. Instead of embedding the lock into the cache, just put in the HashMap directly, and guard it with a lock elsewhere, only if needed. Then you can lock the cache when necessary, then use it normally. In addition, make get return a reference.

  2. You could transform the API into a CPS / callback-based format, and instead of returning the value directly, you would pass a closure to get which would, again, get a reference to the value.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.