persy 1.5.2

Transactional Persistence Engine
Documentation
use crate::{
    id::{RecRef, SegmentId},
    journal::{records::FreedPage, JournalId},
    snapshot::data::{Change, CleanInfo, EntryCase, RecordVersion, SegmentSnapshot, SnapshotEntry},
    snapshots::{search, to_mapping, InternalSnapshots},
};
use std::cmp::Ordering;

#[test]
fn test_search() {
    assert_eq!(search(10, 20, 40), Ordering::Less);
    assert_eq!(search(20, 10, 40), Ordering::Greater);
    assert_eq!(search(10, 30, 20), Ordering::Greater);
    assert_eq!(search(30, 10, 20), Ordering::Less);
    assert_eq!(search(20, 20, 20), Ordering::Equal);
    assert_eq!(search(20, 19, 20), Ordering::Greater);
    assert_eq!(search(20, 21, 20), Ordering::Greater);
    assert_eq!(search(21, 21, 20), Ordering::Equal);
    assert_eq!(search(19, 19, 20), Ordering::Equal);
}

#[test]
fn add_and_read() {
    let mut snap = InternalSnapshots::default();
    let mut records = Vec::new();
    let mut freed_pages = Vec::new();
    for x in 0..3 {
        records.push(SnapshotEntry::change(&RecRef::new(10, x), x as u64, x as u16));
        freed_pages.push(FreedPage::new(x as u64));
    }
    let tx = snap.snapshot(
        records.clone(),
        CleanInfo::new(freed_pages.clone(), Vec::new()),
        JournalId::new(0, 0),
    );
    snap.clear_from(tx);
    let tx = snap.snapshot(records, CleanInfo::new(freed_pages, Vec::new()), JournalId::new(0, 0));
    assert_eq!(
        snap.read(tx - 1, &RecRef::new(10, 2)),
        Some(RecordVersion::new(1, EntryCase::Change(Change { pos: 2, version: 2 }),))
    );

    assert_eq!(
        snap.read(tx - 1, &RecRef::new(10, 1)),
        Some(RecordVersion::new(1, EntryCase::Change(Change { pos: 1, version: 1 }),))
    );

    assert_eq!(
        snap.read(tx, &RecRef::new(10, 2)),
        Some(RecordVersion::new(1, EntryCase::Change(Change { pos: 2, version: 2 }),))
    );
    assert_eq!(snap.read(tx + 1, &RecRef::new(10, 2)), None);
    assert_eq!(snap.read(tx + 1, &RecRef::new(10, 10)), None);
}

#[test]
fn add_and_read_multiple_tx() {
    let mut snap = InternalSnapshots::default();
    let mut txs = Vec::new();
    for t in 0..5 {
        let mut records = Vec::new();
        let mut freed_pages = Vec::new();
        for x in 0..10 {
            // I skip a record for the specific tx because i need a missing record for the test
            if x != t {
                records.push(SnapshotEntry::change(
                    &RecRef::new(10, x),
                    (10 * t + x) as u64,
                    (10 * t + x) as u16,
                ));
                freed_pages.push(FreedPage::new((10 * t + x) as u64));
            }
        }
        txs.push(snap.snapshot(records, CleanInfo::new(freed_pages, Vec::new()), JournalId::new(0, 0)));
    }
    assert_eq!(
        snap.read(txs[2], &RecRef::new(10, 2)),
        Some(RecordVersion::new(
            txs[3],
            EntryCase::Change(Change { pos: 32, version: 32 })
        ),)
    );

    assert_eq!(
        snap.read(txs[3], &RecRef::new(10, 3)),
        Some(RecordVersion::new(
            txs[4],
            EntryCase::Change(Change { pos: 43, version: 43 }),
        ))
    );
}

#[test]
fn test_snapshot_reference_count() {
    let mut snap = InternalSnapshots::default();
    let mut records = Vec::new();
    let mut freed_pages = Vec::new();
    for x in 0..3 {
        records.push(SnapshotEntry::change(&RecRef::new(10, x), x as u64, x as u16));
        freed_pages.push(FreedPage::new(x as u64));
    }
    let first = snap.read_snapshot();
    let tx = snap.snapshot(
        records.clone(),
        CleanInfo::new(freed_pages, Vec::new()),
        JournalId::new(0, 0),
    );

    let last = snap.read_snapshot();
    snap.release(tx);
    assert_eq!(
        snap.read(first, &RecRef::new(10, 2)),
        Some(RecordVersion::new(1, EntryCase::Change(Change { pos: 2, version: 2 }),))
    );

    snap.release(first);
    assert_eq!(snap.read(last, &RecRef::new(10, 2)), None);
}

