use query_planning::error::QueryError;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct RetryFacts {
pub(crate) retry_action: Option<String>,
pub(crate) resume_boundary: Option<String>,
pub(crate) committed_chunks: Option<usize>,
pub(crate) committed_partials: Option<usize>,
pub(crate) merge_level: Option<usize>,
pub(crate) merge_fan_in: Option<usize>,
}
impl RetryFacts {
#[doc(hidden)]
pub fn new() -> Self {
Self::default()
}
#[must_use]
#[doc(hidden)]
pub fn with_retry_action(mut self, retry_action: impl Into<String>) -> Self {
self.retry_action = Some(retry_action.into());
self
}
#[must_use]
#[doc(hidden)]
pub fn with_resume_boundary(mut self, resume_boundary: impl Into<String>) -> Self {
self.resume_boundary = Some(resume_boundary.into());
self
}
#[must_use]
#[doc(hidden)]
pub fn with_committed_chunks(mut self, committed_chunks: usize) -> Self {
self.committed_chunks = Some(committed_chunks);
self
}
#[must_use]
#[doc(hidden)]
pub fn with_committed_partials(mut self, committed_partials: usize) -> Self {
self.committed_partials = Some(committed_partials);
self
}
#[must_use]
#[doc(hidden)]
pub fn with_merge_level(mut self, merge_level: usize) -> Self {
self.merge_level = Some(merge_level);
self
}
#[must_use]
#[doc(hidden)]
pub fn with_merge_fan_in(mut self, merge_fan_in: usize) -> Self {
self.merge_fan_in = Some(merge_fan_in);
self
}
#[doc(hidden)]
pub fn attach_to_error(&self, mut error: QueryError) -> QueryError {
if let Some(retry_action) = &self.retry_action {
error = error.with_fact_if_absent("retry_action", retry_action);
}
if let Some(resume_boundary) = &self.resume_boundary {
error = error.with_fact_if_absent("resume_boundary", resume_boundary);
}
if let Some(committed_chunks) = self.committed_chunks {
error = error.with_fact_if_absent("committed_chunks", committed_chunks);
}
if let Some(committed_partials) = self.committed_partials {
error = error.with_fact_if_absent("committed_partials", committed_partials);
}
if let Some(merge_level) = self.merge_level {
error = error.with_fact_if_absent("merge_level", merge_level);
}
if let Some(merge_fan_in) = self.merge_fan_in {
error = error.with_fact_if_absent("merge_fan_in", merge_fan_in);
}
error
}
}
#[cfg(test)]
mod tests {
use query_planning::error::{QueryError, QueryErrorCode};
use super::*;
#[test]
fn retry_facts_attach_stable_resume_and_merge_context() {
let error = RetryFacts::new()
.with_retry_action("reduce_merge_fan_in")
.with_resume_boundary("final_merge")
.with_committed_chunks(8)
.with_committed_partials(8)
.with_merge_level(1)
.with_merge_fan_in(2)
.attach_to_error(QueryError::new(
QueryErrorCode::DeviceAllocationFailed,
"query_engine.test",
"allocation failed",
));
assert_eq!(error.fact_value("retry_action"), Some("reduce_merge_fan_in"));
assert_eq!(error.fact_value("resume_boundary"), Some("final_merge"));
assert_eq!(error.fact_value("committed_chunks"), Some("8"));
assert_eq!(error.fact_value("committed_partials"), Some("8"));
assert_eq!(error.fact_value("merge_level"), Some("1"));
assert_eq!(error.fact_value("merge_fan_in"), Some("2"));
}
}