Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add error stack to ErrorCode #16343

Merged
merged 3 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ async_fn_in_trait = "allow"
[workspace.lints.clippy]
useless_format = "allow"
mutable_key_type = "allow"
result_large_err = "allow"

[profile.release]
debug = 1
Expand Down
4 changes: 2 additions & 2 deletions src/common/base/src/base/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use unicode_segmentation::UnicodeSegmentation;
/// let new_key = escape_for_key(&key);
/// assert_eq!(Ok("data_bend%21%21".to_string()), new_key);
/// ```
pub fn escape_for_key(key: &str) -> Result<String, FromUtf8Error> {
pub fn escape_for_key(key: &str) -> std::result::Result<String, FromUtf8Error> {
let mut new_key = Vec::with_capacity(key.len());

fn hex(num: u8) -> u8 {
Expand Down Expand Up @@ -64,7 +64,7 @@ pub fn escape_for_key(key: &str) -> Result<String, FromUtf8Error> {
/// let original_key = unescape_for_key(&key);
/// assert_eq!(Ok("data_bend!!".to_string()), original_key);
/// ```
pub fn unescape_for_key(key: &str) -> Result<String, FromUtf8Error> {
pub fn unescape_for_key(key: &str) -> std::result::Result<String, FromUtf8Error> {
let mut new_key = Vec::with_capacity(key.len());

fn unhex(num: u8) -> u8 {
Expand Down
9 changes: 5 additions & 4 deletions src/common/base/src/runtime/memory/stat_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
use std::ptr::addr_of_mut;
use std::sync::atomic::Ordering;

use databend_common_exception::Result;

use crate::runtime::memory::mem_stat::OutOfLimit;
use crate::runtime::memory::MemStat;
use crate::runtime::LimitMemGuard;
Expand Down Expand Up @@ -70,7 +68,10 @@ impl StatBuffer {
}

/// Flush buffered stat to MemStat it belongs to.
pub fn flush<const ROLLBACK: bool>(&mut self, alloc: i64) -> Result<(), OutOfLimit> {
pub fn flush<const ROLLBACK: bool>(
&mut self,
alloc: i64,
) -> std::result::Result<(), OutOfLimit> {
match std::mem::take(&mut self.memory_usage) {
0 => Ok(()),
usage => {
Expand All @@ -94,7 +95,7 @@ impl StatBuffer {
}
}

pub fn alloc(&mut self, memory_usage: i64) -> Result<(), OutOfLimit> {
pub fn alloc(&mut self, memory_usage: i64) -> std::result::Result<(), OutOfLimit> {
// Rust will alloc or dealloc memory after the thread local is destroyed when we using thread_local macro.
// This is the boundary of thread exit. It may be dangerous to throw mistakes here.
if self.destroyed_thread_local_macro {
Expand Down
4 changes: 2 additions & 2 deletions src/common/base/src/runtime/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ where
}

#[track_caller]
pub fn try_spawn_blocking<F, R>(f: F) -> Result<tokio::task::JoinHandle<R>, F>
pub fn try_spawn_blocking<F, R>(f: F) -> std::result::Result<tokio::task::JoinHandle<R>, F>
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
Expand All @@ -480,7 +480,7 @@ pub fn block_on<F: Future>(future: F) -> F::Output {
}

#[track_caller]
pub fn try_block_on<F: Future>(future: F) -> Result<F::Output, F> {
pub fn try_block_on<F: Future>(future: F) -> std::result::Result<F::Output, F> {
match tokio::runtime::Handle::try_current() {
Err(_) => Err(future),
#[expect(clippy::disallowed_methods)]
Expand Down
14 changes: 7 additions & 7 deletions src/common/cloud_control/tests/it/task_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl TaskService for MockTaskService {
async fn create_task(
&self,
request: Request<CreateTaskRequest>,
) -> Result<Response<CreateTaskResponse>, Status> {
) -> std::result::Result<Response<CreateTaskResponse>, Status> {
let task_id = request.into_inner().task_name.parse::<u64>();
Ok(Response::new(CreateTaskResponse {
error: None,
Expand All @@ -65,7 +65,7 @@ impl TaskService for MockTaskService {
async fn describe_task(
&self,
request: Request<DescribeTaskRequest>,
) -> Result<Response<DescribeTaskResponse>, Status> {
) -> std::result::Result<Response<DescribeTaskResponse>, Status> {
Ok(Response::new(DescribeTaskResponse {
task: Some(Task {
task_id: 0,
Expand Down Expand Up @@ -93,21 +93,21 @@ impl TaskService for MockTaskService {
async fn execute_task(
&self,
_request: Request<ExecuteTaskRequest>,
) -> Result<Response<ExecuteTaskResponse>, Status> {
) -> std::result::Result<Response<ExecuteTaskResponse>, Status> {
Ok(Response::new(ExecuteTaskResponse { error: None }))
}

async fn drop_task(
&self,
_request: Request<DropTaskRequest>,
) -> Result<Response<DropTaskResponse>, Status> {
) -> std::result::Result<Response<DropTaskResponse>, Status> {
Ok(Response::new(DropTaskResponse { error: None }))
}

async fn alter_task(
&self,
_request: Request<AlterTaskRequest>,
) -> Result<Response<AlterTaskResponse>, Status> {
) -> std::result::Result<Response<AlterTaskResponse>, Status> {
Ok(Response::new(AlterTaskResponse {
error: None,
task: None,
Expand All @@ -117,7 +117,7 @@ impl TaskService for MockTaskService {
async fn show_tasks(
&self,
_request: Request<ShowTasksRequest>,
) -> Result<Response<ShowTasksResponse>, Status> {
) -> std::result::Result<Response<ShowTasksResponse>, Status> {
Ok(Response::new(ShowTasksResponse {
tasks: vec![],
error: None,
Expand All @@ -127,7 +127,7 @@ impl TaskService for MockTaskService {
async fn show_task_runs(
&self,
_request: Request<ShowTaskRunsRequest>,
) -> Result<Response<ShowTaskRunsResponse>, Status> {
) -> std::result::Result<Response<ShowTaskRunsResponse>, Status> {
Ok(Response::new(ShowTaskRunsResponse {
task_runs: vec![],
error: None,
Expand Down
74 changes: 74 additions & 0 deletions src/common/exception/src/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2021 Datafuse Labs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt::Write;

use crate::ErrorCode;

#[derive(Debug, Clone)]
pub struct ErrorFrame {
pub file: String,
pub line: u32,
pub col: u32,
pub message: String,
}

impl<C> ErrorCode<C> {
#[track_caller]
pub fn with_context<C2>(self, ctx: impl ToString) -> ErrorCode<C2> {
let location = std::panic::Location::caller();
let frame = ErrorFrame {
file: location.file().to_string(),
line: location.line(),
col: location.column(),
message: ctx.to_string(),
};
let mut stacks = self.stacks;
stacks.push(frame);
ErrorCode {
code: self.code,
name: self.name,
display_text: self.display_text,
detail: self.detail,
span: self.span,
cause: self.cause,
backtrace: self.backtrace,
stacks,
_phantom: std::marker::PhantomData,
}
}
}

pub trait ResultExt<T, C> {
fn with_context<C2>(self, ctx: impl ToString) -> std::result::Result<T, ErrorCode<C2>>;
}

impl<T, C> ResultExt<T, C> for std::result::Result<T, ErrorCode<C>> {
fn with_context<C2>(self, ctx: impl ToString) -> std::result::Result<T, ErrorCode<C2>> {
self.map_err(|e| e.with_context(ctx))
}
}

pub fn display_error_stack(stacks: &[ErrorFrame]) -> String {
let mut buf = String::new();
for (i, stack) in stacks.iter().enumerate() {
writeln!(
&mut buf,
"{:<2} {} at {}:{}:{}",
i, stack.message, stack.file, stack.line, stack.col,
)
.unwrap();
}
buf
}
52 changes: 39 additions & 13 deletions src/common/exception/src/exception.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::marker::PhantomData;
use std::sync::Arc;

use backtrace::Backtrace;
Expand All @@ -25,6 +26,7 @@ use databend_common_ast::Span;
use thiserror::Error;

use crate::exception_backtrace::capture;
use crate::ErrorFrame;

#[derive(Clone)]
pub enum ErrorCodeBacktrace {
Expand Down Expand Up @@ -87,19 +89,21 @@ impl From<Arc<Backtrace>> for ErrorCodeBacktrace {
}

#[derive(Error)]
pub struct ErrorCode {
code: u16,
name: String,
display_text: String,
detail: String,
span: Span,
pub struct ErrorCode<C = ()> {
pub(crate) code: u16,
pub(crate) name: String,
pub(crate) display_text: String,
pub(crate) detail: String,
pub(crate) span: Span,
// cause is only used to contain an `anyhow::Error`.
// TODO: remove `cause` when we completely get rid of `anyhow::Error`.
cause: Option<Box<dyn std::error::Error + Sync + Send>>,
backtrace: Option<ErrorCodeBacktrace>,
pub(crate) cause: Option<Box<dyn std::error::Error + Sync + Send>>,
pub(crate) backtrace: Option<ErrorCodeBacktrace>,
pub(crate) stacks: Vec<ErrorFrame>,
pub(crate) _phantom: PhantomData<C>,
}

impl ErrorCode {
impl<C> ErrorCode<C> {
pub fn code(&self) -> u16 {
self.code
}
Expand Down Expand Up @@ -214,11 +218,20 @@ impl ErrorCode {
.as_ref()
.map_or("".to_string(), |x| x.to_string())
}

pub fn stacks(&self) -> &[ErrorFrame] {
&self.stacks
}

pub fn set_stacks(mut self, stacks: Vec<ErrorFrame>) -> Self {
self.stacks = stacks;
self
}
}

pub type Result<T, E = ErrorCode> = std::result::Result<T, E>;
pub type Result<T, C = ()> = std::result::Result<T, ErrorCode<C>>;

impl Debug for ErrorCode {
impl<C> Debug for ErrorCode<C> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(
f,
Expand Down Expand Up @@ -266,6 +279,7 @@ impl Display for ErrorCode {

impl ErrorCode {
/// All std error will be converted to InternalError
#[track_caller]
pub fn from_std_error<T: std::error::Error>(error: T) -> Self {
ErrorCode {
code: 1001,
Expand All @@ -275,19 +289,25 @@ impl ErrorCode {
span: None,
cause: None,
backtrace: capture(),
stacks: vec![],
_phantom: PhantomData::<()>,
}
.with_context(error.to_string())
}

pub fn from_string(error: String) -> Self {
ErrorCode {
code: 1001,
name: String::from("Internal"),
display_text: error,
display_text: error.clone(),
detail: String::new(),
span: None,
cause: None,
backtrace: capture(),
stacks: vec![],
_phantom: PhantomData::<()>,
}
.with_context(error)
}

pub fn from_string_no_backtrace(error: String) -> Self {
Expand All @@ -299,6 +319,8 @@ impl ErrorCode {
span: None,
cause: None,
backtrace: None,
stacks: vec![],
_phantom: PhantomData::<()>,
}
}

Expand All @@ -312,13 +334,16 @@ impl ErrorCode {
) -> ErrorCode {
ErrorCode {
code,
display_text,
display_text: display_text.clone(),
detail,
span: None,
cause,
backtrace,
name: name.to_string(),
stacks: vec![],
_phantom: PhantomData::<()>,
}
.with_context(display_text)
}
}

Expand Down Expand Up @@ -379,5 +404,6 @@ impl Clone for ErrorCode {
self.backtrace(),
)
.set_span(self.span())
.set_stacks(self.stacks().to_vec())
}
}
Loading
Loading