use crate::epoch::Epoch;
use parking_lot::Mutex;
use std::collections::BTreeMap;
use std::collections::HashSet;
use std::sync::Arc;
#[derive(Default)]
pub struct ActiveSpills {
inner: Mutex<HashSet<u64>>,
}
impl ActiveSpills {
pub fn new() -> Self {
Self {
inner: Mutex::new(HashSet::new()),
}
}
pub fn register(self: &Arc<Self>, txn_id: u64) -> SpillGuard {
self.inner.lock().insert(txn_id);
SpillGuard {
registry: Arc::clone(self),
txn_id,
}
}
pub fn is_active(&self, txn_id: u64) -> bool {
self.inner.lock().contains(&txn_id)
}
pub fn is_idle(&self) -> bool {
self.inner.lock().is_empty()
}
fn release(&self, txn_id: u64) {
self.inner.lock().remove(&txn_id);
}
}
pub struct SpillGuard {
registry: Arc<ActiveSpills>,
txn_id: u64,
}
impl Drop for SpillGuard {
fn drop(&mut self) {
self.registry.release(self.txn_id);
}
}
#[derive(Default)]
pub struct SnapshotRegistry {
live: Mutex<BTreeMap<u64, u64>>,
}
impl SnapshotRegistry {
pub fn new() -> Self {
Self {
live: Mutex::new(BTreeMap::new()),
}
}
pub fn register(&self, epoch: Epoch) -> SnapshotGuard<'_> {
let mut live = self.live.lock();
*live.entry(epoch.0).or_insert(0) += 1;
SnapshotGuard {
registry: self,
epoch,
}
}
pub fn min_active(&self, visible: Epoch) -> Epoch {
match self.live.lock().keys().next().copied() {
Some(min) => Epoch(min),
None => visible,
}
}
pub fn min_pinned(&self) -> Option<Epoch> {
self.live.lock().keys().next().copied().map(Epoch)
}
fn release(&self, epoch: Epoch) {
let mut live = self.live.lock();
if let Some(count) = live.get_mut(&epoch.0) {
*count -= 1;
if *count == 0 {
live.remove(&epoch.0);
}
}
}
}
pub struct SnapshotGuard<'r> {
registry: &'r SnapshotRegistry,
epoch: Epoch,
}
impl Drop for SnapshotGuard<'_> {
fn drop(&mut self) {
self.registry.release(self.epoch);
}
}
pub struct OwnedSnapshotGuard {
registry: Arc<SnapshotRegistry>,
epoch: Epoch,
}
impl OwnedSnapshotGuard {
pub fn epoch(&self) -> Epoch {
self.epoch
}
}
impl Drop for OwnedSnapshotGuard {
fn drop(&mut self) {
self.registry.release(self.epoch);
}
}
impl SnapshotRegistry {
pub fn register_owned(self: &Arc<Self>, epoch: Epoch) -> OwnedSnapshotGuard {
{
let mut live = self.live.lock();
*live.entry(epoch.0).or_insert(0) += 1;
}
OwnedSnapshotGuard {
registry: Arc::clone(self),
epoch,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn retention_tracks_min_active_snapshot() {
let r = SnapshotRegistry::new();
assert_eq!(r.min_active(Epoch(10)), Epoch(10));
let g1 = r.register(Epoch(5));
let g2 = r.register(Epoch(8));
assert_eq!(r.min_active(Epoch(10)), Epoch(5));
drop(g1);
assert_eq!(r.min_active(Epoch(10)), Epoch(8));
drop(g2);
assert_eq!(r.min_active(Epoch(10)), Epoch(10));
}
#[test]
fn retention_refcounts_duplicate_epochs() {
let r = SnapshotRegistry::new();
let a = r.register(Epoch(3));
let b = r.register(Epoch(3));
assert_eq!(r.min_active(Epoch(9)), Epoch(3));
drop(a);
assert_eq!(r.min_active(Epoch(9)), Epoch(3));
drop(b);
assert_eq!(r.min_active(Epoch(9)), Epoch(9));
}
}