lint-memory-core failed on #2642: the new search_code scanner, result index, root containment cache and Cypher sort/group/distinct scratch used malloc/calloc/realloc/free directly (mcp.c +22, cypher.c +26, git_context.c +1). They now go through cbm_alloc/cbm_calloc/cbm_realloc/cbm_free/cbm_mem_strdup: file buffers as CBM_MEM_CLASS_EXTRACT, the rest as CBM_MEM_CLASS_OTHER, each block freed with the class it was allocated with. The result index reserves its slot before a result's strings exist, so its insert cannot fail and needs no cleanup; cbm_git_branch_resolve writes into caller buffers instead of returning heap strings. cypher.c ends below its baseline (128 < 132), which is tightened. Output unchanged: 42/42 tool and Cypher responses identical on django; mcp, cypher and git_context suites green under ASan.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
search_code
- Scan the indexed files in process instead of through grep (POSIX) or a
PowerShell Select-String pipeline (Windows), with the same grep -f
semantics: one pattern per line, ERE regex, binary-file and NUL handling,
-Hn records. The subprocess runner stays for the unindexed recursive
fallback and a Windows file_pattern it cannot prefilter.
- Windows now matches like macOS and Linux: Select-String matched
case-insensitively, used .NET regex syntax and read NUL-containing
files as text. A trailing CR is still ignored there, so `foo$` keeps
matching CRLF checkouts.
- Result merge, root containment and source reads no longer scale with
hits x results: a node-id index, one canonical root per request with a
per-file verdict cache, and fread spans instead of per-byte fgetc.
query_graph
- ORDER BY (RETURN and WITH) was a bubble sort. A stable merge sort keeps
the same comparisons and so the same order; WITH keys are resolved once
per row instead of twice per comparison.
- GROUP BY, DISTINCT (RETURN and WITH) and COUNT(DISTINCT) looked every
row up in a linear list. They hash the same keys now.
Store reads
- Read tools run their statements in one deferred read transaction,
renewed every 100 ms, instead of taking the database file lock once per
statement.
list_projects
- Resolve only the branch the listing prints: 2 git processes per project
instead of 7.
On macOS and Linux every response is byte-identical to before:
search_code 30/30 (django), 28/28 (this repo) and 28/28 (Linux, GNU
grep); all tools and the Cypher cases 86/86 on shared django and redis
indexes. On django: search_code 908 -> 355 ms, WITH ... ORDER BY
41 s -> 62 ms, count(*) 508 -> 184 ms, list_projects 94 -> 40 ms. On the
Windows ARM VM: search_code 1.6-3.4 s -> 0.2-0.5 s.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>