hawdb_core/error/
resource.rs1use std::fmt::{Display, Formatter};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum ResourceBudgetKind {
9 MemoryBytes,
10 SpillBytes,
11 SpillRuns,
12}
13
14impl ResourceBudgetKind {
15 pub const fn as_str(self) -> &'static str {
16 match self {
17 Self::MemoryBytes => "memory_bytes",
18 Self::SpillBytes => "spill_bytes",
19 Self::SpillRuns => "spill_runs",
20 }
21 }
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum ResourceBudgetScope {
27 Account,
28 Query,
29 Operator,
30 SharedPool,
31 FileSystem,
32}
33
34impl ResourceBudgetScope {
35 pub const fn as_str(self) -> &'static str {
36 match self {
37 Self::Account => "account",
38 Self::Query => "query",
39 Self::Operator => "operator",
40 Self::SharedPool => "shared_pool",
41 Self::FileSystem => "file_system",
42 }
43 }
44}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
58pub struct ResourceBudgetError {
59 pub resource: ResourceBudgetKind,
60 pub scope: ResourceBudgetScope,
61 pub owner: String,
62 pub memory_class: Option<&'static str>,
63 pub requested: u64,
64 pub used: u64,
65 pub budget: u64,
66 pub budget_option: &'static str,
67 pub message: String,
69}
70
71impl Display for ResourceBudgetError {
72 fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
73 formatter.write_str(&self.message)
74 }
75}
76
77impl std::error::Error for ResourceBudgetError {}
78
79pub(super) fn find_resource_budget_error(
80 error: &(dyn std::error::Error + 'static),
81) -> Option<ResourceBudgetError> {
82 let mut current = Some(error);
83 while let Some(error) = current {
84 if let Some(resource) = error.downcast_ref::<ResourceBudgetError>() {
85 return Some(resource.clone());
86 }
87 if let Some(error) = error.downcast_ref::<std::io::Error>()
89 && let Some(inner) = error.get_ref()
90 && let Some(resource) = find_resource_budget_error(inner)
91 {
92 return Some(resource);
93 }
94 current = error.source();
95 }
96 None
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use crate::HawDBError;
103
104 #[test]
105 fn resource_metadata_survives_nested_io_and_storage_contexts() {
106 let cause = ResourceBudgetError {
107 resource: ResourceBudgetKind::MemoryBytes,
108 scope: ResourceBudgetScope::Account,
109 owner: "source".into(),
110 memory_class: Some("external_read"),
111 requested: 8,
112 used: 4,
113 budget: 10,
114 budget_option: "source grant",
115 message: "source budget refused".into(),
116 };
117 let expected = HawDBError::from(cause.clone());
118 for inner in [
119 std::io::Error::other(cause),
120 std::io::Error::other(expected.clone()),
121 ] {
122 let nested = std::io::Error::other(std::io::Error::other(inner));
123 assert_eq!(
124 HawDBError::from_storage_error_with_context(nested, "read node"),
125 expected
126 );
127 }
128 assert!(matches!(
129 HawDBError::from_storage_error(std::io::Error::other("ordinary I/O failure")),
130 HawDBError::Storage(_)
131 ));
132 }
133}