use mmdb::{DB, DbOptions};
fn make_db(dir: &std::path::Path) -> DB {
DB::open(
DbOptions {
create_if_missing: true,
write_buffer_size: 1024, ..Default::default()
},
dir,
)
.unwrap()
}
#[test]
fn lazy_delete_removes_keys_on_compaction() {
let dir = tempfile::tempdir().unwrap();
let db = make_db(dir.path());
for i in 0u32..100 {
db.put(&i.to_be_bytes(), &[i as u8; 64]).unwrap();
}
let dead: Vec<Vec<u8>> = (50u32..80).map(|i| i.to_be_bytes().to_vec()).collect();
db.lazy_delete_batch(&dead);
assert_eq!(db.dead_key_count(), 30);
assert!(db.get(&50u32.to_be_bytes()).unwrap().is_some());
db.compact_range(None::<&[u8]>, None::<&[u8]>).unwrap();
for i in 50u32..80 {
assert!(
db.get(&i.to_be_bytes()).unwrap().is_none(),
"key {} should have been removed by lazy_delete",
i
);
}
for i in 0u32..50 {
assert!(
db.get(&i.to_be_bytes()).unwrap().is_some(),
"key {} should survive",
i
);
}
for i in 80u32..100 {
assert!(
db.get(&i.to_be_bytes()).unwrap().is_some(),
"key {} should survive",
i
);
}
}
#[test]
fn lazy_delete_single_key() {
let dir = tempfile::tempdir().unwrap();
let db = make_db(dir.path());
db.put(b"keep", b"value1").unwrap();
db.put(b"pad", &[0u8; 1024]).unwrap();
db.put(b"remove", b"value2").unwrap();
db.lazy_delete(b"remove");
assert_eq!(db.dead_key_count(), 1);
assert!(db.get(b"remove").unwrap().is_some());
db.compact_range(None::<&[u8]>, None::<&[u8]>).unwrap();
assert!(db.get(b"remove").unwrap().is_none());
assert_eq!(db.get(b"keep").unwrap().unwrap(), b"value1");
}
#[test]
fn clear_dead_keys_resets_count() {
let dir = tempfile::tempdir().unwrap();
let db = make_db(dir.path());
let keys: Vec<Vec<u8>> = (0u32..10).map(|i| i.to_be_bytes().to_vec()).collect();
db.lazy_delete_batch(&keys);
assert_eq!(db.dead_key_count(), 10);
db.clear_dead_keys();
assert_eq!(db.dead_key_count(), 0);
}
#[test]
fn lazy_delete_batch_auto_triggers_compaction() {
let dir = tempfile::tempdir().unwrap();
let db = DB::open(
DbOptions {
create_if_missing: true,
write_buffer_size: 1024,
lazy_delete_compaction_threshold: 5,
..Default::default()
},
dir.path(),
)
.unwrap();
for i in 0u32..20 {
db.put(&i.to_be_bytes(), &[i as u8; 64]).unwrap();
}
let dead: Vec<Vec<u8>> = (0u32..6).map(|i| i.to_be_bytes().to_vec()).collect();
db.lazy_delete_batch(&dead);
std::thread::sleep(std::time::Duration::from_secs(2));
for i in 0u32..6 {
assert!(
db.get(&i.to_be_bytes()).unwrap().is_none(),
"key {} should have been removed by auto-triggered compaction",
i
);
}
for i in 6u32..20 {
assert!(
db.get(&i.to_be_bytes()).unwrap().is_some(),
"key {} should survive",
i
);
}
}
#[test]
fn lazy_delete_batch_accepts_slices() {
let dir = tempfile::tempdir().unwrap();
let db = make_db(dir.path());
db.put(b"a", b"1").unwrap();
db.put(b"pad", &[0u8; 1024]).unwrap();
db.put(b"b", b"2").unwrap();
let keys: Vec<&[u8]> = vec![b"a", b"b"];
db.lazy_delete_batch(keys);
assert_eq!(db.dead_key_count(), 2);
db.compact_range(None::<&[u8]>, None::<&[u8]>).unwrap();
assert!(db.get(b"a").unwrap().is_none());
assert!(db.get(b"b").unwrap().is_none());
}