#![cfg(feature = "persistent-artrie")]
use std::sync::Arc;
use libdictenstein::artrie_trait::EvictableARTrie;
use libdictenstein::persistent_artrie::eviction::EvictionConfig;
use libdictenstein::persistent_artrie::{PersistentARTrie, WalConfig};
use libdictenstein::persistent_artrie_char::PersistentARTrieChar;
use libdictenstein::persistent_artrie_core::durability::DurabilityPolicy;
use libdictenstein::MappedDictionary;
fn scratch(prefix: &str) -> tempfile::TempDir {
std::fs::create_dir_all("target/test-tmp").ok();
tempfile::Builder::new()
.prefix(prefix)
.tempdir_in("target/test-tmp")
.expect("scratch tempdir under target/test-tmp")
}
#[test]
fn arc_commit_document_byte_needs_no_mut() {
let dir = scratch("libg-arc-commit-byte");
let path = dir.path().join("c.artb");
let mut trie = PersistentARTrie::<u64>::create(&path).expect("create");
trie.set_durability_policy(DurabilityPolicy::Immediate);
let trie = Arc::new(trie);
let worker = Arc::clone(&trie);
let committed = std::thread::spawn(move || {
let mut tx = worker.begin_document("doc-A").expect("begin");
worker.tx_insert(&mut tx, "alpha", Some(1));
worker.tx_insert(&mut tx, "beta", Some(2));
worker.commit_document(tx).expect("commit on Arc")
})
.join()
.expect("worker thread");
assert_eq!(committed, 2, "two new terms committed via the Arc");
let mut tx2 = trie.begin_document("doc-B").expect("begin2");
trie.tx_insert(&mut tx2, "gamma", Some(3));
assert_eq!(trie.commit_document(tx2).expect("commit2"), 1);
assert_eq!(MappedDictionary::get_value(&*trie, "alpha"), Some(1));
assert_eq!(MappedDictionary::get_value(&*trie, "beta"), Some(2));
assert_eq!(MappedDictionary::get_value(&*trie, "gamma"), Some(3));
}
#[test]
fn arc_commit_document_char_needs_no_mut() {
let dir = scratch("libg-arc-commit-char");
let path = dir.path().join("c.artc");
let mut trie = PersistentARTrieChar::<u64>::create_with_config(&path, WalConfig::no_archive())
.expect("create");
trie.set_durability_policy(DurabilityPolicy::Immediate);
let trie = Arc::new(trie);
let worker = Arc::clone(&trie);
let committed = std::thread::spawn(move || {
let mut tx = worker.begin_document("doc-A").expect("begin");
worker.tx_insert(&mut tx, "αlpha", Some(1));
worker.tx_insert(&mut tx, "βeta", Some(2));
worker.commit_document(tx).expect("commit on Arc")
})
.join()
.expect("worker thread");
assert_eq!(committed, 2);
assert_eq!(MappedDictionary::get_value(&*trie, "αlpha"), Some(1));
assert_eq!(MappedDictionary::get_value(&*trie, "βeta"), Some(2));
}
#[test]
fn public_eviction_stats_resident_bytes_and_checkpoint_tail_nodes_evicted() {
fn run(budget: Option<usize>) -> (u64, u64) {
let dir = scratch("libg-evict-stats");
let path = dir.path().join("e.artc");
let mut trie =
PersistentARTrieChar::<u64>::create_with_config(&path, WalConfig::no_archive())
.expect("create");
trie.set_durability_policy(DurabilityPolicy::Immediate);
let trie = Arc::new(trie);
let config = EvictionConfig {
resident_budget_bytes: budget,
..EvictionConfig::without_memory_monitor()
};
trie.enable_eviction(config).expect("enable_eviction");
for i in 0..2_000u32 {
let term = format!("ngram-{i:06}");
trie.try_increment_cas_durable(&term, 1).expect("increment");
}
trie.checkpoint().expect("checkpoint");
let stats = trie.eviction_stats();
trie.disable_eviction().ok();
(stats.resident_bytes, stats.nodes_evicted)
}
let (budg_resident, budg_evicted) = run(Some(4_000));
let (ctrl_resident, ctrl_evicted) = run(None);
assert!(
budg_evicted > 0,
"the checkpoint-tail resident-budget eviction must feed nodes_evicted (the #45 fix); got {budg_evicted}"
);
assert_eq!(
ctrl_evicted, 0,
"no resident budget ⇒ no checkpoint-tail eviction; got {ctrl_evicted}"
);
assert!(
ctrl_resident > 0,
"resident_bytes must report the live overlay heap; got 0 with 2000 resident nodes"
);
assert!(
budg_resident <= ctrl_resident,
"the resident budget must not grow the resident heap ({budg_resident} <= {ctrl_resident})"
);
}