Skip to content

Commit bbaa6d5

Browse files
refactor(query-engine): replace panics with Result/None
1 parent b5bdb8a commit bbaa6d5

8 files changed

Lines changed: 77 additions & 62 deletions

File tree

‎asap-query-engine/src/drivers/query/adapters/elastic_http.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ impl QueryRequestAdapter for ElasticHttpAdapter {
9191
match self.config.language {
9292
QueryLanguage::elastic_sql => "/_sql",
9393
QueryLanguage::elastic_querydsl => "/_search",
94-
_ => panic!("Invalid query language configured for Elastic"),
94+
_ => unreachable!("Elastic adapter config is validated at startup"),
9595
}
9696
}
9797

‎asap-query-engine/src/engines/simple_engine/mod.rs‎

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,16 +1050,22 @@ impl SimpleEngine {
10501050
debug!(" Merging accumulators (should_merge=true)");
10511051
#[cfg(feature = "extra_debugging")]
10521052
let merge_start = Instant::now();
1053-
let merged_accumulator = self.merge_accumulators(&precomputes);
1054-
#[cfg(feature = "extra_debugging")]
1055-
let merge_duration = merge_start.elapsed();
1056-
#[cfg(feature = "extra_debugging")]
1057-
debug!(
1058-
" Merge completed in {:.2}ms, result type: {}",
1059-
merge_duration.as_secs_f64() * 1000.0,
1060-
merged_accumulator.get_accumulator_type()
1061-
);
1062-
merged.insert(key.clone(), merged_accumulator);
1053+
match self.merge_accumulators(&precomputes) {
1054+
Ok(merged_accumulator) => {
1055+
#[cfg(feature = "extra_debugging")]
1056+
let merge_duration = merge_start.elapsed();
1057+
#[cfg(feature = "extra_debugging")]
1058+
debug!(
1059+
" Merge completed in {:.2}ms, result type: {}",
1060+
merge_duration.as_secs_f64() * 1000.0,
1061+
merged_accumulator.get_accumulator_type()
1062+
);
1063+
merged.insert(key.clone(), merged_accumulator);
1064+
}
1065+
Err(e) => {
1066+
warn!("Failed to merge accumulators for key {:?}: {}", key, e);
1067+
}
1068+
}
10631069
} else {
10641070
assert_eq!(
10651071
precomputes.len(),
@@ -1088,21 +1094,21 @@ impl SimpleEngine {
10881094
fn merge_accumulators(
10891095
&self,
10901096
accumulators: &[Box<dyn crate::data_model::AggregateCore>],
1091-
) -> Box<dyn crate::data_model::AggregateCore> {
1097+
) -> Result<Box<dyn crate::data_model::AggregateCore>, String> {
10921098
if accumulators.is_empty() {
1093-
panic!("No accumulators to merge");
1099+
return Err("merge_accumulators called with empty slice".to_string());
10941100
}
10951101

10961102
if accumulators.len() == 1 {
1097-
return accumulators[0].clone_boxed_core();
1103+
return Ok(accumulators[0].clone_boxed_core());
10981104
}
10991105

11001106
// Try to use optimized batch merge for KLL accumulators
11011107
if accumulators[0].get_accumulator_type() == AggregationType::DatasketchesKLL {
11021108
use crate::precompute_operators::datasketches_kll_accumulator::DatasketchesKLLAccumulator;
11031109

11041110
match DatasketchesKLLAccumulator::merge_multiple(accumulators) {
1105-
Ok(merged) => return Box::new(merged),
1111+
Ok(merged) => return Ok(Box::new(merged)),
11061112
Err(e) => {
11071113
warn!(
11081114
"Batch merge failed: {}. Falling back to sequential merge.",
@@ -1118,7 +1124,7 @@ impl SimpleEngine {
11181124
use crate::precompute_operators::count_min_sketch_accumulator::CountMinSketchAccumulator;
11191125

11201126
match CountMinSketchAccumulator::merge_multiple(accumulators) {
1121-
Ok(merged) => return Box::new(merged),
1127+
Ok(merged) => return Ok(Box::new(merged)),
11221128
Err(e) => {
11231129
warn!(
11241130
"Batch merge failed: {}. Falling back to sequential merge.",
@@ -1145,7 +1151,7 @@ impl SimpleEngine {
11451151
}
11461152
}
11471153

1148-
result
1154+
Ok(result)
11491155
}
11501156

11511157
/// Collects results when key and value use different aggregations

‎asap-query-engine/src/engines/simple_engine/sql.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,9 +265,9 @@ impl SimpleEngine {
265265
(QueryType::Spatial, QueryType::TemporalQuantile) => {
266266
QueryPatternType::OneTemporalOneSpatial
267267
}
268-
_ => panic!("Unsupported query type found"),
268+
_ => return None,
269269
},
270-
_ => panic!("Unsupported query type found"),
270+
_ => return None,
271271
};
272272

273273
// For nested queries (spatial of temporal), the outer query has no time clause,

‎asap-query-engine/src/precompute_operators/delta_set_aggregator_accumulator.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ impl AggregateCore for DeltaSetAggregatorAccumulator {
247247

248248
fn get_keys(&self) -> Option<Vec<KeyByLabelValues>> {
249249
if !self.removed.is_empty() {
250-
panic!("DeltaSetAggregatorAccumulator does not support get_keys when removed items are present");
250+
return None;
251251
}
252252
Some(self.added.iter().cloned().collect())
253253
}

‎asap-query-engine/src/precompute_operators/min_max_accumulator.rs‎

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,19 @@ impl MinMaxAccumulator {
2929
}
3030
}
3131

32-
pub fn new(sub_type: String) -> Self {
32+
pub fn new(sub_type: String) -> Result<Self, String> {
3333
match sub_type.as_str() {
34-
"min" => Self::new_min(),
35-
"max" => Self::new_max(),
36-
_ => panic!("sub_type must be 'min' or 'max'"),
34+
"min" => Ok(Self::new_min()),
35+
"max" => Ok(Self::new_max()),
36+
_ => Err(format!("sub_type must be 'min' or 'max', got '{sub_type}'")),
3737
}
3838
}
3939

40-
pub fn with_value(value: f64, sub_type: String) -> Self {
40+
pub fn with_value(value: f64, sub_type: String) -> Result<Self, String> {
4141
if sub_type != "min" && sub_type != "max" {
42-
panic!("sub_type must be 'min' or 'max'");
42+
return Err(format!("sub_type must be 'min' or 'max', got '{sub_type}'"));
4343
}
44-
Self { value, sub_type }
44+
Ok(Self { value, sub_type })
4545
}
4646

4747
pub fn update(&mut self, value: f64) {
@@ -56,7 +56,7 @@ impl MinMaxAccumulator {
5656
self.value = value;
5757
}
5858
}
59-
_ => panic!("Invalid sub_type"),
59+
_ => unreachable!("MinMaxAccumulator sub_type is always 'min' or 'max'"),
6060
}
6161
}
6262

@@ -73,7 +73,7 @@ impl MinMaxAccumulator {
7373
return Err("sub_type must be 'min' or 'max'".into());
7474
}
7575

76-
Ok(Self::with_value(value, sub_type))
76+
Ok(Self::with_value(value, sub_type)?)
7777
}
7878

7979
pub fn deserialize_from_bytes(buffer: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
@@ -91,7 +91,7 @@ impl MinMaxAccumulator {
9191
_ => return Err("Invalid sub_type byte".into()),
9292
};
9393

94-
Ok(Self::with_value(value, sub_type))
94+
Ok(Self::with_value(value, sub_type)?)
9595
}
9696
}
9797

@@ -108,7 +108,7 @@ impl SerializableToSink for MinMaxAccumulator {
108108
let sub_type_byte = match self.sub_type.as_str() {
109109
"min" => 0u8,
110110
"max" => 1u8,
111-
_ => panic!("Invalid sub_type"),
111+
_ => unreachable!("MinMaxAccumulator sub_type is always 'min' or 'max'"),
112112
};
113113
bytes.push(sub_type_byte);
114114
bytes
@@ -132,7 +132,7 @@ impl MergeableAccumulator<MinMaxAccumulator> for MinMaxAccumulator {
132132
}
133133
}
134134

135-
let mut result = MinMaxAccumulator::new(sub_type.clone());
135+
let mut result = MinMaxAccumulator::new(sub_type.clone())?;
136136

137137
for acc in accumulators {
138138
result.update(acc.value);
@@ -282,7 +282,7 @@ impl SingleSubpopulationAggregateFactory for MinMaxAccumulatorFactory {
282282
Ok(Box::new(MinMaxAccumulator::with_value(
283283
result_value,
284284
self.sub_type.clone(),
285-
)))
285+
)?))
286286
}
287287

288288
fn create_default(&self) -> Box<dyn SingleSubpopulationAggregate> {
@@ -330,9 +330,9 @@ mod tests {
330330

331331
#[test]
332332
fn test_merge_min_accumulators() {
333-
let acc1 = MinMaxAccumulator::with_value(10.0, "min".to_string());
334-
let acc2 = MinMaxAccumulator::with_value(5.0, "min".to_string());
335-
let acc3 = MinMaxAccumulator::with_value(15.0, "min".to_string());
333+
let acc1 = MinMaxAccumulator::with_value(10.0, "min".to_string()).unwrap();
334+
let acc2 = MinMaxAccumulator::with_value(5.0, "min".to_string()).unwrap();
335+
let acc3 = MinMaxAccumulator::with_value(15.0, "min".to_string()).unwrap();
336336

337337
let merged =
338338
<MinMaxAccumulator as MergeableAccumulator<MinMaxAccumulator>>::merge_accumulators(
@@ -345,9 +345,9 @@ mod tests {
345345

346346
#[test]
347347
fn test_merge_max_accumulators() {
348-
let acc1 = MinMaxAccumulator::with_value(10.0, "max".to_string());
349-
let acc2 = MinMaxAccumulator::with_value(5.0, "max".to_string());
350-
let acc3 = MinMaxAccumulator::with_value(15.0, "max".to_string());
348+
let acc1 = MinMaxAccumulator::with_value(10.0, "max".to_string()).unwrap();
349+
let acc2 = MinMaxAccumulator::with_value(5.0, "max".to_string()).unwrap();
350+
let acc3 = MinMaxAccumulator::with_value(15.0, "max".to_string()).unwrap();
351351

352352
let merged =
353353
<MinMaxAccumulator as MergeableAccumulator<MinMaxAccumulator>>::merge_accumulators(
@@ -360,8 +360,8 @@ mod tests {
360360

361361
#[test]
362362
fn test_merge_different_types_error() {
363-
let acc1 = MinMaxAccumulator::with_value(10.0, "min".to_string());
364-
let acc2 = MinMaxAccumulator::with_value(5.0, "max".to_string());
363+
let acc1 = MinMaxAccumulator::with_value(10.0, "min".to_string()).unwrap();
364+
let acc2 = MinMaxAccumulator::with_value(5.0, "max".to_string()).unwrap();
365365

366366
assert!(
367367
<MinMaxAccumulator as MergeableAccumulator<MinMaxAccumulator>>::merge_accumulators(
@@ -373,7 +373,7 @@ mod tests {
373373

374374
#[test]
375375
fn test_serialization() {
376-
let acc = MinMaxAccumulator::with_value(42.5, "min".to_string());
376+
let acc = MinMaxAccumulator::with_value(42.5, "min".to_string()).unwrap();
377377

378378
// Test JSON serialization
379379
let json = acc.serialize_to_json();
@@ -391,7 +391,7 @@ mod tests {
391391
#[test]
392392
fn test_single_subpopulation_aggregate_trait() {
393393
let acc: Box<dyn SingleSubpopulationAggregate> =
394-
Box::new(MinMaxAccumulator::with_value(42.0, "max".to_string()));
394+
Box::new(MinMaxAccumulator::with_value(42.0, "max".to_string()).unwrap());
395395

396396
assert_eq!(acc.query(Statistic::Max, None).unwrap(), 42.0);
397397
assert!(acc.query(Statistic::Min, None).is_err());

‎asap-query-engine/src/precompute_operators/multiple_min_max_accumulator.rs‎

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,40 @@ pub struct MultipleMinMaxAccumulator {
1717
}
1818

1919
impl MultipleMinMaxAccumulator {
20-
pub fn new(sub_type: String) -> Self {
20+
pub fn new(sub_type: String) -> Result<Self, String> {
2121
if sub_type != "min" && sub_type != "max" {
22-
panic!("sub_type must be 'min' or 'max'");
22+
return Err(format!("sub_type must be 'min' or 'max', got '{sub_type}'"));
2323
}
2424

25-
Self {
25+
Ok(Self {
2626
values: HashMap::new(),
2727
sub_type,
28-
}
28+
})
2929
}
3030

3131
pub fn new_min() -> Self {
32-
Self::new("min".to_string())
32+
Self {
33+
values: HashMap::new(),
34+
sub_type: "min".to_string(),
35+
}
3336
}
3437

3538
pub fn new_max() -> Self {
36-
Self::new("max".to_string())
39+
Self {
40+
values: HashMap::new(),
41+
sub_type: "max".to_string(),
42+
}
3743
}
3844

39-
pub fn new_with_values(values: HashMap<KeyByLabelValues, f64>, sub_type: String) -> Self {
45+
pub fn new_with_values(
46+
values: HashMap<KeyByLabelValues, f64>,
47+
sub_type: String,
48+
) -> Result<Self, String> {
4049
if sub_type != "min" && sub_type != "max" {
41-
panic!("sub_type must be 'min' or 'max'");
50+
return Err(format!("sub_type must be 'min' or 'max', got '{sub_type}'"));
4251
}
4352

44-
Self { values, sub_type }
53+
Ok(Self { values, sub_type })
4554
}
4655

4756
pub fn update(&mut self, key: KeyByLabelValues, value: f64) {
@@ -58,7 +67,7 @@ impl MultipleMinMaxAccumulator {
5867
*current = value;
5968
}
6069
}
61-
_ => panic!("Invalid sub_type"),
70+
_ => unreachable!("MultipleMinMaxAccumulator sub_type is always 'min' or 'max'"),
6271
}
6372
}
6473

@@ -313,7 +322,7 @@ impl MergeableAccumulator<MultipleMinMaxAccumulator> for MultipleMinMaxAccumulat
313322
}
314323
}
315324

316-
let mut result = MultipleMinMaxAccumulator::new(sub_type.clone());
325+
let mut result = MultipleMinMaxAccumulator::new(sub_type.clone())?;
317326

318327
for acc in accumulators {
319328
for (key, value) in acc.values {

‎asap-query-engine/src/tests/datafusion/plan_execution_tests.rs‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -333,8 +333,8 @@ mod tests {
333333
#[tokio::test]
334334
#[ignore = "Blocked: MinMaxAccumulator has no arroyo serde"]
335335
async fn test_old_vs_new_minmax_min() {
336-
let mm_a = MinMaxAccumulator::with_value(10.0, "min".to_string());
337-
let mm_b = MinMaxAccumulator::with_value(5.0, "min".to_string());
336+
let mm_a = MinMaxAccumulator::with_value(10.0, "min".to_string()).unwrap();
337+
let mm_b = MinMaxAccumulator::with_value(5.0, "min".to_string()).unwrap();
338338

339339
let engine = create_engine_single_pop(
340340
"temperature",
@@ -353,8 +353,8 @@ mod tests {
353353
#[tokio::test]
354354
#[ignore = "Blocked: MinMaxAccumulator has no arroyo serde"]
355355
async fn test_old_vs_new_minmax_max() {
356-
let mm_a = MinMaxAccumulator::with_value(90.0, "max".to_string());
357-
let mm_b = MinMaxAccumulator::with_value(95.0, "max".to_string());
356+
let mm_a = MinMaxAccumulator::with_value(90.0, "max".to_string()).unwrap();
357+
let mm_b = MinMaxAccumulator::with_value(95.0, "max".to_string()).unwrap();
358358

359359
let engine = create_engine_single_pop(
360360
"temperature",
@@ -392,7 +392,7 @@ mod tests {
392392
#[tokio::test]
393393
#[ignore = "Blocked: MultipleMinMaxAccumulator has no arroyo serde"]
394394
async fn test_old_vs_new_multiple_minmax() {
395-
let mm = MultipleMinMaxAccumulator::new("min".to_string());
395+
let mm = MultipleMinMaxAccumulator::new("min".to_string()).unwrap();
396396

397397
let engine = create_engine_single_pop(
398398
"latency",
@@ -564,7 +564,7 @@ mod tests {
564564

565565
#[tokio::test]
566566
async fn test_execute_plan_not_implemented_minmax() {
567-
let mm = MinMaxAccumulator::with_value(42.0, "min".to_string());
567+
let mm = MinMaxAccumulator::with_value(42.0, "min".to_string()).unwrap();
568568

569569
let engine = create_engine_single_pop(
570570
"temperature",

‎asap-query-engine/src/tests/store_correctness_tests.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,7 @@ fn test_clone_fidelity_sum(strategy: LockStrategy) {
829829
}
830830

831831
fn test_clone_fidelity_min_max(strategy: LockStrategy) {
832-
let acc = MinMaxAccumulator::with_value(42.0, "max".to_string());
832+
let acc = MinMaxAccumulator::with_value(42.0, "max".to_string()).unwrap();
833833
roundtrip(strategy, acc);
834834
}
835835

@@ -858,7 +858,7 @@ fn test_clone_fidelity_multiple_min_max(strategy: LockStrategy) {
858858
let mut values = HashMap::new();
859859
values.insert(key(&["dc", "east"]), 77.7);
860860
values.insert(key(&["dc", "west"]), 33.3);
861-
let acc = MultipleMinMaxAccumulator::new_with_values(values, "max".to_string());
861+
let acc = MultipleMinMaxAccumulator::new_with_values(values, "max".to_string()).unwrap();
862862
roundtrip(strategy, acc);
863863
}
864864

0 commit comments

Comments
 (0)