Skip to content

refactor(structure): share chunk-size statement cache with builder helpers#1951

Closed
carlos-alm wants to merge 1 commit into
fix/issue-1765-incremental-rebuild-missing-same-class-barefrom
fix/issue-1767-consider-adopting-chunk-size-statement-cache
Closed

refactor(structure): share chunk-size statement cache with builder helpers#1951
carlos-alm wants to merge 1 commit into
fix/issue-1765-incremental-rebuild-missing-same-class-barefrom
fix/issue-1767-consider-adopting-chunk-size-statement-cache

Conversation

@carlos-alm

Copy link
Copy Markdown
Contributor

Fixes #1767

batchUpdateRoles in src/features/structure.ts duplicated the WeakMap<db, Map<chunkSize, stmt>> cache-getter shape already extracted as getOrCreateBatchStmt in src/domain/graph/builder/helpers.ts during a prior Titan grind pass.

Since features/ is a different domain than domain/graph/builder/, this extracts the generic helper into src/db/repository/cached-stmt.ts as cachedChunkStmt — a natural sibling of the existing single-statement cachedStmt helper already used across db/, domain/analysis/, etc. Both builder/helpers.ts and features/structure.ts now depend on this lower-level db/ module instead of crossing feature/domain boundaries directly. A matching ChunkStmtCache<TRow> type was added next to StmtCache<TRow> in types.ts.

As a side effect, the role statement cache in batchUpdateRoles is now module-scoped and keyed per-db (previously a fresh Map was allocated on every call), matching the semantics of the node/edge/export batch caches — repeated classifyNodeRoles calls against the same long-lived db connection (watch mode, MCP server) now reuse compiled statements instead of recompiling them every time.

No Rust changes: the native engine's role classification (crates/codegraph-core/src/graph/classifiers/roles.rs) already uses rusqlite's built-in prepare_cached, so this duplicate-cache pattern only existed on the TypeScript side.

Validation

  • npx vitest run tests/unit/roles.test.ts — added two regression tests covering (1) a single role spanning multiple statement chunk sizes (500 + remainder), and (2) cache isolation across two separate db instances — all 22 tests pass
  • npm test — full suite: 215 files / 3562 tests passed
  • npm run lint — clean
  • npm run build — clean (tsc)
  • codegraph diff-impact --staged -T — blast radius confined to the 6 changed statement-cache/role-classification functions, 21 transitive callers across 5 files
  • codegraph check --cycles — no cycles introduced

…lpers

batchUpdateRoles in features/structure.ts duplicated the WeakMap<db,
Map<chunkSize, stmt>> cache-getter shape already extracted as
getOrCreateBatchStmt in domain/graph/builder/helpers.ts. Extract the
generic helper as cachedChunkStmt in db/repository/cached-stmt.ts
(alongside the existing single-statement cachedStmt) and have both
builder/helpers.ts and features/structure.ts depend on it, avoiding an
awkward features/ -> domain/graph/builder/ dependency direction.

As a side effect, the role statement cache is now module-scoped and
keyed per-db like the node/edge/export caches, so repeated
classifyNodeRoles calls against the same long-lived db connection
(watch mode, MCP server) reuse compiled statements instead of
recompiling them on every call.

Impact: 6 functions changed, 21 affected
@greptile-apps

greptile-apps Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR extracts the WeakMap<db, Map<chunkSize, stmt>> cache pattern—previously duplicated in builder/helpers.ts and features/structure.ts—into a shared cachedChunkStmt helper in src/db/repository/cached-stmt.ts. It also fixes a real performance regression by promoting roleStmtCache in batchUpdateRoles from a function-scoped Map (freshly allocated on every call) to a module-scoped WeakMap, so watch-mode and MCP-server workloads reuse compiled statements across repeated classifyNodeRoles invocations.

  • New cachedChunkStmt/ChunkStmtCache — generic helper and type added to db/repository; exported through the barrel and consumed by both builder/helpers.ts and features/structure.ts.
  • batchUpdateRoles cache fixroleStmtCache is now module-scoped; the old per-call new Map<number, stmt>() that caused recompilation on every invocation is removed.
  • Two new regression tests — covering a 650-node batch that spans both a full (500) and a remainder (150) chunk, and cache isolation across two independent in-memory databases.

Confidence Score: 5/5

