Preserve semantic reader after failed generation rebuild
This commit is contained in:
1 parent
b3ebd7a894
commit
07840dd5ed
6 files changed
+171
-34
No files matched your search
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,7 @@ impl HybridSearch {
|
||||
tools: &FfmpegTools,
|
||||
limits: &MediaLimits,
|
||||
) -> Result<EmbeddingReport> {
|
||||
let previous_fingerprint = self.generation_fingerprint.clone();
|
||||
self.generation_fingerprint = generation_fingerprint(self.embedder.fingerprint());
|
||||
let mut fingerprint = generation_fingerprint(self.embedder.fingerprint());
|
||||
let defaults = MediaLimits::default();
|
||||
if limits.max_frames != defaults.max_frames
|
||||
|| limits.frame_interval_ms != defaults.frame_interval_ms
|
||||
@@ -29,7 +28,7 @@ impl HybridSearch {
|
||||
|| limits.max_duration_ms != defaults.max_duration_ms
|
||||
|| limits.max_file_bytes != defaults.max_file_bytes
|
||||
{
|
||||
self.generation_fingerprint.push_str(&format!(
|
||||
fingerprint.push_str(&format!(
|
||||
":custom-{}-{}-{}-{}-{}-{}-{}-{}",
|
||||
limits.max_frames,
|
||||
limits.frame_interval_ms,
|
||||
@@ -41,14 +40,12 @@ impl HybridSearch {
|
||||
limits.max_file_bytes
|
||||
));
|
||||
}
|
||||
let _lock = self.store.build_lock()?;
|
||||
let generation = self.store.begin(&self.generation_fingerprint)?;
|
||||
let built = (|| {
|
||||
let mut report = self.build(generation)?;
|
||||
self.rebuild_generation(fingerprint, |service, generation| {
|
||||
let mut report = service.build(generation)?;
|
||||
let mut after = 0;
|
||||
let mut media_count = 0usize;
|
||||
loop {
|
||||
let files = self.store.media_batch(after)?;
|
||||
let files = service.store.media_batch(after)?;
|
||||
if files.is_empty() {
|
||||
break;
|
||||
}
|
||||
@@ -64,7 +61,7 @@ impl HybridSearch {
|
||||
"Media generation exceeds 10000-file resource budget"
|
||||
);
|
||||
let before_chunks = report.chunks;
|
||||
match self.build_media_file(
|
||||
match service.build_media_file(
|
||||
generation,
|
||||
id,
|
||||
path,
|
||||
@@ -78,7 +75,7 @@ impl HybridSearch {
|
||||
if error.downcast_ref::<InferenceFailure>().is_some() {
|
||||
return Err(error);
|
||||
}
|
||||
self.store.media_failure(
|
||||
service.store.media_failure(
|
||||
generation,
|
||||
&path.to_string_lossy(),
|
||||
&format!("{error:#}"),
|
||||
@@ -96,18 +93,7 @@ impl HybridSearch {
|
||||
}
|
||||
}
|
||||
Ok(report)
|
||||
})();
|
||||
match built {
|
||||
Ok(report) => {
|
||||
self.store.activate(generation)?;
|
||||
Ok(report)
|
||||
}
|
||||
Err(error) => {
|
||||
self.store.abandon(generation)?;
|
||||
self.generation_fingerprint = previous_fingerprint;
|
||||
Err(error)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
||||
Reference in new issue
Block a user