File-backed query stores are request-scoped. Keeping one open between MCP * calls pins an old database generation after another process atomically * replaces the project DB. On Windows it can also prevent that replacement * entirely. Embedded/in-memory stores have no path and retain their existing * process lifetime. */
| 11414 | * entirely. Embedded/in-memory stores have no path and retain their existing |
| 11415 | * process lifetime. */ |
| 11416 | static void release_request_store(cbm_mcp_server_t *srv) { |
| 11417 | if (!srv || !srv->owns_store || !srv->store || !cbm_store_db_path(srv->store)) { |
| 11418 | return; |
| 11419 | } |
| 11420 | cbm_store_close(srv->store); |
| 11421 | srv->store = NULL; |
| 11422 | free(srv->current_project); |
| 11423 | srv->current_project = NULL; |
| 11424 | /* The close above frees a connection's worth of page cache. Ask the |
| 11425 | * allocator to hand those pages back now, which keeps a long-lived daemon |
| 11426 | * flat across thousands of request-scoped stores (#581). This only became |
| 11427 | * meaningful once the Windows interposer made the pages mimalloc's: an |
| 11428 | * earlier attempt aimed at the CRT heap instead and could not release |
| 11429 | * them. POSIX already purges on free, so this is a no-op there. */ |
| 11430 | cbm_mem_collect(); |
| 11431 | } |
| 11432 | |
| 11433 | char *cbm_mcp_handle_tool(cbm_mcp_server_t *srv, const char *tool_name, const char *args_json) { |
| 11434 | /* Phase marks bracket the WHOLE request with no unlabelled gap, so growth |
no test coverage detected