Skip to content

Commit d3fc385

Browse files
committed
fix: rebuild index when mode adds capabilities
Signed-off-by: Anton Standrik <astandrik@yandex-team.ru>
1 parent 2469ecc commit d3fc385

4 files changed

Lines changed: 397 additions & 9 deletions

File tree

src/pipeline/pipeline.c

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ enum { CBM_DIR_PERMS = 0755, PL_RING = 4, PL_RING_MASK = 3, PL_SEQ_PASSES = 6, P
3333
#include "foundation/compat_thread.h"
3434
#include "foundation/profile.h"
3535
#include "foundation/mem.h"
36+
#include "yyjson/yyjson.h"
3637

3738
#include <stdint.h>
3839
#include <stdio.h>
@@ -151,6 +152,66 @@ static const char *itoa_buf(int val) {
151152
return bufs[i];
152153
}
153154

155+
static const char *index_mode_name(cbm_index_mode_t mode) {
156+
switch (mode) {
157+
case CBM_MODE_FULL:
158+
return "full";
159+
case CBM_MODE_MODERATE:
160+
return "moderate";
161+
case CBM_MODE_FAST:
162+
return "fast";
163+
default:
164+
return "unknown";
165+
}
166+
}
167+
168+
static bool parse_index_mode(const char *properties_json, cbm_index_mode_t *out_mode) {
169+
if (!properties_json || !out_mode) {
170+
return false;
171+
}
172+
173+
yyjson_doc *doc = yyjson_read(properties_json, strlen(properties_json), 0);
174+
if (!doc) {
175+
return false;
176+
}
177+
178+
yyjson_val *root = yyjson_doc_get_root(doc);
179+
yyjson_val *mode_value = yyjson_is_obj(root) ? yyjson_obj_get(root, "index_mode") : NULL;
180+
const char *mode_name =
181+
mode_value && yyjson_is_str(mode_value) ? yyjson_get_str(mode_value) : NULL;
182+
bool parsed = true;
183+
if (mode_name && strcmp(mode_name, "full") == 0) {
184+
*out_mode = CBM_MODE_FULL;
185+
} else if (mode_name && strcmp(mode_name, "moderate") == 0) {
186+
*out_mode = CBM_MODE_MODERATE;
187+
} else if (mode_name && strcmp(mode_name, "fast") == 0) {
188+
*out_mode = CBM_MODE_FAST;
189+
} else {
190+
parsed = false;
191+
}
192+
193+
yyjson_doc_free(doc);
194+
return parsed;
195+
}
196+
197+
static bool index_mode_covers(cbm_index_mode_t stored_mode, cbm_index_mode_t requested_mode) {
198+
return stored_mode >= CBM_MODE_FULL && stored_mode <= CBM_MODE_FAST &&
199+
requested_mode >= CBM_MODE_FULL && requested_mode <= CBM_MODE_FAST &&
200+
stored_mode <= requested_mode;
201+
}
202+
203+
static bool read_stored_index_mode(cbm_store_t *store, const char *project,
204+
cbm_index_mode_t *out_mode) {
205+
cbm_node_t project_node = {0};
206+
if (cbm_store_find_node_by_qn(store, project, project, &project_node) != CBM_STORE_OK) {
207+
return false;
208+
}
209+
210+
bool parsed = parse_index_mode(project_node.properties_json, out_mode);
211+
cbm_node_free_fields(&project_node);
212+
return parsed;
213+
}
214+
154215
/* Log current + peak RSS at a pipeline phase boundary (memory profiling). */
155216
static void log_phase_mem(const char *phase) {
156217
enum { PL_BYTES_PER_MB = 1024 * 1024 };
@@ -446,7 +507,11 @@ static int pass_structure(cbm_pipeline_t *p, const cbm_file_info_t *files, int f
446507
cbm_log_info("pass.start", "pass", "structure", "files", itoa_buf(file_count));
447508

448509
/* Project node */
449-
cbm_gbuf_upsert_node(p->gbuf, "Project", p->project_name, p->project_name, NULL, 0, 0, "{}");
510+
char project_props[CBM_SZ_64];
511+
snprintf(project_props, sizeof(project_props), "{\"index_mode\":\"%s\"}",
512+
index_mode_name(p->mode));
513+
cbm_gbuf_upsert_node(p->gbuf, "Project", p->project_name, p->project_name, NULL, 0, 0,
514+
project_props);
450515
const char *branch_qn = p->branch_qn ? p->branch_qn : p->project_name;
451516
const char *branch_name = p->git_ctx.branch ? p->git_ctx.branch : "working-tree";
452517
char branch_props[CBM_SZ_2K];
@@ -998,17 +1063,26 @@ static int try_incremental_or_delete_db(cbm_pipeline_t *p, cbm_file_info_t *file
9981063
if (check_store && cbm_store_check_integrity(check_store)) {
9991064
cbm_file_hash_t *hashes = NULL;
10001065
int hash_count = 0;
1066+
cbm_index_mode_t stored_mode = CBM_MODE_FAST;
1067+
bool stored_mode_known = read_stored_index_mode(check_store, p->project_name, &stored_mode);
10011068
cbm_store_get_file_hashes(check_store, p->project_name, &hashes, &hash_count);
10021069
cbm_store_free_file_hashes(hashes, hash_count);
10031070
cbm_store_close(check_store);
1004-
if (hash_count > 0 && file_count <= hash_count + (hash_count / PAIR_LEN)) {
1071+
bool mode_covered = stored_mode_known && index_mode_covers(stored_mode, p->mode);
1072+
if (hash_count > 0 && mode_covered && file_count <= hash_count + (hash_count / PAIR_LEN)) {
10051073
cbm_log_info("pipeline.route", "path", "incremental", "stored_hashes",
1006-
itoa_buf(hash_count));
1007-
int rc = cbm_pipeline_run_incremental(p, db_path, files, file_count);
1074+
itoa_buf(hash_count), "stored_mode", index_mode_name(stored_mode),
1075+
"requested_mode", index_mode_name(p->mode), "effective_mode",
1076+
index_mode_name(stored_mode));
1077+
int rc = cbm_pipeline_run_incremental(p, db_path, files, file_count, stored_mode);
10081078
free(db_path);
10091079
return rc;
10101080
}
1011-
if (hash_count > 0) {
1081+
if (hash_count > 0 && !mode_covered) {
1082+
cbm_log_info("pipeline.route", "path", "mode_upgrade_reindex", "stored_mode",
1083+
stored_mode_known ? index_mode_name(stored_mode) : "unknown",
1084+
"requested_mode", index_mode_name(p->mode));
1085+
} else if (hash_count > 0) {
10121086
cbm_log_info("pipeline.route", "path", "mode_change_reindex", "stored_hashes",
10131087
itoa_buf(hash_count), "discovered", itoa_buf(file_count));
10141088
}

src/pipeline/pipeline_incremental.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -684,11 +684,12 @@ static void dump_and_persist(cbm_gbuf_t *gbuf, const char *db_path, const char *
684684
/* ── Incremental pipeline entry point ────────────────────────────── */
685685

686686
int cbm_pipeline_run_incremental(cbm_pipeline_t *p, const char *db_path, cbm_file_info_t *files,
687-
int file_count) {
687+
int file_count, cbm_index_mode_t effective_mode) {
688688
struct timespec t0;
689689
cbm_clock_gettime(CLOCK_MONOTONIC, &t0);
690690

691691
const char *project = cbm_pipeline_project_name(p);
692+
cbm_index_mode_t requested_mode = (cbm_index_mode_t)cbm_pipeline_get_mode(p);
692693

693694
/* Open existing disk DB */
694695
cbm_store_t *store = cbm_store_open_path(db_path);
@@ -839,7 +840,7 @@ int cbm_pipeline_run_incremental(cbm_pipeline_t *p, const char *db_path, cbm_fil
839840
.registry = registry,
840841
.cancelled = cbm_pipeline_cancelled_ptr(p),
841842
.pipeline = p, /* so passes can record per-file skips (Track B) */
842-
.mode = cbm_pipeline_get_mode(p),
843+
.mode = effective_mode,
843844
.path_aliases = path_aliases,
844845
.excluded_dirs = excluded_dirs,
845846
.excluded_count = excluded_count,
@@ -854,7 +855,12 @@ int cbm_pipeline_run_incremental(cbm_pipeline_t *p, const char *db_path, cbm_fil
854855
}
855856
}
856857

858+
/* Discovery already used requested_mode. Re-extraction must preserve the
859+
* stronger capabilities recorded in Project.index_mode, including full-only
860+
* C/C++ Macro nodes. Restore the process-wide gate immediately afterwards. */
861+
cbm_set_macro_extraction(effective_mode == CBM_MODE_FULL);
857862
run_extract_resolve(&ctx, changed_files, ci);
863+
cbm_set_macro_extraction(requested_mode == CBM_MODE_FULL);
858864
cbm_pipeline_pass_k8s(&ctx, changed_files, ci);
859865
run_postpasses(&ctx, changed_files, ci, project);
860866

src/pipeline/pipeline_internal.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -607,9 +607,11 @@ int cbm_scan_project_env_urls_excluded(const char *root_path, cbm_env_binding_t
607607

608608
/* Run incremental re-index on an existing disk DB.
609609
* Classifies files by mtime+size, deletes changed nodes, re-parses changed
610-
* files, merges into disk DB. Returns 0 on success. */
610+
* files with effective_mode capabilities, then merges into disk DB. The
611+
* pipeline's requested mode still owns discovery/exclusions. Returns 0 on
612+
* success. */
611613
int cbm_pipeline_run_incremental(cbm_pipeline_t *p, const char *db_path, cbm_file_info_t *files,
612-
int file_count);
614+
int file_count, cbm_index_mode_t effective_mode);
613615

614616
/* Pipeline accessors for incremental use */
615617
const char *cbm_pipeline_repo_path(const cbm_pipeline_t *p);

0 commit comments

Comments
 (0)