persy 0.7.0

Transactional Persistence Engine
Documentation
mod helpers;
use helpers::{create_and_drop, create_and_drop_with_config};
use persy::Config;
use persy::PersyError;
use persy::TxStrategy;

#[test]
fn test_insert_read_commit_record() {
    create_and_drop("irc", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("something").into_bytes();
        let id = persy.insert_record(&mut tx, "test", &bytes).unwrap();
        let read_opt = persy.read_record_tx(&mut tx, "test", &id).unwrap();
        assert_eq!(read_opt, Some(bytes));
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let bytes = String::from("something").into_bytes();
        let read_after = persy.read_record("test", &id).unwrap();
        assert_eq!(read_after, Some(bytes));
    });
}

#[test]
fn test_insert_update_record() {
    create_and_drop("iru", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let rec_data: String = "something".into();
        let bytes = rec_data.into_bytes();
        let id = persy.insert_record(&mut tx, "test", &bytes).unwrap();
        let read_opt = persy.read_record_tx(&mut tx, "test", &id).unwrap();
        assert_eq!(read_opt, Some(bytes));
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let rec_1: String = "newthing".into();
        let bytes_1 = rec_1.into_bytes();
        let mut tx1 = persy.begin().unwrap();
        persy.update_record(&mut tx1, "test", &id, &bytes_1).unwrap();
        let read_after = persy.read_record_tx(&mut tx1, "test", &id).unwrap();
        assert_eq!(read_after, Some(bytes_1));
        let finalizer = persy.prepare_commit(tx1).unwrap();
        persy.commit(finalizer).unwrap();
    });
}

#[test]
fn test_insert_delete_record() {
    create_and_drop("ird", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let rec_data: String = "something".into();
        let bytes = rec_data.into_bytes();
        let id = persy.insert_record(&mut tx, "test", &bytes).unwrap();
        let read_opt = persy.read_record_tx(&mut tx, "test", &id).unwrap();
        assert_eq!(read_opt, Some(bytes));
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let mut tx1 = persy.begin().unwrap();
        persy.delete_record(&mut tx1, "test", &id).unwrap();
        let read_after = persy.read_record_tx(&mut tx1, "test", &id).unwrap();
        assert_eq!(read_after, None);
        let finalizer = persy.prepare_commit(tx1).unwrap();
        persy.commit(finalizer).unwrap();
    });
}

#[test]
#[allow(deprecated)]
fn test_insert_scan_records_old() {
    create_and_drop("irs", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let rec_data: String = "something".into();
        let bytes = rec_data.into_bytes();
        persy.insert_record(&mut tx, "test", &bytes).unwrap();
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();
        let iter = persy.scan_records("test").unwrap().into_iter();
        assert_eq!(iter.count(), 1);
        let rec = persy.scan_records("test").unwrap().into_iter().next().unwrap();
        assert_eq!(bytes, rec.content);
    });
}

#[test]
fn test_insert_scan() {
    create_and_drop("irs", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let rec_data: String = "something".into();
        let bytes = rec_data.into_bytes();
        persy.insert_record(&mut tx, "test", &bytes).unwrap();
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();
        let iter = persy.scan("test").unwrap().into_iter();
        assert_eq!(iter.count(), 1);
        let (_, content) = persy.scan("test").unwrap().into_iter().next().unwrap();
        assert_eq!(bytes, content);
    });
}

#[test]
fn test_insert_update_same_tx() {
    create_and_drop("ius", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("something").into_bytes();
        let id = persy.insert_record(&mut tx, "test", &bytes).unwrap();
        let read_opt = persy.read_record_tx(&mut tx, "test", &id).unwrap();
        assert_eq!(read_opt, Some(bytes));
        let bytes = String::from("data1").into_bytes();
        persy.update_record(&mut tx, "test", &id, &bytes).unwrap();
        let read_opt = persy.read_record_tx(&mut tx, "test", &id).unwrap();
        assert_eq!(read_opt, Some(bytes));
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let read_after = persy.read_record("test", &id).unwrap();
        let bytes = String::from("data1").into_bytes();
        assert_eq!(read_after, Some(bytes));
    });
}

#[test]
fn test_double_update_same_tx() {
    create_and_drop("iuus", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("something").into_bytes();
        let id = persy.insert_record(&mut tx, "test", &bytes).unwrap();
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();
        let mut tx = persy.begin().unwrap();
        let bytes = String::from("first").into_bytes();
        persy.update_record(&mut tx, "test", &id, &bytes).unwrap();
        let bytes = String::from("second").into_bytes();
        persy.update_record(&mut tx, "test", &id, &bytes).unwrap();
        let read_opt = persy.read_record_tx(&mut tx, "test", &id).unwrap();
        assert_eq!(read_opt, Some(bytes));
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let read_after = persy.read_record("test", &id).unwrap();
        let bytes = String::from("second").into_bytes();
        assert_eq!(read_after, Some(bytes));
    });
}

#[test]
fn test_insert_update_delete_same_tx() {
    create_and_drop("iuds", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("something").into_bytes();
        let id = persy.insert_record(&mut tx, "test", &bytes).unwrap();
        let bytes = String::from("first").into_bytes();
        persy.update_record(&mut tx, "test", &id, &bytes).unwrap();
        persy.delete_record(&mut tx, "test", &id).unwrap();
        let read_opt = persy.read_record_tx(&mut tx, "test", &id).unwrap();
        assert_eq!(read_opt, None);
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let read_after = persy.read_record("test", &id).unwrap();
        assert_eq!(read_after, None);
    });
}

#[test]
fn test_update_delete_same_tx() {
    create_and_drop("uds", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("something").into_bytes();
        let id = persy.insert_record(&mut tx, "test", &bytes).unwrap();
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let mut tx = persy.begin().unwrap();
        let bytes = String::from("first").into_bytes();
        persy.update_record(&mut tx, "test", &id, &bytes).unwrap();
        persy.delete_record(&mut tx, "test", &id).unwrap();
        let read_opt = persy.read_record_tx(&mut tx, "test", &id).unwrap();
        assert_eq!(read_opt, None);
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let read_after = persy.read_record("test", &id).unwrap();
        assert_eq!(read_after, None);
    });
}

#[test]
fn test_insert_100_same_tx() {
    create_and_drop("i100", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("something").into_bytes();
        for _ in [0; 100].iter() {
            persy.insert_record(&mut tx, "test", &bytes).unwrap();
        }
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let mut count = 0;
        for _ in persy.scan("test").unwrap() {
            count += 1;
        }
        assert_eq!(count, 100);
    });
}

#[test]
fn test_update_100_same_tx() {
    create_and_drop("i100", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("something").into_bytes();
        let mut ids = Vec::new();
        for _ in [0; 100].iter() {
            ids.push(persy.insert_record(&mut tx, "test", &bytes).unwrap());
        }
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let mut tx = persy.begin().unwrap();
        for id in ids {
            persy.update_record(&mut tx, "test", &id, &bytes).unwrap();
        }

        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let mut count = 0;
        for _ in persy.scan("test").unwrap() {
            count += 1;
        }
        assert_eq!(count, 100);
    });
}

#[test]
#[allow(deprecated)]
fn test_create_insert_scan_same_tx_old() {
    create_and_drop("cistx", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("something").into_bytes();
        for _ in [0; 50].iter() {
            persy.insert_record(&mut tx, "test", &bytes).unwrap();
        }
        let mut count = 0;
        for rec in persy.scan_records_tx(&mut tx, "test").unwrap() {
            assert_eq!(rec.content, bytes);
            count += 1;
        }
        assert_eq!(count, 50);
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();
    });
}

#[test]
#[allow(deprecated)]
fn test_insert_100_and_scan_same_tx_old() {
    create_and_drop("i100tx", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("something").into_bytes();
        for _ in [0; 50].iter() {
            persy.insert_record(&mut tx, "test", &bytes).unwrap();
        }
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let mut tx = persy.begin().unwrap();
        for _ in [0; 50].iter() {
            persy.insert_record(&mut tx, "test", &bytes).unwrap();
        }
        let mut count = 0;
        for rec in persy.scan_records_tx(&mut tx, "test").unwrap() {
            assert_eq!(rec.content, bytes);
            count += 1;
        }
        assert_eq!(count, 100);
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();
    });
}

