Write everything after the nodes table: the edges/vectors/token_vectors data * tables, metadata tables, all indexes, and the sqlite_master page-1 + file * header. `nodes_root` is the root of the already-written nodes table. Closes * w->fp before returning (success or error). */
| 2054 | * header. `nodes_root` is the root of the already-written nodes table. Closes |
| 2055 | * w->fp before returning (success or error). */ |
| 2056 | static int write_db_after_nodes(write_db_ctx_t *w, uint32_t nodes_root) { |
| 2057 | FILE *fp = w->fp; |
| 2058 | CBMDumpNode *nodes = w->nodes; |
| 2059 | int node_count = w->node_count; |
| 2060 | CBMDumpEdge *edges = w->edges; |
| 2061 | int edge_count = w->edge_count; |
| 2062 | |
| 2063 | // Phase 1 (cont.): remaining data tables (edge + vector + token_vector records) |
| 2064 | CBM_PROF_START(t_data); |
| 2065 | uint32_t edges_root; |
| 2066 | uint32_t vectors_root; |
| 2067 | uint32_t token_vecs_root; |
| 2068 | int rc = |
| 2069 | write_one_table(w, &edges_root, w->edges, w->edge_count, adapt_build_edge, adapt_edge_id); |
| 2070 | if (rc != 0) { |
| 2071 | return discard_writer_output(w, rc); |
| 2072 | } |
| 2073 | rc = write_one_table(w, &vectors_root, w->vectors, w->vector_count, adapt_build_vector, |
| 2074 | adapt_vector_id); |
| 2075 | if (rc != 0) { |
| 2076 | return discard_writer_output(w, rc); |
| 2077 | } |
| 2078 | rc = write_one_table(w, &token_vecs_root, w->token_vecs, w->token_vec_count, |
| 2079 | adapt_build_token_vec, adapt_token_vec_id); |
| 2080 | if (rc != 0) { |
| 2081 | return discard_writer_output(w, rc); |
| 2082 | } |
| 2083 | CBM_PROF_END_N("write_db", "1_data_tables", t_data, node_count + edge_count); |
| 2084 | |
| 2085 | // Phase 2: Metadata tables (projects, file_hashes, summaries, sqlite_sequence) |
| 2086 | CBM_PROF_START(t_meta); |
| 2087 | uint32_t projects_root; |
| 2088 | uint32_t file_hashes_root; |
| 2089 | uint32_t summaries_root; |
| 2090 | uint32_t sqlite_seq_root; |
| 2091 | write_metadata_tables(w, &projects_root, &file_hashes_root, &summaries_root, &sqlite_seq_root); |
| 2092 | uint32_t next_page = w->next_page; |
| 2093 | CBM_PROF_END("write_db", "2_metadata_tables", t_meta); |
| 2094 | |
| 2095 | // --- Build indexes (all sorted by key columns before writing) --- |
| 2096 | |
| 2097 | // Set sort contexts for qsort comparators. |
| 2098 | g_sort_nodes = nodes; |
| 2099 | g_sort_edges = edges; |
| 2100 | |
| 2101 | // Parallel sort: all 11 index permutations sorted simultaneously. |
| 2102 | // Sorting is O(N log N) per index — the dominant CPU cost in index building. |
| 2103 | // Cell building + B-tree writing remains serial (sequential page allocation). |
| 2104 | SortJob nsorts[] = { |
| 2105 | {node_count, cmp_node_by_label, NULL}, |
| 2106 | {node_count, cmp_node_by_name, NULL}, |
| 2107 | {node_count, cmp_node_by_file, NULL}, |
| 2108 | {node_count, cmp_node_by_qn, NULL}, |
| 2109 | }; |
| 2110 | SortJob esorts[] = { |
| 2111 | {edge_count, cmp_edge_by_source_type, NULL}, |
| 2112 | {edge_count, cmp_edge_by_target_type, NULL}, |
| 2113 | {edge_count, cmp_edge_by_type, NULL}, |
no test coverage detected