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::V3Backend;
use crate::SqliteGraphError;
use crate::backend::native::v3::btree::BTreeManager;
use crate::backend::native::v3::name_index::NameIndex;
use crate::backend::native::v3::wal::{V3WALPaths, WALWriter};
use crate::backend::native::v3::{
    FileCoordinator, KindIndex, KvStore, NodeCache, NodeStore, PageAllocator, PersistentHeaderV3,
    V3EdgeStore,
};
use parking_lot::{Mutex, RwLock};
use rusqlite::Connection;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::Arc;

impl V3Backend {
    pub(crate) fn assemble_backend(
        db_path: PathBuf,
        coordinator: Arc<FileCoordinator>,
        sqlite_conn: Connection,
        btree: BTreeManager,
        node_store: NodeStore,
        edge_store: V3EdgeStore,
        allocator: Arc<RwLock<PageAllocator>>,
        wal: Option<Arc<RwLock<WALWriter>>>,
        header: PersistentHeaderV3,
        kind_index: KindIndex,
        name_index: NameIndex,
    ) -> Self {
        Self {
            db_path,
            file_coordinator: Some(coordinator),
            async_coordinator: std::sync::OnceLock::new(),
            sqlite_conn: Arc::new(Mutex::new(sqlite_conn)),
            btree: RwLock::new(btree),
            node_store: RwLock::new(node_store),
            edge_store: RwLock::new(edge_store),
            allocator,
            wal,
            header: RwLock::new(header),
            kv_store: RwLock::new(None),
            publisher: RwLock::new(None),
            kind_index,
            name_index,
            node_cache: NodeCache::new(
                crate::backend::native::v3::constants::node_cache::DEFAULT_CACHE_CAPACITY,
            ),
            current_snapshot_version: RwLock::new(1),
            snapshot_registry: RwLock::new(HashMap::new()),
            hnsw_indexes: RwLock::new(HashMap::new()),
            graph_tx_state: Mutex::new(
                super::super::transaction_state::GraphTransactionState::default(),
            ),
        }
    }

    pub(crate) fn create_wal_writer(
        db_path: &Path,
    ) -> Result<Arc<RwLock<WALWriter>>, SqliteGraphError> {
        let wal_path = V3WALPaths::wal_file(db_path);
        let wal_writer = WALWriter::new(wal_path, 1)
            .map_err(|e| SqliteGraphError::connection(format!("Failed to create WAL: {:?}", e)))?;
        wal_writer.write_header().map_err(|e| {
            SqliteGraphError::connection(format!("Failed to write WAL header: {:?}", e))
        })?;
        Ok(Arc::new(RwLock::new(wal_writer)))
    }

    pub(crate) fn open_wal_if_present(
        db_path: &Path,
    ) -> Result<Option<Arc<RwLock<WALWriter>>>, SqliteGraphError> {
        let wal_path = V3WALPaths::wal_file(db_path);
        if !wal_path.exists() {
            return Ok(None);
        }

        let wal_writer = WALWriter::new(wal_path, 1)
            .map_err(|e| SqliteGraphError::connection(format!("Failed to open WAL: {:?}", e)))?;
        Ok(Some(Arc::new(RwLock::new(wal_writer))))
    }

    pub(crate) fn recover_kv_store(db_path: &Path) -> Option<KvStore> {
        let wal_path = V3WALPaths::wal_file(db_path);
        let mut kv_store = KvStore::new();
        let mut recovered = false;

        if wal_path.exists() {
            let mut recovery = crate::backend::native::v3::wal::WALRecovery::new(wal_path);
            if let Ok(count) = recovery.recover_kv(&mut kv_store) {
                recovered = count > 0;
            }
        }

        if !recovered
            && let Ok(found) =
                crate::backend::native::v3::wal::read_kv_checkpoint(db_path, &mut kv_store)
        {
            recovered = found;
        }

        recovered.then_some(kv_store)
    }
}