#[test]
fn test_clanup_after_release() {
    let mut snap = InternalSnapshots::default();
    let mut snapshots_id = Vec::new();
    for s in 0..100 {
        let mut records = Vec::new();
        let mut freed_pages = Vec::new();
        for x in 0..3 {
            records.push(SnapshotEntry::change(&RecRef::new(s % 10, x), x as u64, x as u16));
            freed_pages.push(FreedPage::new(x as u64));
        }
        let tx = snap.snapshot(
            records.clone(),
            CleanInfo::new(freed_pages, Vec::new()),
            JournalId::new(0, 0),
        );
        snapshots_id.push(tx);
    }
    for s in snapshots_id.into_iter().rev() {
        snap.release(s);
    }
    {
        assert_eq!(snap.active_snapshots(), 0);
        assert_eq!(snap.mapping_count(), 0);
    }
    // Same code twice this time release the snapshot in direct order
    let mut snapshots_id = Vec::new();
    for s in 0..100 {
        let mut records = Vec::new();
        let mut freed_pages = Vec::new();
        for x in 0..3 {
            records.push(SnapshotEntry::change(&RecRef::new(s % 10, x), x as u64, x as u16));
            freed_pages.push(FreedPage::new(x as u64));
        }
        let tx = snap.snapshot(
            records.clone(),
            CleanInfo::new(freed_pages, Vec::new()),
            JournalId::new(0, 0),
        );
        snapshots_id.push(tx);
    }
    for s in snapshots_id {
        snap.release(s);
    }

    assert_eq!(snap.active_snapshots(), 0);
    assert_eq!(snap.mapping_count(), 0);
}

#[test]
fn test_snapshot_release_clear() {
    let mut snap = InternalSnapshots::default();
    let mut snaps = Vec::new();
    for i in 0..10 {
        let id = snap.read_snapshot();
        let mut segments = Vec::new();
        let seg_id = SegmentId::new(i);
        segments.push(SegmentSnapshot::new("one", seg_id, i.into()));
        segments.push(SegmentSnapshot::new("two", seg_id, i.into()));
        let (segments_id, segments_name) = to_mapping(&segments);
        snap.fill_segments(id, segments_id, segments_name);
        snaps.push(id);
    }
    snap.release(snaps[0]);
    snap.release(snaps[1]);
    snap.release(snaps[2]);
    let solved = snap.solve_segment_id(snaps[3], "one");
    assert_eq!(solved, Some(SegmentId::new(3)));
    assert_eq!(snap.active_snapshots(), 7);
}

#[test]
pub fn test_segment_snapshot_fill() {
    let mut snap = InternalSnapshots::default();
    let id = snap.read_snapshot();
    let mut segments = Vec::new();
    let seg_id = SegmentId::new(10);
    segments.push(SegmentSnapshot::new("one", seg_id, 10));
    let (segments_id, segments_name) = to_mapping(&segments);
    snap.fill_segments(id, segments_id, segments_name);
    let solved = snap.solve_segment_id(id, "one");
    assert_eq!(solved, Some(seg_id));
    let solved = snap.solve_segment_name(id, seg_id);
    assert_eq!(solved, Some("one".to_string()));
    let solved = snap.solve_segment_id(id, "two");
    assert_eq!(solved, None);
    let solved = snap.scan(id, seg_id);
    assert!(solved.is_some());
    snap.release(id);
}

#[test]
pub fn test_segment_snapshot_fill_multiple() {
    let mut snap = InternalSnapshots::default();
    let mut snaps = Vec::new();
    for i in 0..10 {
        let id = snap.read_snapshot();
        let mut segments = Vec::new();
        let seg_id = SegmentId::new(i);
        segments.push(SegmentSnapshot::new("one", seg_id, i.into()));
        segments.push(SegmentSnapshot::new("two", seg_id, i.into()));

        let (segments_id, segments_name) = to_mapping(&segments);
        snap.fill_segments(id, segments_id, segments_name);
        snaps.push(id);
    }
    let solved = snap.solve_segment_id(snaps[3], "one");
    assert_eq!(solved, Some(SegmentId::new(3)));
    let solved = snap.solve_segment_id(snaps[3], "two");
    assert_eq!(solved, Some(SegmentId::new(3)));
    let solved = snap.solve_segment_id(snaps[6], "one");
    assert_eq!(solved, Some(SegmentId::new(6)));
    let solved = snap.solve_segment_id(snaps[6], "two");
    assert_eq!(solved, Some(SegmentId::new(6)));
}