use super::*;
#[test]
fn create_bitmap_index_persists_to_manifest() {
let base_dir = temp_dir("bitmap_index_manifest_persist");
let wal_dir = base_dir.join("wal");
let manifest_path = base_dir.join("ir.manifest");
let sstable_dir = base_dir.join("sst");
let reactor = std::sync::Arc::new(crate::core::reactor::DeterministicReactor::new(
std::time::SystemTime::UNIX_EPOCH,
907,
));
let mut handle = open_store_with_reactor(
StorageConfig {
buffer_pool_pages: 8,
wal_dir,
wal_segment_max_bytes: 1024 * 1024,
manifest_path: manifest_path.clone(),
sstable_dir,
},
reactor,
)
.unwrap();
create_bitmap_index(&mut handle, "idx_country", "n.country").unwrap();
create_bitmap_index(&mut handle, "idx_risk_tier", "n.risk_tier").unwrap();
let indexes = list_bitmap_indexes(&handle);
assert_eq!(indexes.len(), 2);
assert_eq!(indexes[0].index_name, "idx_country");
assert_eq!(indexes[1].index_name, "idx_risk_tier");
let reloaded = crate::features::storage::manifest::Manifest::load(&manifest_path).unwrap();
let persisted = reloaded.bitmap_indexes();
assert_eq!(persisted.len(), 2);
assert_eq!(persisted[0].index_name, "idx_country");
assert_eq!(persisted[0].field_path, "n.country");
assert_eq!(persisted[1].index_name, "idx_risk_tier");
assert_eq!(persisted[1].field_path, "n.risk_tier");
}
#[test]
fn bitmap_postings_flush_and_reload_round_trip() {
let base_dir = temp_dir("bitmap_postings_round_trip");
let wal_dir = base_dir.join("wal");
let manifest_path = base_dir.join("ir.manifest");
let sstable_dir = base_dir.join("sst");
let reactor = std::sync::Arc::new(crate::core::reactor::DeterministicReactor::new(
std::time::SystemTime::UNIX_EPOCH,
908,
));
let mut handle = open_store_with_reactor(
StorageConfig {
buffer_pool_pages: 8,
wal_dir: wal_dir.clone(),
wal_segment_max_bytes: 1024 * 1024,
manifest_path: manifest_path.clone(),
sstable_dir: sstable_dir.clone(),
},
reactor.clone(),
)
.unwrap();
create_bitmap_index(&mut handle, "idx_country", "n.country").unwrap();
bitmap_add_posting(&mut handle, "idx_country", "US", 10).unwrap();
bitmap_add_posting(&mut handle, "idx_country", "US", 12).unwrap();
bitmap_add_posting(&mut handle, "idx_country", "GB", 11).unwrap();
flush(&mut handle).unwrap();
assert_eq!(bitmap_postings(&handle, "idx_country", "US"), vec![10, 12]);
assert_eq!(bitmap_postings(&handle, "idx_country", "GB"), vec![11]);
drop(handle);
let reopened = open_store_with_reactor(
StorageConfig {
buffer_pool_pages: 8,
wal_dir,
wal_segment_max_bytes: 1024 * 1024,
manifest_path,
sstable_dir,
},
reactor,
)
.unwrap();
assert_eq!(
bitmap_postings(&reopened, "idx_country", "US"),
vec![10, 12]
);
assert_eq!(bitmap_postings(&reopened, "idx_country", "GB"), vec![11]);
}
#[test]
fn bitmap_add_posting_rejects_unknown_index() {
let base_dir = temp_dir("bitmap_unknown_index");
let wal_dir = base_dir.join("wal");
let manifest_path = base_dir.join("ir.manifest");
let sstable_dir = base_dir.join("sst");
let reactor = std::sync::Arc::new(crate::core::reactor::DeterministicReactor::new(
std::time::SystemTime::UNIX_EPOCH,
909,
));
let mut handle = open_store_with_reactor(
StorageConfig {
buffer_pool_pages: 8,
wal_dir,
wal_segment_max_bytes: 1024 * 1024,
manifest_path,
sstable_dir,
},
reactor,
)
.unwrap();
let err = bitmap_add_posting(&mut handle, "idx_missing", "US", 1).unwrap_err();
match err {
StorageError::InvalidInput(msg) => assert!(msg.contains("unknown bitmap index")),
other => panic!("unexpected error: {:?}", other),
}
}
#[test]
fn recover_from_wal_replays_bitmap_postings() {
let base_dir = temp_dir("recover_bitmap_wal");
let wal_dir = base_dir.join("wal");
let manifest_path = base_dir.join("ir.manifest");
let sstable_dir = base_dir.join("sst");
let reactor = std::sync::Arc::new(crate::core::reactor::DeterministicReactor::new(
std::time::SystemTime::UNIX_EPOCH,
910,
));
{
let mut handle = open_store_with_reactor(
StorageConfig {
buffer_pool_pages: 8,
wal_dir: wal_dir.clone(),
wal_segment_max_bytes: 1024 * 1024,
manifest_path: manifest_path.clone(),
sstable_dir: sstable_dir.clone(),
},
reactor.clone(),
)
.unwrap();
create_bitmap_index(&mut handle, "idx_country", "n.country").unwrap();
bitmap_add_posting(&mut handle, "idx_country", "US", 21).unwrap();
bitmap_add_posting(&mut handle, "idx_country", "US", 22).unwrap();
}
let mut recovered = open_store_with_reactor(
StorageConfig {
buffer_pool_pages: 8,
wal_dir,
wal_segment_max_bytes: 1024 * 1024,
manifest_path,
sstable_dir,
},
reactor,
)
.unwrap();
let applied = recover_from_wal(&mut recovered).unwrap();
assert!(applied >= 2);
assert_eq!(
bitmap_postings(&recovered, "idx_country", "US"),
vec![21, 22]
);
}
#[test]
fn bitmap_postings_survive_compaction_and_reopen() {
let base_dir = temp_dir("bitmap_compaction_reopen");
let wal_dir = base_dir.join("wal");
let manifest_path = base_dir.join("ir.manifest");
let sstable_dir = base_dir.join("sst");
let reactor = std::sync::Arc::new(crate::core::reactor::DeterministicReactor::new(
std::time::SystemTime::UNIX_EPOCH,
911,
));
let mut handle = open_store_with_reactor(
StorageConfig {
buffer_pool_pages: 8,
wal_dir: wal_dir.clone(),
wal_segment_max_bytes: 1024 * 1024,
manifest_path: manifest_path.clone(),
sstable_dir: sstable_dir.clone(),
},
reactor.clone(),
)
.unwrap();
create_bitmap_index(&mut handle, "idx_country", "n.country").unwrap();
put_full_node(&mut handle, 1, 1, &[2]).unwrap();
bitmap_add_posting(&mut handle, "idx_country", "US", 1).unwrap();
flush(&mut handle).unwrap();
put_full_node(&mut handle, 2, 1, &[3]).unwrap();
bitmap_add_posting(&mut handle, "idx_country", "US", 2).unwrap();
flush(&mut handle).unwrap();
assert!(handle.l0_runs.len() >= 2);
compact(&mut handle, Some(0)).unwrap();
assert_eq!(bitmap_postings(&handle, "idx_country", "US"), vec![1, 2]);
drop(handle);
let reopened = open_store_with_reactor(
StorageConfig {
buffer_pool_pages: 8,
wal_dir,
wal_segment_max_bytes: 1024 * 1024,
manifest_path,
sstable_dir,
},
reactor,
)
.unwrap();
assert_eq!(bitmap_postings(&reopened, "idx_country", "US"), vec![1, 2]);
}