use std::{
collections::VecDeque,
time::{Duration, Instant},
};
use brk_types::{Transaction, Txid};
use rustc_hash::FxHashMap;
use super::{Entry, Tombstone};
use crate::steps::preparer::Removal;
const RETENTION: Duration = Duration::from_secs(60 * 60);
#[derive(Default)]
pub struct TxGraveyard {
tombstones: FxHashMap<Txid, Tombstone>,
order: VecDeque<(Instant, Txid)>,
}
impl TxGraveyard {
pub fn contains(&self, txid: &Txid) -> bool {
self.tombstones.contains_key(txid)
}
pub fn get(&self, txid: &Txid) -> Option<&Tombstone> {
self.tombstones.get(txid)
}
pub fn predecessors_of<'a>(
&'a self,
replacer: &'a Txid,
) -> impl Iterator<Item = (&'a Txid, &'a Tombstone)> {
self.tombstones
.iter()
.filter_map(move |(txid, ts)| (ts.replaced_by() == Some(replacer)).then_some((txid, ts)))
}
pub fn bury(&mut self, txid: Txid, tx: Transaction, entry: Entry, removal: Removal) {
let now = Instant::now();
self.tombstones
.insert(txid.clone(), Tombstone::new(tx, entry, removal, now));
self.order.push_back((now, txid));
}
pub fn exhume(&mut self, txid: &Txid) -> Option<Tombstone> {
self.tombstones.remove(txid)
}
pub fn evict_old(&mut self) {
while let Some(&(t, _)) = self.order.front() {
if t.elapsed() < RETENTION {
break;
}
let (_, txid) = self.order.pop_front().unwrap();
if let Some(ts) = self.tombstones.get(&txid)
&& ts.removed_at() == t
{
self.tombstones.remove(&txid);
}
}
}
pub fn len(&self) -> usize {
self.tombstones.len()
}
pub fn is_empty(&self) -> bool {
self.tombstones.is_empty()
}
}