Safe to merge — focused extraction of a duplicated pattern with no new logic and a real statement-reuse bug fixed.

The refactoring is mechanical: cachedChunkStmt is a verbatim lift of getOrCreateBatchStmt, all callers are updated consistently, and the only behavioral change (module-scoped roleStmtCache) is the intended fix backed by two new regression tests. No existing logic paths are altered.

Both structure.ts and builder/helpers.ts import cachedChunkStmt directly from the implementation file rather than through the db barrel — a minor style inconsistency worth tidying up.

Important Files Changed

Filename Overview
src/db/repository/cached-stmt.ts Adds cachedChunkStmt: a clean generic helper for db+chunk-size keyed statement caching. Logic is correct; WeakMap ensures GC safety when db objects are released.
src/db/repository/index.ts Adds cachedChunkStmt to the barrel export alongside cachedStmt. Trivial, correct.
src/domain/graph/builder/helpers.ts Removes local getOrCreateBatchStmt and replaces it with cachedChunkStmt; cache declarations simplified to typed WeakMap. No behavioral change for node/edge/export caches.
src/features/structure.ts Promotes roleStmtCache to module scope and delegates to cachedChunkStmt. Fixes the per-call recompilation bug; direct import from cached-stmt.ts rather than the db barrel is a minor style inconsistency.
src/types.ts Adds ChunkStmtCache type as a natural sibling of StmtCache. Well-documented and correctly typed.
tests/unit/roles.test.ts Adds two targeted regression tests: cross-chunk-boundary batch writes (500+150) and per-db cache isolation. Both directly validate the behavioral fix.

Fix All in Claude Code

Reviews (1): Last reviewed commit: "refactor(structure): share chunk-size st..." | Re-trigger Greptile

Comment thread src/features/structure.ts
Comment on lines 2 to +3
import { getBuildMeta, getNodeId, setBuildMeta, testFilterSQL } from '../db/index.js';
import { cachedChunkStmt } from '../db/repository/cached-stmt.js';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Both structure.ts and builder/helpers.ts already import other symbols from the db barrel (../db/index.js), which now re-exports cachedChunkStmt. Adding a second import line that reaches into the implementation file directly (../db/repository/cached-stmt.js) creates two entry-points for the same module and diverges from the pattern used for every other db/ symbol in this file.

Suggested change
import { getBuildMeta, getNodeId, setBuildMeta, testFilterSQL } from '../db/index.js';
import { cachedChunkStmt } from '../db/repository/cached-stmt.js';
import { cachedChunkStmt, getBuildMeta, getNodeId, setBuildMeta, testFilterSQL } from '../db/index.js';

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

Comment on lines 9 to +10
import { purgeFilesData } from '../../../db/index.js';
import { cachedChunkStmt } from '../../../db/repository/cached-stmt.js';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 cachedChunkStmt is now re-exported from the db barrel (db/index.js), which this file already imports for purgeFilesData. Keeping the direct sub-path import (db/repository/cached-stmt.js) as a separate line is inconsistent with how every other db/ helper is consumed here.

Suggested change
import { purgeFilesData } from '../../../db/index.js';
import { cachedChunkStmt } from '../../../db/repository/cached-stmt.js';
import { cachedChunkStmt, purgeFilesData } from '../../../db/index.js';

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Codegraph Impact Analysis

6 functions changed26 callers affected across 5 files

  • cachedChunkStmt in src/db/repository/cached-stmt.ts:35 (20 transitive callers)
  • getNodeStmt in src/domain/graph/builder/helpers.ts:362 (15 transitive callers)
  • getEdgeStmt in src/domain/graph/builder/helpers.ts:372 (17 transitive callers)
  • getExportStmt in src/domain/graph/builder/helpers.ts:430 (15 transitive callers)
  • getRoleStmt in src/features/structure.ts:540 (4 transitive callers)
  • batchUpdateRoles in src/features/structure.ts:552 (3 transitive callers)

@carlos-alm

Copy link
Copy Markdown
Contributor Author

Closing — this duplicates already in-progress work on #1890 for the same issue (#1767). Continuing the existing stacked chain (#1885#1939) instead of a competing branch.

@carlos-alm carlos-alm closed this Jul 7, 2026
@carlos-alm carlos-alm deleted the fix/issue-1767-consider-adopting-chunk-size-statement-cache branch July 7, 2026 08:20
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 7, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant