Search code examples
cachingrustmutable

Cannot borrow data in dereference of `std::sync::RwLockReadGuard<'_, LruCache<i32, bytes::Bytes>>` as mutable


I am quite new to Rust. I'm trying to build a global cache using lru::LruCache and a RwLock for safety. It needs to be globally accessible based on my program's architecture.

//Size to take up 5MB
const CACHE_ENTRIES: usize = (GIBYTE as usize/ 200) / (BLOCK_SIZE);

pub type CacheEntry = LruCache<i32, Bytes>;
static mut CACHE : CacheEntry = LruCache::new(CACHE_ENTRIES);
lazy_static!{
    static ref BLOCKCACHE: RwLock<CacheEntry> = RwLock::new(CACHE);
}


//this gets called from another setup function
async fn download_block(&self,
        context: &BlockContext,
        buf: &mut [u8],
        count: u32, //bytes to read
        offset: u64,
        buf_index: u32
    ) -> Result<u32> {

    let block_index = context.block_index;

    let block_data : Bytes = match {BLOCKCACHE.read().unwrap().get(&block_index)} {
        Some(data) => data.to_owned(),
        None => download_block_from_remote(context).await.unwrap().to_owned(),
    };

//the rest of the function does stuff with the block_data
}

async fn download_block_from_remote(context: &BlockContext) -> Result<Bytes>{
    //code to download block data from remote into block_data

    {BLOCKCACHE.write().unwrap().put(block_index, block_data.clone())};
    Ok(block_data)
}

Right now I am getting an error on this line:

let block_data = match {BLOCKCACHE.read().unwrap().get(&block_index)} {

"cannot borrow as mutable" for the value inside the braces.

"help: trait DerefMut is required to modify through a dereference, but it is not implemented for std::sync::RwLockReadGuard<'_, LruCache<i32, bytes::Bytes>>"

I have gotten some other errors involving ownership and mutability, but I can't seem to get rid of this. Is anyone able to offer guidance on how to get this to work, or set me on the right path if it's just not possible/feasible?


Solution

  • The problem here is that LruCache::get() requires mutable access to the cache object. (Reason: it's a cache object, which has to change its internal state when querying things for the actual caching)

    Therefore, if you use an RwLock, you need to use the write() method instead of the read() method.

    That said, the fact that get() requires mutable access makes the entire RwLock pretty pointless, and I'd use a normal Mutex instead. There is very rarely the necessity to use an RwLock as it has more overhead compared to a simple Mutex.