query_runtime/
native_error.rs1use std::borrow::Cow;
14
15use query_planning::error::{MemoryFailure, MemoryUsage, QueryError, QueryErrorCode, redact_uri_tokens};
16
17pub fn cudf_query_error(operation: &'static str, message: impl Into<String>, source: cudf::Error) -> QueryError {
23 let error = cudf_query_error_without_source(operation, message, &source);
24 error.with_source(source)
25}
26
27pub fn cudf_query_error_without_source(
33 operation: &'static str,
34 message: impl Into<String>,
35 source: &cudf::Error,
36) -> QueryError {
37 cudf_query_error_with_code(query_error_code_for_cudf_error(source), operation, message, source)
38}
39
40pub fn cudf_unsupported_type_error(
48 operation: &'static str,
49 message: impl Into<String>,
50 source: cudf::Error,
51) -> QueryError {
52 let mut error = cudf_query_error_with_code(QueryErrorCode::UnsupportedType, operation, message, &source);
53 if let Some(reason) = source.detail_value("reason") {
54 error = error.with_fact("cudf_reason", reason);
55 }
56 error.with_source(source)
57}
58
59fn cudf_query_error_with_code(
60 code: QueryErrorCode,
61 operation: &'static str,
62 message: impl Into<String>,
63 source: &cudf::Error,
64) -> QueryError {
65 let mut error = QueryError::new(code, operation, message)
66 .with_fact("cudf_code", source.code())
67 .with_fact("cudf_kind", source.kind())
68 .with_fact("cudf_status", source.status())
69 .with_fact("cudf_operation", source.operation());
70 error = with_cudf_ffi_detail_facts(error, source);
71 if let Some(detail) = source.budget_exhaustion() {
72 error = error.with_memory_failure(memory_failure(detail));
73 }
74 match cudf_message_fact(source) {
75 Some(cudf_message) => error.with_fact("cudf_message", cudf_message),
76 None => error,
77 }
78}
79
80pub fn query_error_code_for_cudf_error(error: &cudf::Error) -> QueryErrorCode {
86 match cudf::allocation_attribution(error) {
87 cudf::CudfAllocationAttribution::ConfirmedQueryLimit => {
88 return QueryErrorCode::QueryMemoryLimitExceeded;
89 },
90 cudf::CudfAllocationAttribution::ConfirmedPhysical => return QueryErrorCode::DeviceOutOfMemory,
91 cudf::CudfAllocationAttribution::UnattributedAllocationFailure => {
92 return QueryErrorCode::DeviceAllocationFailed;
93 },
94 cudf::CudfAllocationAttribution::NonAllocationFailure => {},
95 }
96 match cudf::classify_cudf_error(error) {
97 cudf::CudfErrorClassification::SizeOverflow => QueryErrorCode::SizeOverflow,
98 cudf::CudfErrorClassification::HostMaterializationLimitExceeded => {
99 QueryErrorCode::HostMaterializationLimitExceeded
100 },
101 cudf::CudfErrorClassification::ResourceExhausted => QueryErrorCode::DeviceAllocationFailed,
102 cudf::CudfErrorClassification::TemporaryFailure => QueryErrorCode::CudfTemporaryFailure,
103 cudf::CudfErrorClassification::PersistentFailure => QueryErrorCode::DeviceFault,
104 cudf::CudfErrorClassification::InvalidInput => QueryErrorCode::CudfInvalidInput,
105 cudf::CudfErrorClassification::Unsupported => QueryErrorCode::CudfUnsupported,
106 cudf::CudfErrorClassification::DependencyFailure => QueryErrorCode::CudfDependencyFailure,
107 cudf::CudfErrorClassification::InvariantViolation => QueryErrorCode::InternalInvariantViolation,
108 }
109}
110
111pub fn memory_failure(detail: &cudf::BudgetExhaustionDetail) -> MemoryFailure {
114 MemoryFailure {
115 boundary: Cow::Owned(detail.boundary().to_owned()),
116 operation: Cow::Borrowed(detail.operation()),
117 usage: detail.usage().map(|usage| MemoryUsage {
118 limit_bytes: usage.allocation_limit_bytes,
119 peak_bytes: usage.peak_bytes,
120 peak_aligned_bytes: usage.peak_aligned_bytes,
121 current_bytes: usage.current_bytes,
122 current_aligned_bytes: usage.current_aligned_bytes,
123 failed_allocation_count: usage.failed_allocation_count,
124 largest_failed_allocation_bytes: usage.largest_failed_allocation_bytes,
125 }),
126 }
127}
128
129pub fn cudf_message_fact(source: &cudf::Error) -> Option<String> {
131 let message = source.message().trim();
132 if message.is_empty() {
133 return None;
134 }
135 Some(redact_uri_tokens(message))
136}
137
138fn with_cudf_ffi_detail_facts(mut error: QueryError, source: &cudf::Error) -> QueryError {
139 let Some(detail) = source.ffi_detail() else {
140 return error;
141 };
142 error = error
143 .with_fact("failure_source", detail.failure_source)
144 .with_fact("requested_allocation_bytes", detail.requested_bytes)
145 .with_fact("allocation_alignment", detail.alignment)
146 .with_fact("cuda_status", detail.cuda_error);
147 if detail.domain_id != 0 {
148 error = error.with_fact("allocation_domain_id", detail.domain_id);
149 }
150 if detail.member_id != 0 {
151 error = error.with_fact("allocation_member_id", detail.member_id);
152 }
153 if detail.generation != 0 {
154 error = error.with_fact("allocation_domain_generation", detail.generation);
155 }
156 error
157}
158
159#[cfg(test)]
160mod tests;