gitnexus 1.6.10-rc.61 → 1.6.10-rc.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -61,6 +61,16 @@ export declare function resolveNativeSafeStorageDir(storagePath: string, subdir:
|
|
|
61
61
|
*/
|
|
62
62
|
export declare const LBUG_MAX_DB_SIZE: number;
|
|
63
63
|
export declare const parseWalCheckpointThreshold: (raw: string | undefined) => number | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Size the buffer pool to an estimated graph size (node + relationship count),
|
|
66
|
+
* clamped to [ADAPTIVE_POOL_FLOOR, defaultBufferPoolSize()]. The estimate can
|
|
67
|
+
* only *shrink* the pool from the default — never above the 2 GiB / 80%-RAM cap,
|
|
68
|
+
* never below the COPY-safety floor — so no repo is under-sized or gets more
|
|
69
|
+
* than the default it would have today.
|
|
70
|
+
*/
|
|
71
|
+
export declare const estimateBufferPool: (graphElementCount: number) => number;
|
|
72
|
+
/** Set (bytes) or clear (`undefined`) the per-run buffer-pool size hint. */
|
|
73
|
+
export declare const setBufferPoolSizeHint: (bytes: number | undefined) => void;
|
|
64
74
|
export declare const WAL_RECOVERY_SUGGESTION = "WAL corruption detected. Run `gitnexus analyze --force` to rebuild the index.";
|
|
65
75
|
export declare function isWalCorruptionError(err: unknown): boolean;
|
|
66
76
|
/**
|
|
@@ -307,6 +307,15 @@ const resolveCheckpointThreshold = () => {
|
|
|
307
307
|
*/
|
|
308
308
|
const DEFAULT_BUFFER_POOL_CAP = 2 * 1024 * 1024 * 1024;
|
|
309
309
|
const BUFFER_POOL_FLOOR = 64 * 1024 * 1024;
|
|
310
|
+
// COPY-safety floor for the adaptive hint (below). LadybugDB's bulk COPY needs
|
|
311
|
+
// working buffer-pool memory that scales with the repo: a 64 MiB pool fails
|
|
312
|
+
// ("buffer pool is full and no memory could be freed") on any non-trivial repo,
|
|
313
|
+
// and even the ~1800-file GitNexus checkout needs ≥256 MiB. So the adaptive
|
|
314
|
+
// size never drops a repo below this — a distinct, higher floor than
|
|
315
|
+
// BUFFER_POOL_FLOOR, which only guards defaultBufferPoolSize on tiny-RAM
|
|
316
|
+
// machines. It is still clamped up to defaultBufferPoolSize, so a machine whose
|
|
317
|
+
// default is below this floor keeps its default rather than over-committing.
|
|
318
|
+
const ADAPTIVE_POOL_FLOOR = 256 * 1024 * 1024;
|
|
310
319
|
const parseBufferPoolSize = (raw) => {
|
|
311
320
|
if (raw === undefined)
|
|
312
321
|
return undefined;
|
|
@@ -319,17 +328,66 @@ const parseBufferPoolSize = (raw) => {
|
|
|
319
328
|
return Math.floor(parsed);
|
|
320
329
|
};
|
|
321
330
|
const defaultBufferPoolSize = () => Math.min(DEFAULT_BUFFER_POOL_CAP, Math.max(BUFFER_POOL_FLOOR, Math.floor(os.totalmem() * 0.8)));
|
|
331
|
+
/**
|
|
332
|
+
* Clamp an adaptive pool request to [ADAPTIVE_POOL_FLOOR, default]. The lower
|
|
333
|
+
* bound keeps LadybugDB's COPY viable; the upper bound (defaultBufferPoolSize)
|
|
334
|
+
* means the hint can only shrink the pool from today's default and can never
|
|
335
|
+
* exceed the 2 GiB / 80%-RAM cap — and on a machine whose default is below the
|
|
336
|
+
* COPY floor, the default wins, so the pool is never over-committed.
|
|
337
|
+
*/
|
|
338
|
+
const clampBufferPool = (bytes) => Math.min(defaultBufferPoolSize(), Math.max(ADAPTIVE_POOL_FLOOR, Math.floor(bytes)));
|
|
339
|
+
/**
|
|
340
|
+
* Buffer-pool bytes to provision per graph element (node + relationship).
|
|
341
|
+
*
|
|
342
|
+
* The fixed 2 GiB default is far larger than most repos' working set, and
|
|
343
|
+
* LadybugDB eagerly commits the pool at DB open — measured: a full
|
|
344
|
+
* `analyze --force` of the GitNexus checkout takes ~51 s with the 2 GiB pool
|
|
345
|
+
* vs ~35 s with the ~414 MiB this factor yields (31% faster; the oversized
|
|
346
|
+
* pool's commit dominates). The pool is a page cache over the on-disk index,
|
|
347
|
+
* which scales with node/edge count, so a per-element budget sizes it to the
|
|
348
|
+
* repo. Kept generous so the whole index stays resident (no COPY thrash) and
|
|
349
|
+
* always clamped to at least ADAPTIVE_POOL_FLOOR; tuned by timing a real
|
|
350
|
+
* large-repo `analyze --force` at this factor vs a forced 2 GiB pool (the pool
|
|
351
|
+
* is a native eager allocation, measured with a real analyze, not a build-free
|
|
352
|
+
* bench — see the emit-path COPY timing note in bench/emit-persistence).
|
|
353
|
+
*/
|
|
354
|
+
const POOL_BYTES_PER_ELEMENT = 4 * 1024;
|
|
355
|
+
/**
|
|
356
|
+
* Size the buffer pool to an estimated graph size (node + relationship count),
|
|
357
|
+
* clamped to [ADAPTIVE_POOL_FLOOR, defaultBufferPoolSize()]. The estimate can
|
|
358
|
+
* only *shrink* the pool from the default — never above the 2 GiB / 80%-RAM cap,
|
|
359
|
+
* never below the COPY-safety floor — so no repo is under-sized or gets more
|
|
360
|
+
* than the default it would have today.
|
|
361
|
+
*/
|
|
362
|
+
export const estimateBufferPool = (graphElementCount) => clampBufferPool(graphElementCount * POOL_BYTES_PER_ELEMENT);
|
|
363
|
+
/**
|
|
364
|
+
* Optional per-run buffer-pool size hint (bytes). The analyze orchestrator sets
|
|
365
|
+
* it once the graph size is known (after the pipeline, before the DB open) so
|
|
366
|
+
* the pool is sized to the repo instead of the fixed 2 GiB default, and clears
|
|
367
|
+
* it at run end. Non-analyze opens (MCP serve, `native-check` `:memory:`) never
|
|
368
|
+
* set it and keep the default.
|
|
369
|
+
*/
|
|
370
|
+
let bufferPoolSizeHint;
|
|
371
|
+
/** Set (bytes) or clear (`undefined`) the per-run buffer-pool size hint. */
|
|
372
|
+
export const setBufferPoolSizeHint = (bytes) => {
|
|
373
|
+
bufferPoolSizeHint = bytes;
|
|
374
|
+
};
|
|
322
375
|
/**
|
|
323
376
|
* Resolve the `bufferManagerSize` passed to every `new lbug.Database(...)`.
|
|
324
|
-
* `GITNEXUS_LBUG_BUFFER_POOL_SIZE` (bytes) overrides
|
|
377
|
+
* `GITNEXUS_LBUG_BUFFER_POOL_SIZE` (bytes) overrides everything; `0` is a
|
|
325
378
|
* deliberate escape hatch that restores LadybugDB's native unbounded
|
|
326
|
-
* 80%-of-RAM default.
|
|
327
|
-
*
|
|
379
|
+
* 80%-of-RAM default. With no env override, a per-run `setBufferPoolSizeHint`
|
|
380
|
+
* (clamped to [floor, default]) sizes the pool to the repo; otherwise the
|
|
381
|
+
* default. Resolved at call time (not module load) so tests can stub the env
|
|
382
|
+
* var, the hint, and `os.totalmem`.
|
|
328
383
|
*/
|
|
329
384
|
const resolveBufferManagerSize = () => {
|
|
330
385
|
const raw = process.env.GITNEXUS_LBUG_BUFFER_POOL_SIZE;
|
|
331
|
-
if (raw === undefined)
|
|
332
|
-
return
|
|
386
|
+
if (raw === undefined) {
|
|
387
|
+
return bufferPoolSizeHint !== undefined
|
|
388
|
+
? clampBufferPool(bufferPoolSizeHint)
|
|
389
|
+
: defaultBufferPoolSize();
|
|
390
|
+
}
|
|
333
391
|
const parsed = parseBufferPoolSize(raw);
|
|
334
392
|
if (parsed !== undefined)
|
|
335
393
|
return parsed;
|
package/dist/core/run-analyze.js
CHANGED
|
@@ -13,6 +13,7 @@ import fs from 'fs/promises';
|
|
|
13
13
|
import { runPipelineFromRepo } from './ingestion/pipeline.js';
|
|
14
14
|
import { resetDegradedParseCounter } from './tree-sitter/safe-parse.js';
|
|
15
15
|
import { initLbug, loadGraphToLbug, getLbugStats, executeQuery, executeWithReusedStatement, closeLbug, closeLbugBeforeExit, loadCachedEmbeddings, deleteNodesForFiles, deleteAllCommunitiesAndProcesses, deleteAllInterprocTaintPaths, deleteAllCallSummaries, deleteAllInjects, queryImportersBatch, loadFTSExtension, wipeLbugDbFiles, LbugWipeError, DELETE_FILES_CHUNK_SIZE, } from './lbug/lbug-adapter.js';
|
|
16
|
+
import { estimateBufferPool, setBufferPoolSizeHint } from './lbug/lbug-config.js';
|
|
16
17
|
import { escapeCypherString } from './lbug/cypher-escape.js';
|
|
17
18
|
import { buildSearchIndexesOrDegrade, createSearchFTSIndexes, initialiseSearchFTSStemmer, verifySearchFTSIndexes, } from './search/fts-indexes.js';
|
|
18
19
|
import { cjkSegmentationModeMismatch, getSearchFTSCjkSegmentation, initialiseSearchFTSCjkSegmentation, } from './search/cjk-segmentation.js';
|
|
@@ -312,6 +313,10 @@ export async function runFullAnalysis(repoPath, options, callbacks, runnerIdenti
|
|
|
312
313
|
// (parse-cache, parsedfile-store) and the kuzu-migration cleanup live there
|
|
313
314
|
// and are shared across branches (#2106 KTD7).
|
|
314
315
|
const { storagePath } = getStoragePaths(repoPath);
|
|
316
|
+
// Start each analyze with a clean buffer-pool hint: any pre-pipeline DB open
|
|
317
|
+
// (e.g. the embeddings-cache open) falls back to the default until the hint is
|
|
318
|
+
// set from the built graph below, so a prior run's size can't leak in.
|
|
319
|
+
setBufferPoolSizeHint(undefined);
|
|
315
320
|
// Clean up stale KuzuDB files from before the LadybugDB migration.
|
|
316
321
|
const kuzuResult = await cleanupOldKuzuFiles(storagePath);
|
|
317
322
|
if (kuzuResult.found && kuzuResult.needsReindex) {
|
|
@@ -944,6 +949,13 @@ export async function runFullAnalysis(repoPath, options, callbacks, runnerIdenti
|
|
|
944
949
|
// a still-populated DB this run believes it wiped.
|
|
945
950
|
await wipeLbugDbFiles(lbugPath);
|
|
946
951
|
}
|
|
952
|
+
// Size the buffer pool to the graph just built by the pipeline (a page cache
|
|
953
|
+
// over the on-disk index, which scales with node/edge count) instead of the
|
|
954
|
+
// fixed 2 GiB default, whose eager commit dominates large-repo analyze. The
|
|
955
|
+
// size is clamped to [COPY-safety floor, default], so it only ever shrinks
|
|
956
|
+
// the pool; env override / no-hint paths are unchanged. See
|
|
957
|
+
// resolveBufferManagerSize / estimateBufferPool.
|
|
958
|
+
setBufferPoolSizeHint(estimateBufferPool(pipelineResult.graph.nodeCount + pipelineResult.graph.relationshipCount));
|
|
947
959
|
await initLbug(lbugPath);
|
|
948
960
|
// Manual WAL checkpoint driver (#1741): periodically drain the WAL
|
|
949
961
|
// from JS so the un-retriable native auto-checkpoint almost never
|
package/package.json
CHANGED