#[test]
#[allow(deprecated)]
fn test_insert_100_update_and_scan_same_tx_old() {
    create_and_drop("i100u_tx", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("something").into_bytes();
        let mut inserted = Vec::new();
        for _ in [0; 50].iter() {
            inserted.push(persy.insert_record(&mut tx, "test", &bytes).unwrap());
        }
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let bytes_other = String::from("other").into_bytes();
        let mut tx = persy.begin().unwrap();
        for _ in [0; 50].iter() {
            persy.insert_record(&mut tx, "test", &bytes).unwrap();
        }
        for id in inserted.iter() {
            persy.update_record(&mut tx, "test", id, &bytes_other).unwrap();
        }

        let mut count = 0;
        for rec in persy.scan_records_tx(&mut tx, "test").unwrap() {
            if inserted.contains(&rec.id) {
                assert_eq!(rec.content, bytes_other);
            } else {
                assert_eq!(rec.content, bytes);
            }
            count += 1;
        }
        assert_eq!(count, 100);
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();
    });
}

#[test]
fn test_create_insert_scan_same_tx() {
    create_and_drop("cistx", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("something").into_bytes();
        for _ in [0; 50].iter() {
            persy.insert_record(&mut tx, "test", &bytes).unwrap();
        }
        let mut count = 0;
        for (_, content) in persy.scan_tx(&mut tx, "test").unwrap() {
            assert_eq!(content, bytes);
            count += 1;
        }
        assert_eq!(count, 50);
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();
    });
}

#[test]
fn test_create_insert_scan_same_tx_access() {
    create_and_drop("cistx", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        persy.create_segment(&mut tx, "test1").unwrap();
        let bytes = String::from("something").into_bytes();
        for _ in [0; 50].iter() {
            persy.insert_record(&mut tx, "test", &bytes).unwrap();
        }
        let mut count = 0;
        let mut iter = persy.scan_tx(&mut tx, "test").unwrap();
        persy.insert_record(iter.tx(), "test1", "bytes".as_bytes()).unwrap();
        let new_bytes = String::from("other").into_bytes();
        while let Some((id, content, tx)) = iter.next_tx() {
            assert_eq!(content, bytes);
            count += 1;
            persy.update_record(tx, "test", &id, &new_bytes).unwrap();
        }
        assert_eq!(count, 50);
        let mut count = 0;
        for (_, content) in persy.scan_tx(&mut tx, "test").unwrap() {
            assert_eq!(content, new_bytes);
            count += 1;
        }
        assert_eq!(count, 50);
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();
    });
}

#[test]
fn test_insert_100_and_scan_same_tx() {
    create_and_drop("i100tx", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("something").into_bytes();
        for _ in [0; 50].iter() {
            persy.insert_record(&mut tx, "test", &bytes).unwrap();
        }
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let mut tx = persy.begin().unwrap();
        for _ in [0; 50].iter() {
            persy.insert_record(&mut tx, "test", &bytes).unwrap();
        }
        let mut count = 0;
        for (_, content) in persy.scan_tx(&mut tx, "test").unwrap() {
            assert_eq!(content, bytes);
            count += 1;
        }
        assert_eq!(count, 100);
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();
    });
}

#[test]
fn test_insert_100_update_and_scan_same_tx() {
    create_and_drop("i100u_tx", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("something").into_bytes();
        let mut inserted = Vec::new();
        for _ in [0; 50].iter() {
            inserted.push(persy.insert_record(&mut tx, "test", &bytes).unwrap());
        }
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let bytes_other = String::from("other").into_bytes();
        let mut tx = persy.begin().unwrap();
        for _ in [0; 50].iter() {
            persy.insert_record(&mut tx, "test", &bytes).unwrap();
        }
        for id in inserted.iter() {
            persy.update_record(&mut tx, "test", id, &bytes_other).unwrap();
        }

        let mut count = 0;
        for (id, content) in persy.scan_tx(&mut tx, "test").unwrap() {
            if inserted.contains(&id) {
                assert_eq!(content, bytes_other);
            } else {
                assert_eq!(content, bytes);
            }
            count += 1;
        }
        assert_eq!(count, 100);
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();
    });
}

#[test]
#[allow(deprecated)]
fn test_scan_tx_segment_not_exist_old() {
    create_and_drop("sne_tx", |persy| {
        let mut tx = persy.begin().unwrap();
        let res = persy.scan_records_tx(&mut tx, "test");
        if let Err(x) = res {
            match x {
                PersyError::SegmentNotFound => {}
                _ => assert!(false),
            }
        } else {
            assert!(false);
        }
    });
}

#[test]
fn test_scan_tx_segment_not_exist() {
    create_and_drop("sne_tx", |persy| {
        let mut tx = persy.begin().unwrap();
        let res = persy.scan_tx(&mut tx, "test");
        if let Err(x) = res {
            match x {
                PersyError::SegmentNotFound => {}
                _ => assert!(false),
            }
        } else {
            assert!(false);
        }
    });
}

