iridium-db 0.4.0

A high-performance vector-graph hybrid storage and indexing engine
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();
        // Intentionally skip flush to force WAL replay path.
    }

    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]);
}