Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0



## [1.0.153] - 2026-06-02

### Added

- **Auto-prune stale repos during Phase 1 warmup** — when a repo fails warmup
because its path or database no longer exists, `codesearch serve` now
automatically removes it from `repos.json` and logs a warning, instead of
silently retrying on every restart. Works in concert with the relocation pass
(reconcile_all_paths): relocatable repos are rewritten first, truly missing
ones are pruned.

### Fixed

- **Missing `YELLOW` color variable in `scripts/qc.sh`** — the variable was
referenced but never declared, causing a visual glitch in QC output.

## [1.0.152] - 2026-06-02

### Added
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "codesearch"
version = "1.0.152"
version = "1.0.153"
edition = "2021"
authors = ["codesearch contributors"]
license = "Apache-2.0"
Expand Down
1 change: 1 addition & 0 deletions scripts/qc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
GRAY='\033[0;90m'
YELLOW='\033[1;33m'
NC='\033[0m'

FAILED=()
Expand Down
58 changes: 56 additions & 2 deletions src/serve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -610,20 +610,74 @@ impl ServeState {
}

/// 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<Self>) {
let aliases = self.aliases();
if aliases.is_empty() {
return;
}
info!("🔥 Phase 1 warmup: {} repos (no FSW)", aliases.len());

let mut pruned: Vec<String> = Vec::new();

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),
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;
}
info!("🔥 Phase 1 warmup complete");

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.
Expand Down
Loading