use std::sync::Arc;
use parking_lot::Mutex;
use uqa_core::memory::{BudgetedVec, MemoryBudget};
#[derive(Default)]
pub(super) struct ValueCache {
chunk: Option<(u64, Arc<BudgetedVec<u8>>)>,
}
impl ValueCache {
pub(super) fn get(&mut self, start: u64) -> Option<Arc<BudgetedVec<u8>>> {
if self
.chunk
.as_ref()
.is_some_and(|(previous, _)| *previous != start)
{
self.clear();
}
self.chunk.as_ref().map(|(_, bytes)| Arc::clone(bytes))
}
pub(super) fn keep(&mut self, start: u64, bytes: &Arc<BudgetedVec<u8>>) {
self.chunk = Some((start, Arc::clone(bytes)));
}
pub(super) fn clear(&mut self) {
self.chunk = None;
}
}
#[derive(Default)]
struct Cached {
readers: usize,
block: Option<(usize, Arc<BudgetedVec<u8>>)>,
chunk: ValueCache,
}
pub(super) struct RunCache {
memory: MemoryBudget,
cached: Mutex<Cached>,
}
impl RunCache {
pub(super) fn new(memory: &MemoryBudget) -> Self {
Self {
memory: memory.clone(),
cached: Mutex::new(Cached::default()),
}
}
pub(super) fn reader(self: &Arc<Self>) -> RunCacheReader {
self.cached.lock().readers += 1;
RunCacheReader(Arc::clone(self))
}
pub(super) fn memory(&self) -> &MemoryBudget {
&self.memory
}
pub(super) fn block(&self, index: usize) -> Option<Arc<BudgetedVec<u8>>> {
self.cached
.lock()
.block
.as_ref()
.filter(|(cached, _)| *cached == index)
.map(|(_, bytes)| Arc::clone(bytes))
}
pub(super) fn discard_other_block(&self, index: usize) {
let mut cached = self.cached.lock();
if cached
.block
.as_ref()
.is_some_and(|(previous, _)| *previous != index)
{
cached.block = None;
}
}
pub(super) fn keep_block(&self, index: usize, bytes: &Arc<BudgetedVec<u8>>) {
let mut cached = self.cached.lock();
if cached.readers != 0 {
cached.block = Some((index, Arc::clone(bytes)));
}
}
pub(super) fn chunk(&self, start: u64) -> Option<Arc<BudgetedVec<u8>>> {
self.cached.lock().chunk.get(start)
}
pub(super) fn keep_chunk(&self, start: u64, bytes: &Arc<BudgetedVec<u8>>) {
let mut cached = self.cached.lock();
if cached.readers != 0 {
cached.chunk.keep(start, bytes);
}
}
}
pub(in crate::mvcc) struct RunCacheReader(Arc<RunCache>);
impl Drop for RunCacheReader {
fn drop(&mut self) {
let mut cached = self.0.cached.lock();
cached.readers -= 1;
if cached.readers == 0 {
cached.block = None;
cached.chunk.clear();
}
}
}