From 7ee2b9b54a56c3bfbfc1d5bfa19df572dda5efcd Mon Sep 17 00:00:00 2001 From: Pratyush Sharma <56130065+pratyush618@users.noreply.github.com> Date: Fri, 24 Apr 2026 00:48:01 +0530 Subject: [PATCH] refactor(fts): pool adapter calls loadFTSExtension, drop debug breadcrumb Addresses PR #726 review feedback. - pool-adapter.ts now calls loadFTSExtension(available[0]) in both initPool and initLbugWithDb instead of duplicating the LOAD/INSTALL try-catch chain. - loadFTSExtension accepts an optional connection and returns a boolean so the pool adapter can track shared.ftsLoaded without replicating the error handling. - Removed the console.debug breadcrumb per reviewer request. --- gitnexus/src/core/lbug/lbug-adapter.ts | 54 ++++++++++++++++---------- gitnexus/src/core/lbug/pool-adapter.ts | 29 ++------------ 2 files changed, 36 insertions(+), 47 deletions(-) diff --git a/gitnexus/src/core/lbug/lbug-adapter.ts b/gitnexus/src/core/lbug/lbug-adapter.ts index 8977b1270..a765665dc 100644 --- a/gitnexus/src/core/lbug/lbug-adapter.ts +++ b/gitnexus/src/core/lbug/lbug-adapter.ts @@ -1144,29 +1144,41 @@ export const getEmbeddingTableName = (): string => EMBEDDING_TABLE_NAME; /** * Load the FTS extension (required before using FTS functions). - * Safe to call multiple times — tracks loaded state via module-level ftsLoaded. + * + * Safe to call multiple times — when invoked without arguments, tracks loaded + * state via module-level `ftsLoaded`. When invoked with an explicit + * connection, loads on that connection and returns whether the load + * succeeded — letting callers (e.g. the pool adapter) track their own state. + * + * Tries `LOAD EXTENSION fts` first so previously-cached installs skip the + * network entirely; falls back to `INSTALL` + `LOAD` only when the extension + * hasn't been cached yet. */ -export const loadFTSExtension = async (): Promise => { - if (ftsLoaded) return; - if (!conn) { - throw new Error('LadybugDB not initialized. Call initLbug first.'); +export const loadFTSExtension = async (targetConn?: lbug.Connection): Promise => { + const useModuleState = targetConn === undefined; + if (useModuleState) { + if (ftsLoaded) return true; + if (!conn) { + throw new Error('LadybugDB not initialized. Call initLbug first.'); + } + targetConn = conn; } + + const markLoaded = (): true => { + if (useModuleState) ftsLoaded = true; + return true; + }; + try { // Try loading locally first (no network required) - await conn.query('LOAD EXTENSION fts'); - ftsLoaded = true; - } catch (err: any) { - // Fall back to install + load (requires network). Log a breadcrumb so - // cache corruption / version mismatches leave a diagnostic trail instead - // of a silent fall-through to the (slower, network-bound) INSTALL path. - console.debug( - 'GitNexus: FTS LOAD from cache failed, will attempt INSTALL:', - err?.message || '', - ); + await targetConn!.query('LOAD EXTENSION fts'); + return markLoaded(); + } catch { + // Fall back to install + load (requires network) try { - await conn.query('INSTALL fts'); - await conn.query('LOAD EXTENSION fts'); - ftsLoaded = true; + await targetConn!.query('INSTALL fts'); + await targetConn!.query('LOAD EXTENSION fts'); + return markLoaded(); } catch (err: any) { const msg = err?.message || ''; if ( @@ -1174,10 +1186,10 @@ export const loadFTSExtension = async (): Promise => { msg.includes('already installed') || msg.includes('already exists') ) { - ftsLoaded = true; - } else { - console.error('GitNexus: FTS extension load failed:', msg); + return markLoaded(); } + console.error('GitNexus: FTS extension load failed:', msg); + return false; } } }; diff --git a/gitnexus/src/core/lbug/pool-adapter.ts b/gitnexus/src/core/lbug/pool-adapter.ts index 85026ff1e..90f3f1f11 100644 --- a/gitnexus/src/core/lbug/pool-adapter.ts +++ b/gitnexus/src/core/lbug/pool-adapter.ts @@ -17,6 +17,7 @@ import fs from 'fs/promises'; import lbug from '@ladybugdb/core'; +import { loadFTSExtension } from './lbug-adapter.js'; /** Per-repo pool: one Database, many Connections */ interface PoolEntry { @@ -354,19 +355,7 @@ async function doInitLbug(repoId: string, dbPath: string): Promise { // Done BEFORE pool registration so no concurrent checkout can grab // the connection while the async FTS load is in progress. if (!shared.ftsLoaded) { - try { - await available[0].query('LOAD EXTENSION fts'); - shared.ftsLoaded = true; - } catch { - // Extension not cached locally — try INSTALL (downloads from remote) then LOAD - try { - await available[0].query('INSTALL fts'); - await available[0].query('LOAD EXTENSION fts'); - shared.ftsLoaded = true; - } catch { - // FTS unavailable — queries will fail gracefully - } - } + shared.ftsLoaded = await loadFTSExtension(available[0]); } // Load VECTOR extension once per shared Database for semantic search support. @@ -440,19 +429,7 @@ export async function initLbugWithDb( // Load FTS extension if not already loaded on this Database if (!shared.ftsLoaded) { - try { - await available[0].query('LOAD EXTENSION fts'); - shared.ftsLoaded = true; - } catch { - // Extension not cached locally — try INSTALL (downloads from remote) then LOAD - try { - await available[0].query('INSTALL fts'); - await available[0].query('LOAD EXTENSION fts'); - shared.ftsLoaded = true; - } catch { - // FTS unavailable — queries will fail gracefully - } - } + shared.ftsLoaded = await loadFTSExtension(available[0]); } // Load VECTOR extension for semantic search support