view src/snapshot.rs @ 327:63389f1585f0

types: Move Direction enum into types.
author Lewin Bormann <lbo@spheniscida.de>
date Sun, 01 Oct 2017 20:37:42 +0200
parents c8288b1ca724
children 036e3084f8f0
line wrap: on
line source

use std::collections::HashMap;
use types::{share, MAX_SEQUENCE_NUMBER, SequenceNumber, Shared};

/// Opaque snapshot handle; Represents index to SnapshotList.map
type SnapshotHandle = u64;

pub struct Snapshot {
    id: SnapshotHandle,
    sl: Shared<InnerSnapshotList>,
}

impl Drop for Snapshot {
    fn drop(&mut self) {
        self.sl.borrow_mut().delete(self.id);
    }
}

/// 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 {
            id: sl.newest,
            sl: inner,
        }
    }

    pub fn sequence_at(&self, ss: &Snapshot) -> Option<SequenceNumber> {
        let sl = self.inner.borrow_mut();
        sl.map.get(&ss.id).map(|sn| *sn)
    }

    /// 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(test)]
mod tests {
    use super::*;

    #[allow(unused_variables)]
    #[test]
    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);
    }
}