use std::collections::HashMap;
use crate::error::Result;
use crate::io::BlockDevice;
const DEFAULT_CAPACITY: usize = 256;
struct CacheEntry {
data: Vec<u8>,
generation: u64,
}
pub struct BlockCache {
entries: HashMap<u64, CacheEntry>,
generation: u64,
capacity: usize,
}
impl Default for BlockCache {
fn default() -> Self {
Self::new()
}
}
impl BlockCache {
pub fn new() -> Self {
Self {
entries: HashMap::new(),
generation: 0,
capacity: DEFAULT_CAPACITY,
}
}
pub fn invalidate(&mut self, block: u64) {
self.entries.remove(&block);
}
pub fn read_reserved(
&mut self,
dev: &dyn BlockDevice,
block: u64,
reserved_blksize: u16,
) -> Result<&[u8]> {
self.generation += 1;
let g = self.generation;
if let Some(entry) = self.entries.get_mut(&block) {
entry.generation = g;
return Ok(&self.entries.get(&block).unwrap().data);
}
let sectors = ((reserved_blksize as u32) / dev.block_size()).max(1);
let mut buf = vec![0u8; reserved_blksize as usize];
dev.read_blocks(block, sectors, &mut buf)?;
if self.entries.len() >= self.capacity {
let oldest = self
.entries
.iter()
.min_by_key(|(_, e)| e.generation)
.map(|(&k, _)| k);
if let Some(k) = oldest {
self.entries.remove(&k);
}
}
self.entries.insert(
block,
CacheEntry {
data: buf,
generation: g,
},
);
Ok(&self.entries.get(&block).unwrap().data)
}
}