#[test]
fn test_concurrency_version_on_write() {
    let mut config = Config::new();
    config.change_tx_strategy(TxStrategy::VersionOnWrite);
    create_and_drop_with_config("cvow", config, |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "seg").unwrap();
        let bytes = String::from("aaa").into_bytes();
        let id = persy.insert_record(&mut tx, "seg", &bytes).unwrap();
        let prep = persy.prepare_commit(tx).unwrap();
        persy.commit(prep).unwrap();

        let bytes2 = String::from("bbb").into_bytes();
        let mut tx = persy.begin().unwrap();
        persy.update_record(&mut tx, "seg", &id, &bytes2).unwrap();

        let bytes3 = String::from("cccc").into_bytes();
        let mut tx1 = persy.begin().unwrap();
        persy.update_record(&mut tx1, "seg", &id, &bytes3).unwrap();

        let prep = persy.prepare_commit(tx1).unwrap();
        persy.commit(prep).unwrap();
        let to_fail = persy.prepare_commit(tx);
        assert!(to_fail.is_err());
        let val = persy.read_record("seg", &id).unwrap().unwrap();
        assert_eq!(val, bytes3);
    });
}

#[test]
fn test_concurrency_last_win() {
    let mut config = Config::new();
    config.change_tx_strategy(TxStrategy::LastWin);
    create_and_drop_with_config("cvol", config, |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "seg").unwrap();
        let bytes = String::from("aaa").into_bytes();
        let id = persy.insert_record(&mut tx, "seg", &bytes).unwrap();
        let prep = persy.prepare_commit(tx).unwrap();
        persy.commit(prep).unwrap();

        let bytes2 = String::from("bbb").into_bytes();
        let mut tx = persy.begin().unwrap();
        persy.update_record(&mut tx, "seg", &id, &bytes2).unwrap();

        let bytes3 = String::from("cccc").into_bytes();
        let mut tx1 = persy.begin().unwrap();
        persy.update_record(&mut tx1, "seg", &id, &bytes3).unwrap();

        let prep = persy.prepare_commit(tx1).unwrap();
        persy.commit(prep).unwrap();

        let prep = persy.prepare_commit(tx).unwrap();
        persy.commit(prep).unwrap();

        let val = persy.read_record("seg", &id).unwrap().unwrap();
        assert_eq!(val, bytes2);
    });
}

#[test]
fn test_concurrency_version_on_read() {
    let mut config = Config::new();
    config.change_tx_strategy(TxStrategy::VersionOnRead);
    create_and_drop_with_config("cvor", config, |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "seg").unwrap();
        let bytes = String::from("aaa").into_bytes();
        let id = persy.insert_record(&mut tx, "seg", &bytes).unwrap();
        let prep = persy.prepare_commit(tx).unwrap();
        persy.commit(prep).unwrap();

        let bytes2 = String::from("bbb").into_bytes();
        let mut tx = persy.begin().unwrap();
        let _ = persy.read_record_tx(&mut tx, "seg", &id).unwrap();

        let bytes3 = String::from("cccc").into_bytes();

        let mut tx1 = persy.begin().unwrap();
        persy.update_record(&mut tx1, "seg", &id, &bytes3).unwrap();
        let prep = persy.prepare_commit(tx1).unwrap();
        persy.commit(prep).unwrap();

        persy.update_record(&mut tx, "seg", &id, &bytes2).unwrap();
        let to_fail = persy.prepare_commit(tx);
        assert!(to_fail.is_err());

        let val = persy.read_record("seg", &id).unwrap().unwrap();
        assert_eq!(val, bytes3);
    });
}

#[test]
#[allow(deprecated)]
fn test_scan_segment_not_exist_old() {
    create_and_drop("sne", |persy| {
        let res = persy.scan_records("test");
        if let Err(x) = res {
            match x {
                PersyError::SegmentNotFound => {}
                _ => assert!(false),
            }
        } else {
            assert!(false);
        }
    });
}

#[test]
fn test_scan_segment_not_exist() {
    create_and_drop("sne", |persy| {
        let res = persy.scan("test");
        if let Err(x) = res {
            match x {
                PersyError::SegmentNotFound => {}
                _ => assert!(false),
            }
        } else {
            assert!(false);
        }
    });
}