Preserve semantic reader after failed generation rebuild

This commit is contained in:
karl committed 2026-10-12 23:54:26 +02:00
1 parent b3ebd7a894
commit 07840dd5ed
6 files changed
+171 -34

No files matched your search

+23 -9
View File
@@ -289,22 +289,36 @@ impl HybridSearch {
/// storage errors leave the previous generation active. A crashed build is
/// reclaimed on the next explicit rebuild under an OS advisory lock.
pub fn index_embeddings(&mut self) -> Result<EmbeddingReport> {
let previous_fingerprint = self.generation_fingerprint.clone();
self.generation_fingerprint = format!(
let fingerprint = format!(
"{}:text-only",
generation_fingerprint(self.embedder.fingerprint())
);
self.rebuild_generation(fingerprint, Self::build)
}
/// Keep the reader's policy aligned with the active generation on every
/// failure boundary, including lock admission, activation and cleanup.
fn rebuild_generation(
&mut self,
fingerprint: String,
build: impl FnOnce(&mut Self, i64) -> Result<EmbeddingReport>,
) -> Result<EmbeddingReport> {
let _lock = self.store.build_lock()?;
let generation = self.store.begin(&self.generation_fingerprint)?;
let built = self.build(generation);
let generation = self.store.begin(&fingerprint)?;
let previous_fingerprint = std::mem::replace(&mut self.generation_fingerprint, fingerprint);
let built = build(self, generation).and_then(|report| {
self.store.activate(generation)?;
Ok(report)
});
match built {
Ok(report) => {
self.store.activate(generation)?;
Ok(report)
}
Ok(report) => Ok(report),
Err(error) => {
self.store.abandon(generation)?;
self.generation_fingerprint = previous_fingerprint;
if let Err(cleanup) = self.store.abandon(generation) {
return Err(error.context(format!(
"Failed to discard staging generation {generation}: {cleanup:#}"
)));
}
Err(error)
}
}