mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-10-27 06:53:11 +08:00
cbm_service_pattern_match runs once per resolved CALL edge inside
emit_service_edge — that's 7 pattern lists × ~30 patterns × strstr
= ~210 strstrs per call. On kubernetes (~600k resolved CALL edges)
the SAME resolved QN ("fmt.Errorf", "context.Context.Done",
"errors.New", etc) repeats thousands of times across files. Caching
turns the linear pattern-list scan into one hash lookup after the
first miss.
API additions in service_patterns.h:
void cbm_service_pattern_cache_begin(void);
void cbm_service_pattern_cache_end(void);
Cache is TLS (no contention) scoped to the resolve_worker's lifetime
in the parallel_resolve phase. Capacity 8192 entries per worker —
covers typical project QN diversity without rehashing.
Encoding: enum value + 1 in the void* slot (0/NULL means "miss").
Two helpers svc_enum_to_ptr / svc_ptr_to_enum hide the trick.
Benchmark on kubernetes (12 workers, 20,650 files):
- parallel_resolve wall: 98,520 -> 90,104 ms (-8.5% vs Chunk 1
baseline, -12.8% vs original 103,281 baseline)
- resolve_calls CPU: 992,427 -> 885,663 ms (-10.8% vs Chunk 1,
-5.4% vs original — Chunk 1 added overhead that Chunk 2 recovers
AND surpasses)
- resolve_usages CPU: 11,977 -> 10,944 ms (-8.6%)
- total_loop CPU: 1,005,409 -> 897,561 ms (-10.7%)
- Tests: 3616/0
- Graph: 297,082 -> 297,080 nodes (-2), 1,153,482 -> 1,156,097 edges
(within 0.2%, semantic-preserving)
- zod/serilog sanity: edges within +/-3 of baseline
- Peak RSS: 7.46 -> 7.75 GB (+290 MB for 12 × 8192-entry caches)
Cumulative trajectory: original broken state ~35 min K8s ->
1.92 min wall (-49× total). The per-file is_import_reachable cache
(Chunk 1) + the per-worker service-pattern cache (Chunk 2) together
save ~13s of resolve wall time. Next chunks target the gbuf_insert_
edge hot path and remaining strstr scans.
59 lines
2.7 KiB
C
59 lines
2.7 KiB
C
/*
|
||
* service_patterns.h — Allowlists for HTTP clients, async dispatch, and config accessors.
|
||
*
|
||
* Used during call resolution to classify CALLS edges as:
|
||
* HTTP_CALLS — synchronous HTTP client calls
|
||
* ASYNC_CALLS — async message/task dispatch
|
||
* CONFIGURES — config/env access
|
||
*
|
||
* Lookup is O(1) via hash table initialized once at startup.
|
||
*/
|
||
#ifndef CBM_SERVICE_PATTERNS_H
|
||
#define CBM_SERVICE_PATTERNS_H
|
||
|
||
/* Edge type returned by pattern match. */
|
||
typedef enum {
|
||
CBM_SVC_NONE = 0, /* Not a service pattern — use normal CALLS */
|
||
CBM_SVC_HTTP = 1, /* Synchronous HTTP client call */
|
||
CBM_SVC_ASYNC = 2, /* Async dispatch (message broker, task queue) */
|
||
CBM_SVC_CONFIG = 3, /* Config/env accessor */
|
||
CBM_SVC_ROUTE_REG = 4, /* Route registration (router.GET, app.get, Route::post) */
|
||
CBM_SVC_GRPC = 5, /* gRPC client call (protobuf stub invocation) */
|
||
CBM_SVC_GRAPHQL = 6, /* GraphQL client query/mutation */
|
||
CBM_SVC_TRPC = 7, /* tRPC client procedure call */
|
||
} cbm_svc_kind_t;
|
||
|
||
/* Initialize the pattern lookup tables. Call once at startup. Thread-safe after init. */
|
||
void cbm_service_patterns_init(void);
|
||
|
||
/* Check if a resolved QN contains a known service library identifier.
|
||
* Returns the pattern kind, or CBM_SVC_NONE if no match.
|
||
* Matches on library name substrings in the QN (e.g., "requests" in
|
||
* "project.venv.requests.api.get"). Import-alias transparent. */
|
||
cbm_svc_kind_t cbm_service_pattern_match(const char *resolved_qn);
|
||
|
||
/* Per-worker TLS cache for cbm_service_pattern_match results. The
|
||
* pattern matcher runs once per resolved CALL edge in emit_service_
|
||
* edge — that's 6 pattern lists × ~30 patterns × strstr per call ≈
|
||
* ~180 strstrs per call. The same resolved QN repeats across most of
|
||
* the call edges in a project (e.g. "fmt.Errorf"), so caching turns
|
||
* a linear pattern-list scan into one hash lookup. Call _begin once
|
||
* per worker thread before the resolve loop and _end at the end. */
|
||
void cbm_service_pattern_cache_begin(void);
|
||
void cbm_service_pattern_cache_end(void);
|
||
|
||
/* Get the HTTP method from the callee name suffix (e.g., ".get" → "GET").
|
||
* Returns NULL if method cannot be inferred. */
|
||
const char *cbm_service_pattern_http_method(const char *callee_name);
|
||
|
||
/* Get the HTTP method from a route registration callee name suffix
|
||
* (e.g., "router.GET" → "GET", "app.post" → "POST").
|
||
* Returns NULL if not a known route registration method. */
|
||
const char *cbm_service_pattern_route_method(const char *callee_name);
|
||
|
||
/* Get the broker name for an async QN (e.g., "pubsub" from a Pub/Sub QN).
|
||
* Returns NULL if not an async pattern. */
|
||
const char *cbm_service_pattern_broker(const char *resolved_qn);
|
||
|
||
#endif /* CBM_SERVICE_PATTERNS_H */
|