use std::io::{Read, Seek, SeekFrom};
use anyhow::{bail, Result};
use crate::{Db, CACHE_SIZE, PAGE_SIZE};
impl Db {
pub(super) fn invalidate_cache(&mut self, page_number: u64) {
if let Some((time, _)) = self.cached_pages.remove(&page_number) {
self.time_to_page.remove(&time).unwrap();
}
}
fn cache_page(&mut self, page_number: u64, page: &[u8]) {
let this_time = self.next_time;
self.next_time += 1;
if self.cached_pages.len() >= CACHE_SIZE {
let (&least_used_time, &least_used_page_number) =
self.time_to_page.first_key_value().unwrap();
self.time_to_page.remove(&least_used_time).unwrap();
self.cached_pages.remove(&least_used_page_number).unwrap();
}
self.cached_pages
.insert(page_number, (this_time, page.to_vec()));
self.time_to_page.insert(this_time, page_number);
}
fn get_cached_page(&mut self, page_number: u64) -> Option<Vec<u8>> {
let this_time = self.next_time;
self.next_time += 1;
let (previous_time, page) = self.cached_pages.remove(&page_number)?;
self.cached_pages
.insert(page_number, (this_time, page.clone()));
self.time_to_page.remove(&previous_time).unwrap();
self.time_to_page.insert(this_time, page_number);
Some(page)
}
pub(super) fn get_page(&mut self, page_number: u64) -> Result<Vec<u8>> {
if let Some(page) = self.get_cached_page(page_number) {
return Ok(page);
} else if let Some(page) = self.write_pages.get(&page_number).cloned() {
self.cache_page(page_number, &page);
Ok(page)
} else if let Some(file) = self.file.as_mut() {
let mut v = vec![0u8; PAGE_SIZE];
file.seek(SeekFrom::Start(page_number * PAGE_SIZE as u64))?;
file.read_exact(&mut v)?;
self.cache_page(page_number, &v);
Ok(v)
} else {
bail!("in memory database somehow lost a page")
}
}
}