| 2109 | } cypher_edge_thread_ctx_t; |
| 2110 | |
| 2111 | static void *cypher_edge_props_concurrently(void *opaque) { |
| 2112 | cypher_edge_thread_ctx_t *ctx = opaque; |
| 2113 | cbm_store_t *store = setup_cypher_http_store(); |
| 2114 | if (!store) { |
| 2115 | return NULL; |
| 2116 | } |
| 2117 | |
| 2118 | /* Keep projection busy after the store scan has completed. A single-edge |
| 2119 | * query can be incidentally ordered by SQLite's internal mutexes, masking |
| 2120 | * the independent Cypher scratch-buffer race from TSan. */ |
| 2121 | cbm_node_t source = {.project = "test", |
| 2122 | .label = "Function", |
| 2123 | .name = "HandleOrder", |
| 2124 | .qualified_name = "test.main.HandleOrder", |
| 2125 | .file_path = "main.go", |
| 2126 | .start_line = 10, |
| 2127 | .end_line = 30}; |
| 2128 | int64_t source_id = cbm_store_upsert_node(store, &source); |
| 2129 | for (int i = 0; i < 256; i++) { |
| 2130 | char name[64]; |
| 2131 | char qualified_name[96]; |
| 2132 | snprintf(name, sizeof(name), "ConcurrentTarget%d", i); |
| 2133 | snprintf(qualified_name, sizeof(qualified_name), "test.concurrent.%s", name); |
| 2134 | cbm_node_t target = {.project = "test", |
| 2135 | .label = "Function", |
| 2136 | .name = name, |
| 2137 | .qualified_name = qualified_name, |
| 2138 | .file_path = "concurrent.go"}; |
| 2139 | int64_t target_id = cbm_store_upsert_node(store, &target); |
| 2140 | cbm_edge_t edge = { |
| 2141 | .project = "test", |
| 2142 | .source_id = source_id, |
| 2143 | .target_id = target_id, |
| 2144 | .type = "HTTP_CALLS", |
| 2145 | .properties_json = |
| 2146 | "{\"url_path\":\"/api/orders\",\"confidence\":0.85,\"method\":\"POST\"}"}; |
| 2147 | if (source_id < 0 || target_id < 0 || cbm_store_insert_edge(store, &edge) < 0) { |
| 2148 | cbm_store_close(store); |
| 2149 | return NULL; |
| 2150 | } |
| 2151 | } |
| 2152 | |
| 2153 | atomic_fetch_add_explicit(ctx->ready, 1, memory_order_release); |
| 2154 | while (atomic_load_explicit(ctx->start, memory_order_acquire) == 0) { |
| 2155 | cbm_usleep(1000); |
| 2156 | } |
| 2157 | ctx->succeeded = true; |
| 2158 | for (int i = 0; i < 128; i++) { |
| 2159 | cbm_cypher_result_t result = {0}; |
| 2160 | int rc = cbm_cypher_execute(store, |
| 2161 | "MATCH (a:Function)-[r:HTTP_CALLS]->(b:Function) " |
| 2162 | "RETURN r.url_path, r.confidence, r.method", |
| 2163 | "test", 0, &result); |
| 2164 | if (rc != 0 || result.row_count != 257 || |
| 2165 | strcmp(cypher_get_col(&result, 0, "r.url_path"), "/api/orders") != 0 || |
| 2166 | strcmp(cypher_get_col(&result, 0, "r.confidence"), "0.85") != 0 || |
| 2167 | strcmp(cypher_get_col(&result, 0, "r.method"), "POST") != 0) { |
| 2168 | ctx->succeeded = false; |
nothing calls this directly
no test coverage detected