1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//! Durability test: Db::close flushes all collection write buffers so that a
//! drop + reopen sees every previously-acknowledged write.
#![cfg(all(feature = "typed-tree", feature = "armour", feature = "rapira-codec"))]
use armdb::armour::Db;
use armdb::{CollectionMeta, Config, NoHook, RapiraCodec};
use armour_core::GetType;
use rapira::Rapira;
use tempfile::tempdir;
// ---------------------------------------------------------------------------
// Domain type
// ---------------------------------------------------------------------------
#[derive(Clone, Debug, PartialEq, Rapira, GetType)]
struct FlushItem {
value: u64,
}
impl CollectionMeta for FlushItem {
type SelfId = [u8; 8];
const NAME: &'static str = "db_close_flush_items";
const VERSION: u16 = 1;
}
fn item_key(id: u64) -> [u8; 8] {
id.to_be_bytes()
}
// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------
/// Db::close must flush collection write buffers before returning.
/// On reopen all 100 previously-written entries must be readable.
#[test]
fn db_close_flushes_collections() {
let dir = tempdir().unwrap();
const N: u64 = 100;
// Phase 1: insert N entries, then call db.close().
{
let db = Db::open(dir.path()).unwrap();
let tree = db
.open_typed_tree::<FlushItem, RapiraCodec, _>(Config::test(), NoHook, &[])
.unwrap();
for i in 0..N {
tree.put(&item_key(i), FlushItem { value: i }).unwrap();
}
// Explicit close flushes collection buffers and persists lengths.
db.close().expect("db.close() must not fail");
// Drop here; we've already called close().
}
// Phase 2: reopen and verify all entries are present.
{
let db = Db::open(dir.path()).unwrap();
let tree = db
.open_typed_tree::<FlushItem, RapiraCodec, _>(Config::test(), NoHook, &[])
.unwrap();
for i in 0..N {
let item = tree
.get(&item_key(i))
.unwrap_or_else(|| panic!("entry {i} missing after close + reopen"));
assert_eq!(item.value, i, "entry {i} has wrong value after reopen");
}
assert_eq!(tree.len(), N as usize, "collection length mismatch");
}
}