blob: 486b2b954396d5dc1032fa6f5a763f64aba3f245 [file] [log] [blame]
use crate::types::{share, SequenceNumber, Shared, MAX_SEQUENCE_NUMBER};
use std::collections::HashMap;
use std::rc::Rc;
/// Opaque snapshot handle; Represents index to SnapshotList.map
type SnapshotHandle = u64;
/// An InnerSnapshot is shared by several Snapshots. This enables cloning snapshots, and a snapshot
/// is released once the last instance is dropped.
#[derive(Clone)]
struct InnerSnapshot {
id: SnapshotHandle,
seq: SequenceNumber,
sl: Shared<InnerSnapshotList>,
}
impl Drop for InnerSnapshot {
fn drop(&mut self) {
self.sl.borrow_mut().delete(self.id);
}
}
#[derive(Clone)]
pub struct Snapshot {
inner: Rc<InnerSnapshot>,
}
impl Snapshot {
pub fn sequence(&self) -> SequenceNumber {
(*self.inner).seq
}
}
/// A list of all snapshots is kept in the DB.
struct InnerSnapshotList {
map: HashMap<SnapshotHandle, SequenceNumber>,
newest: SnapshotHandle,
oldest: SnapshotHandle,
}
pub struct SnapshotList {
inner: Shared<InnerSnapshotList>,
}
impl SnapshotList {
pub fn new() -> SnapshotList {
SnapshotList {
inner: share(InnerSnapshotList {
map: HashMap::new(),
newest: 0,
oldest: 0,
}),
}
}
pub fn new_snapshot(&mut self, seq: SequenceNumber) -> Snapshot {
let inner = self.inner.clone();
let mut sl = self.inner.borrow_mut();
sl.newest += 1;
let newest = sl.newest;
sl.map.insert(newest, seq);
if sl.oldest == 0 {
sl.oldest = sl.newest;
}
Snapshot {
inner: Rc::new(InnerSnapshot {
id: sl.newest,
seq,
sl: inner,
}),
}
}
/// oldest returns the lowest sequence number of all snapshots. It returns 0 if no snapshots
/// are present.
pub fn oldest(&self) -> SequenceNumber {
let oldest = self
.inner
.borrow()
.map
.iter()
.fold(
MAX_SEQUENCE_NUMBER,
|s, (seq, _)| if *seq < s { *seq } else { s },
);
if oldest == MAX_SEQUENCE_NUMBER {
0
} else {
oldest
}
}
/// newest returns the newest sequence number of all snapshots. If no snapshots are present, it
/// returns 0.
pub fn newest(&self) -> SequenceNumber {
self.inner
.borrow()
.map
.iter()
.fold(0, |s, (seq, _)| if *seq > s { *seq } else { s })
}
pub fn empty(&self) -> bool {
self.inner.borrow().oldest == 0
}
}
impl InnerSnapshotList {
fn delete(&mut self, id: SnapshotHandle) {
self.map.remove(&id);
}
}
#[cfg(feature = "enclave_unit_test")]
pub mod tests {
use super::*;
use std::prelude::v1::*;
use teaclave_test_utils::*;
pub fn run_tests() -> bool {
run_tests!(test_snapshot_list,)
}
#[allow(unused_variables)]
fn test_snapshot_list() {
let mut l = SnapshotList::new();
{
assert!(l.empty());
let a = l.new_snapshot(1);
{
let b = l.new_snapshot(2);
{
let c = l.new_snapshot(3);
assert!(!l.empty());
assert_eq!(l.oldest(), 1);
assert_eq!(l.newest(), 3);
}
assert_eq!(l.newest(), 2);
assert_eq!(l.oldest(), 1);
}
assert_eq!(l.oldest(), 1);
}
assert_eq!(l.oldest(), 0);
}
}