iridium-db 0.4.0

A high-performance vector-graph hybrid storage and indexing engine
use super::*;

fn open(base: &std::path::Path) -> StorageHandle {
    open_store(StorageConfig {
        buffer_pool_pages: 8,
        wal_dir: base.join("wal"),
        wal_segment_max_bytes: 1 << 20,
        manifest_path: base.join("ir.manifest"),
        sstable_dir: base.join("sst"),
    })
    .unwrap()
}

#[test]
fn insert_node_with_embedding_pending_flag_is_marked() {
    let base = temp_dir("embed_pending_flag");
    let mut handle = open(&base);

    put_full_node(&mut handle, 10, 1, &[11]).unwrap();
    put_embedding_pending(&mut handle, 10).unwrap();

    assert!(node_is_embedding_pending(&handle, 10));
    // Node is still graph-queryable.
    let logical = get_logical_node(&mut handle, 10).unwrap();
    assert!(logical.full.is_some());
    assert_eq!(logical.adjacency(), vec![11]);
}

#[test]
fn update_vector_delta_clears_pending_flag() {
    let base = temp_dir("embed_pending_cleared");
    let mut handle = open(&base);

    put_full_node(&mut handle, 20, 1, &[]).unwrap();
    put_embedding_pending(&mut handle, 20).unwrap();
    assert!(node_is_embedding_pending(&handle, 20));

    let delta = encode_delta(
        20,
        2,
        &encode_vector_payload_f32(1, VectorMetric::Cosine, &[1.0, 0.0], false),
    );
    put_vector_delta(&mut handle, &delta).unwrap();

    assert!(!node_is_embedding_pending(&handle, 20));
}

#[test]
fn wal_replay_reconstructs_pending_set() {
    let base = temp_dir("embed_pending_wal_replay");
    {
        let mut handle = open(&base);
        put_full_node(&mut handle, 30, 1, &[]).unwrap();
        put_embedding_pending(&mut handle, 30).unwrap();
        put_full_node(&mut handle, 31, 1, &[]).unwrap();
        // node 31 gets a vector before we close; should not be in the pending set after replay.
        let delta = encode_delta(
            31,
            2,
            &encode_vector_payload_f32(1, VectorMetric::Cosine, &[0.5, 0.5], false),
        );
        put_vector_delta(&mut handle, &delta).unwrap();
    }

    // Reopen: recover from WAL rebuilds the pending set.
    let mut handle = open(&base);
    recover_from_wal(&mut handle).unwrap();

    assert!(
        node_is_embedding_pending(&handle, 30),
        "node 30 should still be pending after replay"
    );
    assert!(
        !node_is_embedding_pending(&handle, 31),
        "node 31 received a vector, should not be pending"
    );
}

#[test]
fn non_pending_node_not_marked() {
    let base = temp_dir("embed_pending_not_marked");
    let mut handle = open(&base);
    put_full_node(&mut handle, 99, 1, &[]).unwrap();
    assert!(!node_is_embedding_pending(&handle, 99));
}

#[test]
fn pending_flag_absent_for_unknown_node() {
    let base = temp_dir("embed_pending_unknown");
    let handle = open(&base);
    assert!(!node_is_embedding_pending(&handle, 12345));
}