sqlitegraph 3.9.0

Embedded graph database with explicit SQLite, native-v3, and combined backend modes; HNSW vector search; and graph algorithms
Documentation
use super::*;

pub(super) fn restore_indexes(
    db_path: &Path,
    db_node_count: u64,
) -> Result<(KindIndex, NameIndex), IndexPersistenceError> {
    let index_path = super::index_path_for_db(db_path);

    #[cfg(feature = "v3-forensics")]
    let file_open_syscall_start = std::time::Instant::now();

    let mut file = std::fs::File::open(&index_path)
        .map_err(|_| IndexPersistenceError::Corrupted("Index file not found".to_string()))?;

    #[cfg(feature = "v3-forensics")]
    let file_open_syscall_elapsed = file_open_syscall_start.elapsed();

    #[cfg(feature = "v3-forensics")]
    let file_open_start = std::time::Instant::now();

    let magic = support::read_array::<4, _>(&mut file, "magic")?;
    if &magic != INDEX_MAGIC {
        return Err(IndexPersistenceError::InvalidMagic(magic.to_vec()));
    }

    let version = u32::from_be_bytes(support::read_array::<4, _>(&mut file, "version")?);
    if version != INDEX_VERSION {
        return Err(IndexPersistenceError::UnsupportedVersion(version));
    }

    let stored_node_count =
        u64::from_be_bytes(support::read_array::<8, _>(&mut file, "stored node count")?);
    if stored_node_count != db_node_count {
        return Err(IndexPersistenceError::Corrupted(format!(
            "Stale index: sidecar node_count {} != DB node_count {}",
            stored_node_count, db_node_count
        )));
    }

    #[cfg(feature = "v3-forensics")]
    let file_open_elapsed = file_open_start.elapsed();

    #[cfg(feature = "v3-forensics")]
    let bulk_read_start = std::time::Instant::now();

    let mut remaining_data = Vec::new();
    file.read_to_end(&mut remaining_data).map_err(|e| {
        IndexPersistenceError::Corrupted(format!("Failed to read index data: {}", e))
    })?;

    #[cfg(feature = "v3-forensics")]
    let bulk_read_elapsed = bulk_read_start.elapsed();

    let mut cursor = support::SliceCursor::new(&remaining_data);
    let kind_count = cursor.read_u32()? as usize;

    #[cfg(feature = "v3-forensics")]
    let kind_loop_start = std::time::Instant::now();

    let kind_data = support::read_string_index_entries(&mut cursor, kind_count, "kind")?;

    #[cfg(feature = "v3-forensics")]
    let kind_loop_elapsed = kind_loop_start.elapsed();

    let name_count = cursor.read_u32()? as usize;

    #[cfg(feature = "v3-forensics")]
    let name_loop_start = std::time::Instant::now();

    let name_data = support::read_string_index_entries(&mut cursor, name_count, "name")?;

    #[cfg(feature = "v3-forensics")]
    let name_loop_elapsed = name_loop_start.elapsed();

    #[cfg(feature = "v3-forensics")]
    let index_creation_start = std::time::Instant::now();

    let kind_index = KindIndex::new();
    let name_index = NameIndex::new();

    #[cfg(feature = "v3-forensics")]
    let index_creation_elapsed = index_creation_start.elapsed();

    #[cfg(feature = "v3-forensics")]
    let hashmap_import_start = std::time::Instant::now();

    kind_index.import(kind_data);
    name_index.import(name_data);

    #[cfg(feature = "v3-forensics")]
    let hashmap_import_elapsed = hashmap_import_start.elapsed();

    #[cfg(feature = "v3-forensics")]
    {
        use std::io::Write;
        let _ = std::io::stderr().flush();
        eprintln!("    [restore_indexes breakdown]");
        eprintln!(
            "      - File::open() syscall:    {:.2} µs",
            file_open_syscall_elapsed.as_secs_f64() * 1_000_000.0
        );
        eprintln!(
            "      - read/verify header:      {:.2} µs",
            file_open_elapsed.as_secs_f64() * 1_000_000.0
        );
        eprintln!(
            "      - bulk_read() all data:    {:.2} µs ({:.2} KB)",
            bulk_read_elapsed.as_secs_f64() * 1_000_000.0,
            remaining_data.len() as f64 / 1024.0
        );
        eprintln!(
            "      - kind_loop ({}, entries):   {:.2} µs",
            kind_count,
            kind_loop_elapsed.as_secs_f64() * 1_000_000.0
        );
        eprintln!(
            "      - name_loop ({}, entries):   {:.2} µs",
            name_count,
            name_loop_elapsed.as_secs_f64() * 1_000_000.0
        );
        eprintln!(
            "      - index creation (2 objs):  {:.2} µs",
            index_creation_elapsed.as_secs_f64() * 1_000_000.0
        );
        eprintln!(
            "      - hashmap import:            {:.2} µs",
            hashmap_import_elapsed.as_secs_f64() * 1_000_000.0
        );
        let _ = std::io::stderr().flush();
    }

    Ok((kind_index, name_index))
}