| 2428 | } cypher_edge_thread_ctx_t; |
| 2429 | |
| 2430 | static void *cypher_edge_props_concurrently(void *opaque) { |
| 2431 | cypher_edge_thread_ctx_t *ctx = opaque; |
| 2432 | cbm_store_t *store = setup_cypher_http_store(); |
| 2433 | if (!store) { |
| 2434 | return NULL; |
| 2435 | } |
| 2436 | |
| 2437 | /* Keep projection busy after the store scan has completed. A single-edge |
| 2438 | * query can be incidentally ordered by SQLite's internal mutexes, masking |
| 2439 | * the independent Cypher scratch-buffer race from TSan. */ |
| 2440 | cbm_node_t source = {.project = "test", |
| 2441 | .label = "Function", |
| 2442 | .name = "HandleOrder", |
| 2443 | .qualified_name = "test.main.HandleOrder", |
| 2444 | .file_path = "main.go", |
| 2445 | .start_line = 10, |
| 2446 | .end_line = 30}; |
| 2447 | int64_t source_id = cbm_store_upsert_node(store, &source); |
| 2448 | for (int i = 0; i < 256; i++) { |
| 2449 | char name[64]; |
| 2450 | char qualified_name[96]; |
| 2451 | snprintf(name, sizeof(name), "ConcurrentTarget%d", i); |
| 2452 | snprintf(qualified_name, sizeof(qualified_name), "test.concurrent.%s", name); |
| 2453 | cbm_node_t target = {.project = "test", |
| 2454 | .label = "Function", |
| 2455 | .name = name, |
| 2456 | .qualified_name = qualified_name, |
| 2457 | .file_path = "concurrent.go"}; |
| 2458 | int64_t target_id = cbm_store_upsert_node(store, &target); |
| 2459 | cbm_edge_t edge = { |
| 2460 | .project = "test", |
| 2461 | .source_id = source_id, |
| 2462 | .target_id = target_id, |
| 2463 | .type = "HTTP_CALLS", |
| 2464 | .properties_json = |
| 2465 | "{\"url_path\":\"/api/orders\",\"confidence\":0.85,\"method\":\"POST\"}"}; |
| 2466 | if (source_id < 0 || target_id < 0 || cbm_store_insert_edge(store, &edge) < 0) { |
| 2467 | cbm_store_close(store); |
| 2468 | return NULL; |
| 2469 | } |
| 2470 | } |
| 2471 | |
| 2472 | atomic_fetch_add_explicit(ctx->ready, 1, memory_order_release); |
| 2473 | while (atomic_load_explicit(ctx->start, memory_order_acquire) == 0) { |
| 2474 | cbm_usleep(1000); |
| 2475 | } |
| 2476 | ctx->succeeded = true; |
| 2477 | for (int i = 0; i < 128; i++) { |
| 2478 | cbm_cypher_result_t result = {0}; |
| 2479 | int rc = cbm_cypher_execute(store, |
| 2480 | "MATCH (a:Function)-[r:HTTP_CALLS]->(b:Function) " |
| 2481 | "RETURN r.url_path, r.confidence, r.method", |
| 2482 | "test", 0, &result); |
| 2483 | if (rc != 0 || result.row_count != 257 || |
| 2484 | strcmp(cypher_get_col(&result, 0, "r.url_path"), "/api/orders") != 0 || |
| 2485 | strcmp(cypher_get_col(&result, 0, "r.confidence"), "0.85") != 0 || |
| 2486 | strcmp(cypher_get_col(&result, 0, "r.method"), "POST") != 0) { |
| 2487 | ctx->succeeded = false; |
nothing calls this directly
no test coverage detected