use cesiumdb::{
Db,
DbOptions,
};
use tempfile::TempDir;
#[test]
fn test_l0_key_ranges_persist_across_flush() {
let temp_dir = TempDir::new().unwrap();
let mut opts = DbOptions::new();
opts.data_dir(temp_dir.path().to_path_buf())
.memtable_size(512 * 1024) .max_memtables(2);
let db = Db::open(opts);
for c in b'a'..=b'z' {
db.put(&[c], b"value").unwrap();
}
db.sync().unwrap();
for c in b'a'..=b'z' {
let result = db.get(&[c]).unwrap();
assert!(result.is_some(), "Key {} should be present", c as char);
assert_eq!(&result.unwrap()[..], b"value");
}
db.close().unwrap();
}
#[test]
fn test_l0_key_ranges_recovered_from_manifest() {
let temp_dir = TempDir::new().unwrap();
let mut opts = DbOptions::new();
opts.data_dir(temp_dir.path().to_path_buf())
.memtable_size(512 * 1024)
.max_memtables(2);
{
let mut opts1 = DbOptions::new();
opts1
.data_dir(temp_dir.path().to_path_buf())
.memtable_size(512 * 1024)
.max_memtables(2);
let db = Db::open(opts1);
db.put(b"m", b"value_m").unwrap();
db.put(b"p", b"value_p").unwrap();
db.put(b"x", b"value_x").unwrap();
db.sync().unwrap();
db.close().unwrap();
}
{
let mut opts2 = DbOptions::new();
opts2
.data_dir(temp_dir.path().to_path_buf())
.memtable_size(512 * 1024)
.max_memtables(2);
let db = Db::open(opts2);
let result_m = db.get(b"m").unwrap();
assert!(
result_m.is_some(),
"Key 'm' should be present after recovery"
);
assert_eq!(&result_m.unwrap()[..], b"value_m");
let result_p = db.get(b"p").unwrap();
assert!(
result_p.is_some(),
"Key 'p' should be present after recovery"
);
assert_eq!(&result_p.unwrap()[..], b"value_p");
let result_x = db.get(b"x").unwrap();
assert!(
result_x.is_some(),
"Key 'x' should be present after recovery"
);
assert_eq!(&result_x.unwrap()[..], b"value_x");
db.close().unwrap();
}
}
#[test]
fn test_multiple_l0_segments_have_key_ranges() {
let temp_dir = TempDir::new().unwrap();
let mut opts = DbOptions::new();
opts.data_dir(temp_dir.path().to_path_buf())
.memtable_size(512 * 1024)
.max_memtables(2);
let db = Db::open(opts);
for i in 0..1000 {
let key = format!("a_key_{:05}", i);
db.put(key.as_bytes(), b"value_a").unwrap();
}
db.sync().unwrap();
for i in 0..1000 {
let key = format!("m_key_{:05}", i);
db.put(key.as_bytes(), b"value_m").unwrap();
}
db.sync().unwrap();
for i in 0..1000 {
let key = format!("z_key_{:05}", i);
db.put(key.as_bytes(), b"value_z").unwrap();
}
db.sync().unwrap();
for i in 0..1000 {
let key_a = format!("a_key_{:05}", i);
let result = db.get(key_a.as_bytes()).unwrap();
assert!(result.is_some(), "Key {} should be present", key_a);
let key_m = format!("m_key_{:05}", i);
let result = db.get(key_m.as_bytes()).unwrap();
assert!(result.is_some(), "Key {} should be present", key_m);
let key_z = format!("z_key_{:05}", i);
let result = db.get(key_z.as_bytes()).unwrap();
assert!(result.is_some(), "Key {} should be present", key_z);
}
db.close().unwrap();
}
#[test]
#[ignore]
fn test_l0_compaction_uses_key_ranges() {
let temp_dir = TempDir::new().unwrap();
let mut opts = DbOptions::new();
opts.data_dir(temp_dir.path().to_path_buf())
.memtable_size(256 * 1024) .max_memtables(2);
let db = Db::open(opts);
for batch in 0..10 {
for i in 0..500 {
let key = format!("key_batch{:02}_item{:05}", batch, i);
db.put(key.as_bytes(), b"test_value").unwrap();
}
db.sync().unwrap();
}
db.compact().unwrap();
std::thread::sleep(std::time::Duration::from_secs(5));
for batch in 0..10 {
for i in 0..500 {
let key = format!("key_batch{:02}_item{:05}", batch, i);
let result = db.get(key.as_bytes()).unwrap();
assert!(
result.is_some(),
"Key {} should be present after compaction",
key
);
assert_eq!(
&result.unwrap()[..],
b"test_value",
"Value mismatch for key {} after compaction",
key
);
}
}
db.close().unwrap();
}