use crate::device::{PageOps, ReadPage};
use linked_hash_map::LinkedHashMap;
use std::time::{Duration, Instant};
struct CacheEntry {
page: ReadPage,
instant: Instant,
}
impl CacheEntry {
fn new(page: ReadPage) -> Self {
Self {
page,
instant: Instant::now(),
}
}
}
pub struct Cache {
cache: LinkedHashMap<u64, CacheEntry>,
size: u64,
limit: u64,
age_limit: Duration,
}
impl Cache {
pub fn new(limit: u64, age_limit: Duration) -> Cache {
Cache {
cache: LinkedHashMap::new(),
size: 0,
limit,
age_limit,
}
}
pub fn get(&mut self, key: u64) -> Option<ReadPage> {
self.cache.get_refresh(&key).map(|val| val.page.clone_read())
}
pub fn put(&mut self, key: u64, value: ReadPage) {
self.size += 1 << value.get_size_exp();
if let Some(pre) = self.cache.insert(key, CacheEntry::new(value)) {
self.size -= 1 << pre.page.get_size_exp();
}
while self.size > self.limit {
if let Some(en) = self.cache.pop_front() {
self.size -= 1 << en.1.page.get_size_exp();
} else {
break;
}
}
loop {
if self
.cache
.front()
.map(|(_, e)| e.instant.elapsed() > self.age_limit)
.unwrap_or(false)
{
if let Some(en) = self.cache.pop_front() {
self.size -= 1 << en.1.page.get_size_exp();
}
} else {
break;
}
}
}
pub fn remove(&mut self, key: u64) {
if let Some(removed) = self.cache.remove(&key) {
self.size -= 1 << removed.page.get_size_exp();
}
}
pub fn remove_all(&mut self, keys: &[u64]) {
for key in keys {
if let Some(removed) = self.cache.remove(key) {
self.size -= 1 << removed.page.get_size_exp();
}
}
}
#[allow(unused)]
pub fn size(&self) -> u64 {
self.size
}
#[allow(unused)]
pub fn entry_count(&self) -> usize {
self.cache.len()
}
}