From 1c15c84ee5306fdf36c185ca24b51264ed87e523 Mon Sep 17 00:00:00 2001 From: Flupkede Date: Fri, 15 May 2026 18:19:54 +0000 Subject: [PATCH 1/3] feat: auto-prune stale repos during Phase 1 warmup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a repo's database or path no longer exists (e.g. folder moved), Phase 1 now automatically unregisters the alias from repos.json instead of logging a warning and leaving the stale entry forever. Prune conditions (safe — only missing-db / path-gone, not transient errors): - .codesearch.db directory does not exist at registered path - Registered path itself no longer exists - Alias resolves to nothing in config Side effects per pruned alias: - stop_fsw + evict from DashMap + remove last_access timer - unregister_alias (removes from repos, repos_meta, groups) - persist via config.save() Closes: stale repos.json entries after folder reorganization --- Cargo.lock | 2 +- src/serve/mod.rs | 89 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 74 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 416cb11..5167c32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -628,7 +628,7 @@ dependencies = [ [[package]] name = "codesearch" -version = "1.0.96" +version = "1.0.97" dependencies = [ "anyhow", "arroy", diff --git a/src/serve/mod.rs b/src/serve/mod.rs index b771e1b..9ddbe8f 100644 --- a/src/serve/mod.rs +++ b/src/serve/mod.rs @@ -502,22 +502,79 @@ impl ServeState { }); } - /// Phase 1: warm all repos sequentially, awaiting incremental refresh per repo. - pub(crate) async fn run_phase_1_warmup_all(self: &Arc) { - let aliases = self.aliases(); - if aliases.is_empty() { - return; - } - info!("🔥 Phase 1 warmup: {} repos (no FSW)", aliases.len()); - for alias in &aliases { - match self.warmup_repo(alias).await { - Ok(()) => info!("phase-1: warmed '{}'", alias), - Err(e) => warn!("phase-1: warmup '{}' failed: {}", alias, e), - } - tokio::time::sleep(Duration::from_millis(200)).await; - } - info!("🔥 Phase 1 warmup complete"); - } + /// Phase 1: warm all repos sequentially, awaiting incremental refresh per repo. + /// Stale entries (database missing or repo path gone) are auto-pruned from repos.json. + pub(crate) async fn run_phase_1_warmup_all(self: &Arc) { + let aliases = self.aliases(); + if aliases.is_empty() { + return; + } + info!("🔥 Phase 1 warmup: {} repos (no FSW)", aliases.len()); + + let mut pruned: Vec = Vec::new(); + + for alias in &aliases { + match self.warmup_repo(alias).await { + Ok(()) => info!("phase-1: warmed '{}'", alias), + Err(e) => { + // Auto-prune stale entries where the database or repo path no longer exists. + let should_prune = { + let config = self.config.read().ok(); + let path = config.as_ref().and_then(|c| c.resolve(alias)); + match path { + Some(p) => { + let db_missing = !p.join(DB_DIR_NAME).exists(); + let path_gone = !p.exists(); + db_missing || path_gone + } + None => { + // Alias resolves to nothing — definitely stale + true + } + } + }; + + if should_prune { + warn!( + "phase-1: pruning stale alias '{}' — {}", + alias, e + ); + // Clean up any residual in-memory state + let _ = self.stop_fsw(alias); + self.repos.remove(alias); + self.last_access.remove(alias); + + // Unregister from repos.json + if let Ok(mut config) = self.config.write() { + if config.unregister_alias(alias) { + if let Err(save_err) = config.save() { + warn!( + "phase-1: failed to save repos.json after pruning '{}': {}", + alias, save_err + ); + } else { + pruned.push(alias.clone()); + } + } + } + } else { + warn!("phase-1: warmup '{}' failed: {}", alias, e); + } + } + } + tokio::time::sleep(Duration::from_millis(200)).await; + } + + if !pruned.is_empty() { + info!( + "🔥 Phase 1 warmup complete (pruned {} stale: {})", + pruned.len(), + pruned.join(", ") + ); + } else { + info!("🔥 Phase 1 warmup complete"); + } + } /// Phase 2: semaphore-bounded concurrent C# SCIP rebuilds, sorted by recency. pub(crate) async fn run_phase_2_csharp_scip(self: &Arc) { From 3e9350caf83a4ab61bba279ed87f08ae48ad622b Mon Sep 17 00:00:00 2001 From: Flupkede Date: Fri, 15 May 2026 20:12:26 +0000 Subject: [PATCH 2/3] fix: add missing YELLOW color variable in qc.sh --- Cargo.lock | 2 +- Cargo.toml | 2 +- scripts/qc.sh | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 01dc826..570dcd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -628,7 +628,7 @@ dependencies = [ [[package]] name = "codesearch" -version = "1.0.100" +version = "1.0.102" dependencies = [ "anyhow", "arroy", diff --git a/Cargo.toml b/Cargo.toml index 3172c43..1fdec21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "codesearch" -version = "1.0.100" +version = "1.0.102" edition = "2021" authors = ["codesearch contributors"] license = "Apache-2.0" diff --git a/scripts/qc.sh b/scripts/qc.sh index 75f5f38..c96915d 100644 --- a/scripts/qc.sh +++ b/scripts/qc.sh @@ -25,6 +25,7 @@ RED='\033[0;31m' GREEN='\033[0;32m' CYAN='\033[0;36m' GRAY='\033[0;90m' +YELLOW='\033[1;33m' NC='\033[0m' FAILED=() From 13adf2b7b7c4e6de4d0cef0936d79c960aa31bb3 Mon Sep 17 00:00:00 2001 From: flupkede Date: Tue, 2 Jun 2026 13:16:43 +0200 Subject: [PATCH 3/3] =?UTF-8?q?bump=20version=20to=201.0.153=20=E2=80=94?= =?UTF-8?q?=20align=20with=20CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d32baf..386b4ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -628,7 +628,7 @@ dependencies = [ [[package]] name = "codesearch" -version = "1.0.152" +version = "1.0.153" dependencies = [ "anyhow", "arroy", diff --git a/Cargo.toml b/Cargo.toml index 33d2449..a59dd0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "codesearch" -version = "1.0.152" +version = "1.0.153" edition = "2021" authors = ["codesearch contributors"] license = "Apache-2.0"