use mongreldb_core::schema::{ColumnDef, ColumnFlags, IndexDef, IndexKind, Schema, TypeId};
use mongreldb_core::{Table, Value};
use tempfile::tempdir;
fn schema() -> Schema {
Schema {
schema_id: 1,
columns: vec![
ColumnDef {
id: 1,
name: "id".into(),
ty: TypeId::Int64,
flags: ColumnFlags::empty().with(ColumnFlags::PRIMARY_KEY),
},
ColumnDef {
id: 2,
name: "v".into(),
ty: TypeId::Int64,
flags: ColumnFlags::empty(),
},
],
indexes: vec![IndexDef {
name: "v_lr".into(),
column_id: 2,
kind: IndexKind::LearnedRange,
predicate: None,
}],
colocation: vec![],
constraints: Default::default(),
clustered: false,
}
}
#[test]
fn shared_cache_serves_reads_across_readers() {
let dir = tempdir().unwrap();
let mut db = Table::create(dir.path(), schema(), 1).unwrap();
for i in 0..200_000i64 {
db.put(vec![(1, Value::Int64(i)), (2, Value::Int64(i * 2))])
.unwrap();
}
db.flush().unwrap();
let snap = db.snapshot();
let out = db.visible_columns_native(snap, None).unwrap();
let n = out
.iter()
.find(|(c, _)| *c == 1)
.map(|(_, c)| c.len())
.unwrap();
assert_eq!(n, 200_000);
let snap2 = db.snapshot();
let out2 = db.visible_columns_native(snap2, None).unwrap();
let n2 = out2
.iter()
.find(|(c, _)| *c == 1)
.map(|(_, c)| c.len())
.unwrap();
assert_eq!(n, n2);
}
#[test]
fn persistent_cache_survives_reopen() {
let dir = tempdir().unwrap();
{
let mut db = Table::create(dir.path(), schema(), 1).unwrap();
db.set_mutable_run_spill_bytes(1); for i in 0..100_000i64 {
db.put(vec![(1, Value::Int64(i)), (2, Value::Int64(i / 7))])
.unwrap();
}
db.flush().unwrap();
let snap = db.snapshot();
let _ = db.visible_columns_native(snap, None).unwrap();
db.page_cache_flush();
}
let cache_dir = dir.path().join("_cache");
assert!(cache_dir.exists(), "_cache dir should exist");
let spilled = std::fs::read_dir(&cache_dir).unwrap().count();
assert!(spilled > 0, "expected spilled page files, got {spilled}");
let db = Table::open(dir.path()).unwrap();
assert_eq!(db.count(), 100_000);
let snap = db.snapshot();
let out = db.visible_columns_native(snap, None).unwrap();
let n = out
.iter()
.find(|(c, _)| *c == 1)
.map(|(_, c)| c.len())
.unwrap();
assert_eq!(n, 100_000);
}
#[cfg(feature = "encryption")]
#[test]
fn cache_does_not_break_encrypted_reads() {
let dir = tempdir().unwrap();
{
let mut db = Table::create_encrypted(dir.path(), schema(), 1, "passphrase").unwrap();
for i in 0..5_000i64 {
db.put(vec![(1, Value::Int64(i)), (2, Value::Int64(i + 1))])
.unwrap();
}
db.flush().unwrap();
let s1 = db.snapshot();
let o1 = db.visible_columns_native(s1, None).unwrap();
let s2 = db.snapshot();
let o2 = db.visible_columns_native(s2, None).unwrap();
let n1 = o1
.iter()
.find(|(c, _)| *c == 1)
.map(|(_, c)| c.len())
.unwrap();
let n2 = o2
.iter()
.find(|(c, _)| *c == 1)
.map(|(_, c)| c.len())
.unwrap();
assert_eq!(n1, 5_000);
assert_eq!(n2, 5_000);
}
let db = Table::open_encrypted(dir.path(), "passphrase").unwrap();
assert_eq!(db.count(), 5_000);
}