diff --git a/Cargo.lock b/Cargo.lock index 1eaf5b4eaf36..463bb474d98d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -208,6 +208,7 @@ version = "0.4.0-nightly" dependencies = [ "common-base", "common-error", + "common-macro", "common-time", "datatypes", "greptime-proto", @@ -690,6 +691,7 @@ dependencies = [ "api", "async-trait", "common-error", + "common-macro", "common-test-util", "digest", "hex", @@ -1250,6 +1252,7 @@ dependencies = [ "common-catalog", "common-error", "common-grpc", + "common-macro", "common-meta", "common-query", "common-recordbatch", @@ -1532,6 +1535,7 @@ dependencies = [ "common-error", "common-grpc", "common-grpc-expr", + "common-macro", "common-meta", "common-query", "common-recordbatch", @@ -1600,6 +1604,7 @@ dependencies = [ "common-catalog", "common-config", "common-error", + "common-macro", "common-meta", "common-procedure", "common-query", @@ -1672,6 +1677,7 @@ dependencies = [ "bitvec", "bytes", "common-error", + "common-macro", "paste", "serde", "snafu", @@ -1684,6 +1690,7 @@ version = "0.4.0-nightly" dependencies = [ "chrono", "common-error", + "common-macro", "serde", "serde_json", "snafu", @@ -1709,6 +1716,7 @@ dependencies = [ "async-trait", "bytes", "common-error", + "common-macro", "common-runtime", "common-test-util", "datafusion", @@ -1787,6 +1795,7 @@ dependencies = [ "backtrace", "common-base", "common-error", + "common-macro", "common-recordbatch", "common-runtime", "common-telemetry", @@ -1815,6 +1824,7 @@ dependencies = [ "common-base", "common-catalog", "common-error", + "common-macro", "common-query", "common-telemetry", "common-time", @@ -1838,6 +1848,7 @@ dependencies = [ "snafu", "static_assertions", "syn 1.0.109", + "syn 2.0.29", ] [[package]] @@ -1845,6 +1856,7 @@ name = "common-mem-prof" version = "0.4.0-nightly" dependencies = [ "common-error", + "common-macro", "snafu", "tempfile", "tikv-jemalloc-ctl", @@ -1864,6 +1876,7 @@ dependencies = [ "common-catalog", "common-error", "common-grpc-expr", + "common-macro", "common-procedure", "common-recordbatch", "common-runtime", @@ -1895,6 +1908,7 @@ dependencies = [ "async-trait", "backon", "common-error", + "common-macro", "common-runtime", "common-telemetry", "common-test-util", @@ -1926,6 +1940,7 @@ dependencies = [ "async-trait", "common-base", "common-error", + "common-macro", "common-recordbatch", "common-time", "datafusion", @@ -1945,6 +1960,7 @@ name = "common-recordbatch" version = "0.4.0-nightly" dependencies = [ "common-error", + "common-macro", "datafusion", "datafusion-common", "datatypes", @@ -1962,6 +1978,7 @@ version = "0.4.0-nightly" dependencies = [ "async-trait", "common-error", + "common-macro", "common-telemetry", "metrics", "once_cell", @@ -2016,6 +2033,7 @@ dependencies = [ "chrono", "chrono-tz 0.8.3", "common-error", + "common-macro", "rand", "serde", "serde_json", @@ -2684,6 +2702,7 @@ dependencies = [ "common-greptimedb-telemetry", "common-grpc", "common-grpc-expr", + "common-macro", "common-meta", "common-procedure", "common-query", @@ -2741,6 +2760,7 @@ dependencies = [ "arrow-schema", "common-base", "common-error", + "common-macro", "common-telemetry", "common-time", "datafusion-common", @@ -3203,6 +3223,7 @@ dependencies = [ "common-catalog", "common-datasource", "common-error", + "common-macro", "common-procedure", "common-procedure-test", "common-query", @@ -3325,6 +3346,7 @@ dependencies = [ "common-function", "common-grpc", "common-grpc-expr", + "common-macro", "common-meta", "common-procedure", "common-query", @@ -4188,7 +4210,7 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "greptime-proto" version = "0.1.0" -source = "git+https://github.com/GreptimeTeam/greptime-proto.git?rev=115c1080773be8a819e50b257fece9f839a0c836#115c1080773be8a819e50b257fece9f839a0c836" +source = "git+https://github.com/GreptimeTeam/greptime-proto.git?rev=693128abe9adc70ba636010a172c9da55b206bba#693128abe9adc70ba636010a172c9da55b206bba" dependencies = [ "prost", "serde", @@ -5030,6 +5052,7 @@ dependencies = [ "common-base", "common-config", "common-error", + "common-macro", "common-meta", "common-runtime", "common-telemetry", @@ -5305,6 +5328,7 @@ dependencies = [ "chrono", "common-error", "common-grpc", + "common-macro", "common-meta", "common-telemetry", "datatypes", @@ -5341,6 +5365,7 @@ dependencies = [ "common-greptimedb-telemetry", "common-grpc", "common-grpc-expr", + "common-macro", "common-meta", "common-procedure", "common-procedure-test", @@ -5532,6 +5557,7 @@ dependencies = [ "common-catalog", "common-datasource", "common-error", + "common-macro", "common-procedure", "common-procedure-test", "common-query", @@ -6241,6 +6267,7 @@ dependencies = [ "common-datasource", "common-error", "common-grpc-expr", + "common-macro", "common-meta", "common-query", "common-recordbatch", @@ -6503,6 +6530,7 @@ dependencies = [ "async-trait", "common-catalog", "common-error", + "common-macro", "common-meta", "common-query", "common-telemetry", @@ -8626,6 +8654,7 @@ dependencies = [ "common-catalog", "common-error", "common-function", + "common-macro", "common-query", "common-recordbatch", "common-runtime", @@ -8916,6 +8945,7 @@ dependencies = [ "common-error", "common-grpc", "common-grpc-expr", + "common-macro", "common-mem-prof", "common-meta", "common-query", @@ -9272,6 +9302,7 @@ dependencies = [ "common-catalog", "common-datasource", "common-error", + "common-macro", "common-query", "common-time", "datafusion-sql", @@ -9536,6 +9567,7 @@ dependencies = [ "common-config", "common-datasource", "common-error", + "common-macro", "common-query", "common-recordbatch", "common-runtime", @@ -9583,6 +9615,7 @@ dependencies = [ "bytes", "common-base", "common-error", + "common-macro", "common-query", "common-recordbatch", "common-time", @@ -9718,6 +9751,7 @@ dependencies = [ "catalog", "common-catalog", "common-error", + "common-macro", "common-telemetry", "datafusion", "datafusion-common", @@ -9876,6 +9910,7 @@ dependencies = [ "common-catalog", "common-datasource", "common-error", + "common-macro", "common-procedure", "common-query", "common-recordbatch", diff --git a/Cargo.toml b/Cargo.toml index 426b07d468b2..a89c9f19d3f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,7 +78,7 @@ datafusion-substrait = { git = "https://github.com/waynexia/arrow-datafusion.git derive_builder = "0.12" futures = "0.3" futures-util = "0.3" -greptime-proto = { git = "https://github.com/GreptimeTeam/greptime-proto.git", rev = "115c1080773be8a819e50b257fece9f839a0c836" } +greptime-proto = { git = "https://github.com/GreptimeTeam/greptime-proto.git", rev = "693128abe9adc70ba636010a172c9da55b206bba" } humantime-serde = "1.1" itertools = "0.10" lazy_static = "1.4" diff --git a/src/api/Cargo.toml b/src/api/Cargo.toml index 05fb33785701..05e625e2c5aa 100644 --- a/src/api/Cargo.toml +++ b/src/api/Cargo.toml @@ -7,6 +7,7 @@ license.workspace = true [dependencies] common-base = { workspace = true } common-error = { workspace = true } +common-macro = { workspace = true } common-time = { workspace = true } datatypes = { workspace = true } greptime-proto.workspace = true diff --git a/src/api/src/error.rs b/src/api/src/error.rs index c67fc5f9aacb..77b3d54097d9 100644 --- a/src/api/src/error.rs +++ b/src/api/src/error.rs @@ -16,14 +16,16 @@ use std::any::Any; use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use datatypes::prelude::ConcreteDataType; use snafu::prelude::*; use snafu::Location; pub type Result = std::result::Result; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Unknown proto column datatype: {}", datatype))] UnknownColumnDataType { datatype: i32, location: Location }, diff --git a/src/auth/Cargo.toml b/src/auth/Cargo.toml index ae1c4a49ff58..3909d8078157 100644 --- a/src/auth/Cargo.toml +++ b/src/auth/Cargo.toml @@ -14,6 +14,7 @@ testing = [] api.workspace = true async-trait.workspace = true common-error.workspace = true +common-macro.workspace = true digest = "0.10" hex = { version = "0.4" } secrecy = { version = "0.8", features = ["serde", "alloc"] } diff --git a/src/auth/src/error.rs b/src/auth/src/error.rs index bba69dbca353..cc07f3d0aa41 100644 --- a/src/auth/src/error.rs +++ b/src/auth/src/error.rs @@ -14,10 +14,12 @@ use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use snafu::{Location, Snafu}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Invalid config value: {}, {}", value, msg))] InvalidConfig { value: String, msg: String }, @@ -30,7 +32,8 @@ pub enum Error { #[snafu(display("IO error"))] Io { - source: std::io::Error, + #[snafu(source)] + error: std::io::Error, location: Location, }, diff --git a/src/catalog/Cargo.toml b/src/catalog/Cargo.toml index b9ff8c19ae97..314a332672ea 100644 --- a/src/catalog/Cargo.toml +++ b/src/catalog/Cargo.toml @@ -16,6 +16,7 @@ async-trait = "0.1" common-catalog = { workspace = true } common-error = { workspace = true } common-grpc = { workspace = true } +common-macro = { workspace = true } common-meta = { workspace = true } common-query = { workspace = true } common-recordbatch = { workspace = true } diff --git a/src/catalog/src/error.rs b/src/catalog/src/error.rs index d6c708cdff49..599795337ef4 100644 --- a/src/catalog/src/error.rs +++ b/src/catalog/src/error.rs @@ -17,14 +17,16 @@ use std::fmt::Debug; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use datafusion::error::DataFusionError; use datatypes::prelude::ConcreteDataType; use snafu::{Location, Snafu}; use table::metadata::TableId; use tokio::task::JoinError; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to list catalogs"))] ListCatalogs { @@ -92,7 +94,8 @@ pub enum Error { #[snafu(display("Failed to deserialize value"))] ValueDeserialize { - source: serde_json::error::Error, + #[snafu(source)] + error: serde_json::error::Error, location: Location, }, @@ -142,7 +145,10 @@ pub enum Error { }, #[snafu(display("Failed to open table in parallel"))] - ParallelOpenTable { source: JoinError }, + ParallelOpenTable { + #[snafu(source)] + error: JoinError, + }, #[snafu(display("Table not found while opening table, table info: {}", table_info))] TableNotFound { @@ -213,7 +219,8 @@ pub enum Error { #[snafu(display("msg: {}", msg))] Datafusion { msg: String, - source: DataFusionError, + #[snafu(source)] + error: DataFusionError, location: Location, }, diff --git a/src/client/Cargo.toml b/src/client/Cargo.toml index dde80a01943b..72942cd3a3d9 100644 --- a/src/client/Cargo.toml +++ b/src/client/Cargo.toml @@ -16,6 +16,7 @@ common-base = { workspace = true } common-catalog = { workspace = true } common-error = { workspace = true } common-grpc = { workspace = true } +common-macro = { workspace = true } common-meta = { workspace = true } common-query = { workspace = true } common-recordbatch = { workspace = true } diff --git a/src/client/examples/stream_ingest.rs b/src/client/examples/stream_ingest.rs index 7b67cf33931e..94f9773096b9 100644 --- a/src/client/examples/stream_ingest.rs +++ b/src/client/examples/stream_ingest.rs @@ -42,14 +42,14 @@ async fn run() { .insert(vec![to_insert_request(weather_records_1())]) .await { - error!("Error: {e}"); + error!("Error: {e:?}"); } if let Err(e) = stream_inserter .insert(vec![to_insert_request(weather_records_2())]) .await { - error!("Error: {e}"); + error!("Error: {e:?}"); } let result = stream_inserter.finish().await; @@ -59,7 +59,7 @@ async fn run() { info!("Rows written: {rows}"); } Err(e) => { - error!("Error: {e}"); + error!("Error: {e:?}"); } }; } diff --git a/src/client/src/database.rs b/src/client/src/database.rs index bb792de47b21..7e4c33a07417 100644 --- a/src/client/src/database.rs +++ b/src/client/src/database.rs @@ -276,7 +276,7 @@ impl Database { source: BoxedError::new(ServerSnafu { code, msg }.build()), }; logging::error!( - "Failed to do Flight get, addr: {}, code: {}, source: {}", + "Failed to do Flight get, addr: {}, code: {}, source: {:?}", client.addr(), tonic_code, error diff --git a/src/client/src/error.rs b/src/client/src/error.rs index f0676da7b6ca..6b25e5c58ac3 100644 --- a/src/client/src/error.rs +++ b/src/client/src/error.rs @@ -17,11 +17,13 @@ use std::any::Any; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; use common_error::{GREPTIME_ERROR_CODE, GREPTIME_ERROR_MSG}; +use common_macro::stack_trace_debug; use snafu::{Location, Snafu}; use tonic::{Code, Status}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Illegal Flight messages, reason: {}", reason))] IllegalFlightMessages { reason: String, location: Location }, diff --git a/src/cmd/Cargo.toml b/src/cmd/Cargo.toml index c83f65f7488e..d04eb8f86265 100644 --- a/src/cmd/Cargo.toml +++ b/src/cmd/Cargo.toml @@ -26,6 +26,7 @@ common-base = { workspace = true } common-catalog = { workspace = true } common-config = { workspace = true } common-error = { workspace = true } +common-macro = { workspace = true } common-meta = { workspace = true } common-procedure = { workspace = true } common-query = { workspace = true } diff --git a/src/cmd/src/error.rs b/src/cmd/src/error.rs index fea82b568daf..8631eb7f58f0 100644 --- a/src/cmd/src/error.rs +++ b/src/cmd/src/error.rs @@ -16,12 +16,14 @@ use std::any::Any; use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use config::ConfigError; use rustyline::error::ReadlineError; use snafu::{Location, Snafu}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to create default catalog and schema"))] InitMetadata { @@ -101,13 +103,15 @@ pub enum Error { #[snafu(display("Cannot create REPL"))] ReplCreation { - source: ReadlineError, + #[snafu(source)] + error: ReadlineError, location: Location, }, #[snafu(display("Error reading command"))] Readline { - source: ReadlineError, + #[snafu(source)] + error: ReadlineError, location: Location, }, @@ -157,7 +161,8 @@ pub enum Error { #[snafu(display("Failed to load layered config"))] LoadLayeredConfig { - source: ConfigError, + #[snafu(source)] + error: ConfigError, location: Location, }, @@ -170,7 +175,8 @@ pub enum Error { #[snafu(display("Failed to connect to Etcd at {etcd_addr}"))] ConnectEtcd { etcd_addr: String, - source: etcd_client::Error, + #[snafu(source)] + error: etcd_client::Error, location: Location, }, } diff --git a/src/common/base/Cargo.toml b/src/common/base/Cargo.toml index fc319981a03e..2a0030b33beb 100644 --- a/src/common/base/Cargo.toml +++ b/src/common/base/Cargo.toml @@ -9,6 +9,7 @@ anymap = "1.0.0-beta.2" bitvec = "1.0" bytes = { version = "1.1", features = ["serde"] } common-error = { workspace = true } +common-macro = { workspace = true } paste = "1.0" serde = { version = "1.0", features = ["derive"] } snafu.workspace = true diff --git a/src/common/base/src/buffer.rs b/src/common/base/src/buffer.rs index 34f6f63491b0..b472bbf5380e 100644 --- a/src/common/base/src/buffer.rs +++ b/src/common/base/src/buffer.rs @@ -17,11 +17,13 @@ use std::io::{Read, Write}; use bytes::{Buf, BufMut, BytesMut}; use common_error::ext::ErrorExt; +use common_macro::stack_trace_debug; use paste::paste; use snafu::{ensure, Location, ResultExt, Snafu}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display( "Destination buffer overflow, src_len: {}, dst_len: {}", @@ -39,7 +41,8 @@ pub enum Error { #[snafu(display("IO operation reach EOF"))] Eof { - source: std::io::Error, + #[snafu(source)] + error: std::io::Error, location: Location, }, } diff --git a/src/common/catalog/Cargo.toml b/src/common/catalog/Cargo.toml index 23f498c993ba..e3b9fa5dd72b 100644 --- a/src/common/catalog/Cargo.toml +++ b/src/common/catalog/Cargo.toml @@ -6,6 +6,7 @@ license.workspace = true [dependencies] common-error = { workspace = true } +common-macro = { workspace = true } serde.workspace = true serde_json = "1.0" snafu = { version = "0.7", features = ["backtraces"] } diff --git a/src/common/catalog/src/error.rs b/src/common/catalog/src/error.rs index 2ded9e47a576..46166b1ccee5 100644 --- a/src/common/catalog/src/error.rs +++ b/src/common/catalog/src/error.rs @@ -16,10 +16,12 @@ use std::any::Any; use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use snafu::{Location, Snafu}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Invalid full table name: {}", table_name))] InvalidFullTableName { diff --git a/src/common/datasource/Cargo.toml b/src/common/datasource/Cargo.toml index edb327519ab0..e6bff6953876 100644 --- a/src/common/datasource/Cargo.toml +++ b/src/common/datasource/Cargo.toml @@ -18,6 +18,7 @@ async-compression = { version = "0.3", features = [ async-trait.workspace = true bytes = "1.1" common-error = { workspace = true } +common-macro = { workspace = true } common-runtime = { workspace = true } datafusion.workspace = true derive_builder.workspace = true diff --git a/src/common/datasource/src/error.rs b/src/common/datasource/src/error.rs index ab1e918100d3..f8ab4a30c634 100644 --- a/src/common/datasource/src/error.rs +++ b/src/common/datasource/src/error.rs @@ -17,12 +17,14 @@ use std::any::Any; use arrow_schema::ArrowError; use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use datafusion::parquet::errors::ParquetError; use snafu::{Location, Snafu}; use url::ParseError; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Unsupported compression type: {}", compression_type))] UnsupportedCompressionType { @@ -46,83 +48,96 @@ pub enum Error { #[snafu(display("Invalid url: {}", url))] InvalidUrl { url: String, - source: ParseError, + #[snafu(source)] + error: ParseError, location: Location, }, #[snafu(display("Failed to build backend"))] BuildBackend { - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, location: Location, }, #[snafu(display("Failed to build orc reader"))] OrcReader { location: Location, - source: orc_rust::error::Error, + #[snafu(source)] + error: orc_rust::error::Error, }, #[snafu(display("Failed to read object from path: {}", path))] ReadObject { path: String, location: Location, - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, }, #[snafu(display("Failed to write object to path: {}", path))] WriteObject { path: String, location: Location, - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, }, #[snafu(display("Failed to write"))] AsyncWrite { - source: std::io::Error, + #[snafu(source)] + error: std::io::Error, location: Location, }, #[snafu(display("Failed to write record batch"))] WriteRecordBatch { location: Location, - source: ArrowError, + #[snafu(source)] + error: ArrowError, }, #[snafu(display("Failed to encode record batch"))] EncodeRecordBatch { location: Location, - source: ParquetError, + #[snafu(source)] + error: ParquetError, }, #[snafu(display("Failed to read record batch"))] ReadRecordBatch { location: Location, - source: datafusion::error::DataFusionError, + #[snafu(source)] + error: datafusion::error::DataFusionError, }, #[snafu(display("Failed to read parquet"))] ReadParquetSnafu { location: Location, - source: datafusion::parquet::errors::ParquetError, + #[snafu(source)] + error: datafusion::parquet::errors::ParquetError, }, #[snafu(display("Failed to convert parquet to schema"))] ParquetToSchema { location: Location, - source: datafusion::parquet::errors::ParquetError, + #[snafu(source)] + error: datafusion::parquet::errors::ParquetError, }, #[snafu(display("Failed to infer schema from file"))] InferSchema { location: Location, - source: arrow_schema::ArrowError, + #[snafu(source)] + error: arrow_schema::ArrowError, }, #[snafu(display("Failed to list object in path: {}", path))] ListObjects { path: String, location: Location, - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, }, #[snafu(display("Invalid connection: {}", msg))] @@ -131,7 +146,8 @@ pub enum Error { #[snafu(display("Failed to join handle"))] JoinHandle { location: Location, - source: tokio::task::JoinError, + #[snafu(source)] + error: tokio::task::JoinError, }, #[snafu(display("Failed to parse format {} with value: {}", key, value))] @@ -143,7 +159,8 @@ pub enum Error { #[snafu(display("Failed to merge schema"))] MergeSchema { - source: arrow_schema::ArrowError, + #[snafu(source)] + error: arrow_schema::ArrowError, location: Location, }, diff --git a/src/common/error/src/ext.rs b/src/common/error/src/ext.rs index 261f8f773699..b840b2911ea0 100644 --- a/src/common/error/src/ext.rs +++ b/src/common/error/src/ext.rs @@ -13,11 +13,12 @@ // limitations under the License. use std::any::Any; +use std::sync::Arc; use crate::status_code::StatusCode; /// Extension to [`Error`](std::error::Error) in std. -pub trait ErrorExt: std::error::Error { +pub trait ErrorExt: std::error::Error + StackError { /// Map this error to [StatusCode]. fn status_code(&self) -> StatusCode { StatusCode::Unknown @@ -35,6 +36,32 @@ pub trait ErrorExt: std::error::Error { fn as_any(&self) -> &dyn Any; } +pub trait StackError { + fn debug_fmt(&self, layer: usize, buf: &mut Vec); + + fn next(&self) -> Option<&dyn StackError>; +} + +impl StackError for Arc { + fn debug_fmt(&self, layer: usize, buf: &mut Vec) { + self.as_ref().debug_fmt(layer, buf) + } + + fn next(&self) -> Option<&dyn StackError> { + self.as_ref().next() + } +} + +impl StackError for Box { + fn debug_fmt(&self, layer: usize, buf: &mut Vec) { + self.as_ref().debug_fmt(layer, buf) + } + + fn next(&self) -> Option<&dyn StackError> { + self.as_ref().next() + } +} + /// An opaque boxed error based on errors that implement [ErrorExt] trait. pub struct BoxedError { inner: Box, @@ -90,6 +117,16 @@ impl crate::snafu::ErrorCompat for BoxedError { } } +impl StackError for BoxedError { + fn debug_fmt(&self, layer: usize, buf: &mut Vec) { + self.inner.debug_fmt(layer, buf) + } + + fn next(&self) -> Option<&dyn StackError> { + self.inner.next() + } +} + /// Error type with plain error message #[derive(Debug)] pub struct PlainError { @@ -128,3 +165,13 @@ impl crate::ext::ErrorExt for PlainError { self as _ } } + +impl StackError for PlainError { + fn debug_fmt(&self, layer: usize, buf: &mut Vec) { + buf.push(format!("{}: {}", layer, self.msg)) + } + + fn next(&self) -> Option<&dyn StackError> { + None + } +} diff --git a/src/common/error/src/format.rs b/src/common/error/src/format.rs index 9bf219640985..341e4829e954 100644 --- a/src/common/error/src/format.rs +++ b/src/common/error/src/format.rs @@ -50,6 +50,7 @@ mod tests { use snafu::{GenerateImplicitData, Location}; use super::*; + use crate::ext::StackError; #[derive(Debug, Snafu)] #[snafu(display("This is a leaf error"))] @@ -65,6 +66,14 @@ mod tests { } } + impl StackError for Leaf { + fn debug_fmt(&self, _: usize, _: &mut Vec) {} + + fn next(&self) -> Option<&dyn StackError> { + None + } + } + #[derive(Debug, Snafu)] #[snafu(display("This is a leaf with location"))] struct LeafWithLocation { @@ -81,6 +90,14 @@ mod tests { } } + impl StackError for LeafWithLocation { + fn debug_fmt(&self, _: usize, _: &mut Vec) {} + + fn next(&self) -> Option<&dyn StackError> { + None + } + } + #[derive(Debug, Snafu)] #[snafu(display("Internal error"))] struct Internal { @@ -99,6 +116,17 @@ mod tests { } } + impl StackError for Internal { + fn debug_fmt(&self, layer: usize, buf: &mut Vec) { + buf.push(format!("{}: Internal error, at {}", layer, self.location)); + self.source.debug_fmt(layer + 1, buf); + } + + fn next(&self) -> Option<&dyn StackError> { + Some(&self.source) + } + } + #[test] fn test_debug_format() { let err = Leaf; diff --git a/src/common/error/src/mock.rs b/src/common/error/src/mock.rs index a3f061fd6609..2781149b1268 100644 --- a/src/common/error/src/mock.rs +++ b/src/common/error/src/mock.rs @@ -19,7 +19,7 @@ use std::fmt; use snafu::Location; -use crate::ext::ErrorExt; +use crate::ext::{ErrorExt, StackError}; use crate::status_code::StatusCode; /// A mock error mainly for test. @@ -69,3 +69,11 @@ impl ErrorExt for MockError { self } } + +impl StackError for MockError { + fn debug_fmt(&self, _: usize, _: &mut Vec) {} + + fn next(&self) -> Option<&dyn StackError> { + None + } +} diff --git a/src/common/grpc-expr/Cargo.toml b/src/common/grpc-expr/Cargo.toml index 0143b5628373..6cd42995266e 100644 --- a/src/common/grpc-expr/Cargo.toml +++ b/src/common/grpc-expr/Cargo.toml @@ -10,6 +10,7 @@ async-trait.workspace = true common-base = { workspace = true } common-catalog = { workspace = true } common-error = { workspace = true } +common-macro = { workspace = true } common-query = { workspace = true } common-telemetry = { workspace = true } common-time = { workspace = true } diff --git a/src/common/grpc-expr/src/error.rs b/src/common/grpc-expr/src/error.rs index 8456d05db862..15a5a3ffc794 100644 --- a/src/common/grpc-expr/src/error.rs +++ b/src/common/grpc-expr/src/error.rs @@ -16,10 +16,12 @@ use std::any::Any; use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use snafu::{Location, Snafu}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Illegal delete request, reason: {reason}"))] IllegalDeleteRequest { reason: String, location: Location }, diff --git a/src/common/grpc/Cargo.toml b/src/common/grpc/Cargo.toml index 416566506921..81e935f1a39f 100644 --- a/src/common/grpc/Cargo.toml +++ b/src/common/grpc/Cargo.toml @@ -11,6 +11,7 @@ async-trait = "0.1" backtrace = "0.3" common-base = { workspace = true } common-error = { workspace = true } +common-macro = { workspace = true } common-recordbatch = { workspace = true } common-runtime = { workspace = true } common-telemetry = { workspace = true } diff --git a/src/common/grpc/src/error.rs b/src/common/grpc/src/error.rs index a92fbcf0a939..e6ddab8c126c 100644 --- a/src/common/grpc/src/error.rs +++ b/src/common/grpc/src/error.rs @@ -17,19 +17,22 @@ use std::io; use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use snafu::{Location, Snafu}; pub type Result = std::result::Result; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Invalid client tls config, {}", msg))] InvalidTlsConfig { msg: String }, #[snafu(display("Invalid config file path"))] InvalidConfigFilePath { - source: io::Error, + #[snafu(source)] + error: io::Error, location: Location, }, @@ -48,7 +51,8 @@ pub enum Error { #[snafu(display("Failed to create gRPC channel"))] CreateChannel { - source: tonic::transport::Error, + #[snafu(source)] + error: tonic::transport::Error, location: Location, }, @@ -63,7 +67,8 @@ pub enum Error { #[snafu(display("Failed to decode FlightData"))] DecodeFlightData { - source: api::DecodeError, + #[snafu(source)] + error: api::DecodeError, location: Location, }, diff --git a/src/common/macro/Cargo.toml b/src/common/macro/Cargo.toml index c0ab6b0a5be3..36f2ae4a1e87 100644 --- a/src/common/macro/Cargo.toml +++ b/src/common/macro/Cargo.toml @@ -13,6 +13,15 @@ common-telemetry = { workspace = true } proc-macro2 = "1.0.66" quote = "1.0" syn = "1.0" +syn2 = { version = "2.0", package = "syn", features = [ + "derive", + "parsing", + "printing", + "clone-impls", + "proc-macro", + "extra-traits", + "full", +] } [dev-dependencies] arc-swap = "1.0" diff --git a/src/common/macro/src/lib.rs b/src/common/macro/src/lib.rs index d374440ff323..f33f308a86a9 100644 --- a/src/common/macro/src/lib.rs +++ b/src/common/macro/src/lib.rs @@ -15,6 +15,7 @@ mod aggr_func; mod print_caller; mod range_fn; +mod stack_trace_debug; use aggr_func::{impl_aggr_func_type_store, impl_as_aggr_func_creator}; use print_caller::process_print_caller; @@ -87,3 +88,23 @@ pub fn range_fn(args: TokenStream, input: TokenStream) -> TokenStream { pub fn print_caller(args: TokenStream, input: TokenStream) -> TokenStream { process_print_caller(args, input) } + +/// Attribute macro to derive [std::fmt::Debug] for the annotated `Error` type. +/// +/// The generated `Debug` implementation will print the error in a stack trace style. E.g.: +/// ```plaintext +/// 0: Foo error, at src/common/catalog/src/error.rs:80:10 +/// 1: Bar error, at src/common/function/src/error.rs:90:10 +/// 2: Root cause, invalid table name, at src/common/catalog/src/error.rs:100:10 +/// ``` +/// +/// Notes on using this macro: +/// - `#[snafu(display)]` must present on each enum variants, +/// and should not include `location` and `source`. +/// - Only our internal error can be named `source`. +/// All external error should be `error` with an `#[snafu(source)]` annotation. +/// - `common_error` crate must be accessible. +#[proc_macro_attribute] +pub fn stack_trace_debug(args: TokenStream, input: TokenStream) -> TokenStream { + stack_trace_debug::stack_trace_style_impl(args.into(), input.into()).into() +} diff --git a/src/common/macro/src/stack_trace_debug.rs b/src/common/macro/src/stack_trace_debug.rs new file mode 100644 index 000000000000..2e6f2d15946a --- /dev/null +++ b/src/common/macro/src/stack_trace_debug.rs @@ -0,0 +1,278 @@ +// Copyright 2023 Greptime Team +// +// 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. + +//! implement `::common_error::ext::StackError` + +use proc_macro2::{Span, TokenStream as TokenStream2}; +use quote::{quote, quote_spanned}; +use syn2::spanned::Spanned; +use syn2::{parenthesized, Attribute, Ident, ItemEnum, Variant}; + +pub fn stack_trace_style_impl(args: TokenStream2, input: TokenStream2) -> TokenStream2 { + let input_cloned: TokenStream2 = input.clone(); + + let error_enum_definition: ItemEnum = syn2::parse2(input_cloned).unwrap(); + let enum_name = error_enum_definition.ident; + + let mut variants = vec![]; + + for error_variant in error_enum_definition.variants { + let variant = ErrorVariant::from_enum_variant(error_variant); + variants.push(variant); + } + + let debug_fmt_fn = build_debug_fmt_impl(enum_name.clone(), variants.clone()); + let next_fn = build_next_impl(enum_name.clone(), variants); + let debug_impl = build_debug_impl(enum_name.clone()); + + quote! { + #args + #input + + impl ::common_error::ext::StackError for #enum_name { + #debug_fmt_fn + #next_fn + } + + #debug_impl + } +} + +/// Generate `debug_fmt` fn. +/// +/// The generated fn will be like: +/// ```rust, ignore +/// fn debug_fmt(&self, layer: usize, buf: &mut Vec); +/// ``` +fn build_debug_fmt_impl(enum_name: Ident, variants: Vec) -> TokenStream2 { + let match_arms = variants + .iter() + .map(|v| v.to_debug_match_arm()) + .collect::>(); + + quote! { + fn debug_fmt(&self, layer: usize, buf: &mut Vec) { + use #enum_name::*; + match self { + #(#match_arms)* + } + } + } +} + +/// Generate `next` fn. +/// +/// The generated fn will be like: +/// ```rust, ignore +/// fn next(&self) -> Option<&dyn ::common_error::ext::StackError>; +/// ``` +fn build_next_impl(enum_name: Ident, variants: Vec) -> TokenStream2 { + let match_arms = variants + .iter() + .map(|v| v.to_next_match_arm()) + .collect::>(); + + quote! { + fn next(&self) -> Option<&dyn ::common_error::ext::StackError> { + use #enum_name::*; + match self { + #(#match_arms)* + } + } + } +} + +/// Implement [std::fmt::Debug] via `debug_fmt` +fn build_debug_impl(enum_name: Ident) -> TokenStream2 { + quote! { + impl std::fmt::Debug for #enum_name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use ::common_error::ext::StackError; + let mut buf = vec![]; + self.debug_fmt(0, &mut buf); + write!(f, "{}", buf.join("\n")) + } + } + } +} + +#[derive(Clone, Debug)] +struct ErrorVariant { + name: Ident, + fields: Vec, + has_location: bool, + has_source: bool, + has_external_cause: bool, + display: TokenStream2, + span: Span, + cfg_attr: Option, +} + +impl ErrorVariant { + /// Construct self from [Variant] + fn from_enum_variant(variant: Variant) -> Self { + let span = variant.span(); + let mut has_location = false; + let mut has_source = false; + let mut has_external_cause = false; + + for field in &variant.fields { + if let Some(ident) = &field.ident { + if ident == "location" { + has_location = true; + } else if ident == "source" { + has_source = true; + } else if ident == "error" { + has_external_cause = true; + } + } + } + + let mut display = None; + let mut cfg_attr = None; + for attr in variant.attrs { + if attr.path().is_ident("snafu") { + attr.parse_nested_meta(|meta| { + if meta.path.is_ident("display") { + let content; + parenthesized!(content in meta.input); + let display_ts: TokenStream2 = content.parse()?; + display = Some(display_ts); + Ok(()) + } else { + Err(meta.error("unrecognized repr")) + } + }) + .expect("Each error should contains a display attribute"); + } + + if attr.path().is_ident("cfg") { + cfg_attr = Some(attr); + } + } + + let field_ident = variant + .fields + .iter() + .map(|f| f.ident.clone().unwrap_or_else(|| Ident::new("_", f.span()))) + .collect(); + + Self { + name: variant.ident, + fields: field_ident, + has_location, + has_source, + has_external_cause, + display: display.unwrap(), + span, + cfg_attr, + } + } + + /// Convert self into an match arm that will be used in [build_debug_impl]. + /// + /// The generated match arm will be like: + /// ```rust, ignore + /// ErrorKindWithSource { source, .. } => { + /// debug_fmt(source, layer + 1, buf); + /// }, + /// ErrorKindWithoutSource { .. } => { + /// buf.push(format!("{layer}: {}, at {}", format!(#display), location))); + /// } + /// ``` + /// + /// The generated code assumes fn `debug_fmt`, var `layer`, var `buf` are in scope. + fn to_debug_match_arm(&self) -> TokenStream2 { + let name = &self.name; + let fields = &self.fields; + let display = &self.display; + let cfg = if let Some(cfg) = &self.cfg_attr { + quote_spanned!(cfg.span() => #cfg) + } else { + quote! {} + }; + + match (self.has_location, self.has_source, self.has_external_cause) { + (true, true, _) => quote_spanned! { + self.span => #cfg #[allow(unused_variables)] #name { #(#fields),*, } => { + buf.push(format!("{layer}: {}, at {}", format!(#display), location)); + source.debug_fmt(layer + 1, buf); + }, + }, + (true, false, true) => quote_spanned! { + self.span => #cfg #[allow(unused_variables)] #name { #(#fields),* } => { + buf.push(format!("{layer}: {}, at {}", format!(#display), location)); + buf.push(format!("{}: {:?}", layer + 1, error)); + }, + }, + (true, false, false) => quote_spanned! { + self.span => #cfg #[allow(unused_variables)] #name { #(#fields),* } => { + buf.push(format!("{layer}: {}, at {}", format!(#display), location)); + }, + }, + (false, true, _) => quote_spanned! { + self.span => #cfg #[allow(unused_variables)] #name { #(#fields),* } => { + buf.push(format!("{layer}: {}", format!(#display))); + source.debug_fmt(layer + 1, buf); + }, + }, + (false, false, true) => quote_spanned! { + self.span => #cfg #[allow(unused_variables)] #name { #(#fields),* } => { + buf.push(format!("{layer}: {}", format!(#display))); + buf.push(format!("{}: {:?}", layer + 1, error)); + }, + }, + (false, false, false) => quote_spanned! { + self.span => #cfg #[allow(unused_variables)] #name { #(#fields),* } => { + buf.push(format!("{layer}: {}", format!(#display))); + }, + }, + } + } + + /// Convert self into an match arm that will be used in [build_next_impl]. + /// + /// The generated match arm will be like: + /// ```rust, ignore + /// ErrorKindWithSource { source, .. } => { + /// Some(source) + /// }, + /// ErrorKindWithoutSource { .. } => { + /// None + /// } + /// ``` + fn to_next_match_arm(&self) -> TokenStream2 { + let name = &self.name; + let fields = &self.fields; + let cfg = if let Some(cfg) = &self.cfg_attr { + quote_spanned!(cfg.span() => #cfg) + } else { + quote! {} + }; + + if self.has_source { + quote_spanned! { + self.span => #cfg #[allow(unused_variables)] #name { #(#fields),* } => { + Some(source) + }, + } + } else { + quote_spanned! { + self.span => #cfg #[allow(unused_variables)] #name { #(#fields),* } =>{ + None + } + } + } + } +} diff --git a/src/common/mem-prof/Cargo.toml b/src/common/mem-prof/Cargo.toml index 211f941cabd7..923e169fae35 100644 --- a/src/common/mem-prof/Cargo.toml +++ b/src/common/mem-prof/Cargo.toml @@ -6,6 +6,7 @@ license.workspace = true [dependencies] common-error = { workspace = true } +common-macro = { workspace = true } snafu.workspace = true tempfile = "3.4" tokio.workspace = true diff --git a/src/common/mem-prof/src/error.rs b/src/common/mem-prof/src/error.rs index db83bb86ed79..55b2676ca652 100644 --- a/src/common/mem-prof/src/error.rs +++ b/src/common/mem-prof/src/error.rs @@ -16,14 +16,16 @@ use std::any::Any; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use snafu::Snafu; pub type Result = std::result::Result; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { - #[snafu(display(""))] + #[snafu(display("Internal error"))] Internal { source: BoxedError }, #[snafu(display("Memory profiling is not supported"))] diff --git a/src/common/mem-prof/src/jemalloc/error.rs b/src/common/mem-prof/src/jemalloc/error.rs index 8aaf1d3a3057..a0e0f2ede068 100644 --- a/src/common/mem-prof/src/jemalloc/error.rs +++ b/src/common/mem-prof/src/jemalloc/error.rs @@ -17,13 +17,18 @@ use std::path::PathBuf; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use snafu::{Location, Snafu}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to read OPT_PROF"))] - ReadOptProf { source: tikv_jemalloc_ctl::Error }, + ReadOptProf { + #[snafu(source)] + error: tikv_jemalloc_ctl::Error, + }, #[snafu(display("Memory profiling is not enabled"))] ProfilingNotEnabled, @@ -34,13 +39,15 @@ pub enum Error { #[snafu(display("Failed to open temp file: {}", path))] OpenTempFile { path: String, - source: std::io::Error, + #[snafu(source)] + error: std::io::Error, }, #[snafu(display("Failed to dump profiling data to temp file: {:?}", path))] DumpProfileData { path: PathBuf, - source: tikv_jemalloc_ctl::Error, + #[snafu(source)] + error: tikv_jemalloc_ctl::Error, }, } diff --git a/src/common/meta/Cargo.toml b/src/common/meta/Cargo.toml index f7c4b3435f8b..98aa010a4d65 100644 --- a/src/common/meta/Cargo.toml +++ b/src/common/meta/Cargo.toml @@ -15,6 +15,7 @@ async-trait.workspace = true common-catalog = { workspace = true } common-error = { workspace = true } common-grpc-expr.workspace = true +common-macro = { workspace = true } common-procedure = { workspace = true } common-recordbatch = { workspace = true } common-runtime = { workspace = true } diff --git a/src/common/meta/src/ddl.rs b/src/common/meta/src/ddl.rs index f84825252435..4ec389199f91 100644 --- a/src/common/meta/src/ddl.rs +++ b/src/common/meta/src/ddl.rs @@ -28,6 +28,7 @@ use crate::rpc::router::RegionRoute; pub mod alter_table; pub mod create_table; pub mod drop_table; +pub mod truncate_table; pub mod utils; #[derive(Debug, Default)] diff --git a/src/common/meta/src/ddl/create_table.rs b/src/common/meta/src/ddl/create_table.rs index 87a6cf0dc046..975c2aa471fb 100644 --- a/src/common/meta/src/ddl/create_table.rs +++ b/src/common/meta/src/ddl/create_table.rs @@ -199,8 +199,8 @@ impl CreateTableProcedure { for request in requests { let request = RegionRequest { header: Some(RegionRequestHeader { - trace_id: 0, - span_id: 0, + trace_id: common_telemetry::trace_id().unwrap_or_default(), + ..Default::default() }), body: Some(request), }; diff --git a/src/common/meta/src/ddl/drop_table.rs b/src/common/meta/src/ddl/drop_table.rs index f8c11324fa8e..9da7759cd006 100644 --- a/src/common/meta/src/ddl/drop_table.rs +++ b/src/common/meta/src/ddl/drop_table.rs @@ -156,8 +156,8 @@ impl DropTableProcedure { let request = RegionRequest { header: Some(RegionRequestHeader { - trace_id: 0, - span_id: 0, + trace_id: common_telemetry::trace_id().unwrap_or_default(), + ..Default::default() }), body: Some(region_request::Body::Drop(PbDropRegionRequest { region_id: region_id.as_u64(), diff --git a/src/common/meta/src/ddl/truncate_table.rs b/src/common/meta/src/ddl/truncate_table.rs new file mode 100644 index 000000000000..831b41a631f0 --- /dev/null +++ b/src/common/meta/src/ddl/truncate_table.rs @@ -0,0 +1,234 @@ +// Copyright 2023 Greptime Team +// +// 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 api::v1::region::{ + region_request, RegionRequest, RegionRequestHeader, TruncateRequest as PbTruncateRegionRequest, +}; +use async_trait::async_trait; +use common_procedure::error::{FromJsonSnafu, ToJsonSnafu}; +use common_procedure::{ + Context as ProcedureContext, LockKey, Procedure, Result as ProcedureResult, Status, +}; +use common_telemetry::debug; +use futures::future::join_all; +use serde::{Deserialize, Serialize}; +use snafu::{ensure, ResultExt}; +use store_api::storage::RegionId; +use strum::AsRefStr; +use table::engine::TableReference; +use table::metadata::{RawTableInfo, TableId}; + +use super::utils::handle_retry_error; +use crate::ddl::utils::handle_operate_region_error; +use crate::ddl::DdlContext; +use crate::error::{Result, TableNotFoundSnafu}; +use crate::key::table_info::TableInfoValue; +use crate::key::table_name::TableNameKey; +use crate::metrics; +use crate::rpc::ddl::TruncateTableTask; +use crate::rpc::router::{find_leader_regions, find_leaders, RegionRoute}; +use crate::table_name::TableName; + +pub struct TruncateTableProcedure { + context: DdlContext, + data: TruncateTableData, +} + +#[async_trait] +impl Procedure for TruncateTableProcedure { + fn type_name(&self) -> &str { + Self::TYPE_NAME + } + + async fn execute(&mut self, _ctx: &ProcedureContext) -> ProcedureResult { + let state = &self.data.state; + + let _timer = common_telemetry::timer!( + metrics::METRIC_META_PROCEDURE_TRUNCATE_TABLE, + &[("step", state.as_ref().to_string())] + ); + + match self.data.state { + TruncateTableState::Prepare => self.on_prepare().await, + TruncateTableState::DatanodeTruncateRegions => { + self.on_datanode_truncate_regions().await + } + } + .map_err(handle_retry_error) + } + + fn dump(&self) -> ProcedureResult { + serde_json::to_string(&self.data).context(ToJsonSnafu) + } + + fn lock_key(&self) -> LockKey { + let table_ref = &self.data.table_ref(); + let key = common_catalog::format_full_table_name( + table_ref.catalog, + table_ref.schema, + table_ref.table, + ); + + LockKey::single(key) + } +} + +impl TruncateTableProcedure { + pub(crate) const TYPE_NAME: &'static str = "metasrv-procedure::TruncateTable"; + + pub(crate) fn new( + cluster_id: u64, + task: TruncateTableTask, + table_info_value: TableInfoValue, + region_routes: Vec, + context: DdlContext, + ) -> Self { + Self { + context, + data: TruncateTableData::new(cluster_id, task, table_info_value, region_routes), + } + } + + pub(crate) fn from_json(json: &str, context: DdlContext) -> ProcedureResult { + let data = serde_json::from_str(json).context(FromJsonSnafu)?; + Ok(Self { context, data }) + } + + // Checks whether the table exists. + async fn on_prepare(&mut self) -> Result { + let table_ref = &self.data.table_ref(); + + let manager = &self.context.table_metadata_manager; + + let exist = manager + .table_name_manager() + .exists(TableNameKey::new( + table_ref.catalog, + table_ref.schema, + table_ref.table, + )) + .await?; + + ensure!( + exist, + TableNotFoundSnafu { + table_name: table_ref.to_string() + } + ); + + self.data.state = TruncateTableState::DatanodeTruncateRegions; + + Ok(Status::executing(true)) + } + + async fn on_datanode_truncate_regions(&mut self) -> Result { + let table_id = self.data.table_id(); + + let region_routes = &self.data.region_routes; + let leaders = find_leaders(region_routes); + let mut truncate_region_tasks = Vec::with_capacity(leaders.len()); + + for datanode in leaders { + let requester = self.context.datanode_manager.datanode(&datanode).await; + let regions = find_leader_regions(region_routes, &datanode); + + for region in regions { + let region_id = RegionId::new(table_id, region); + debug!( + "Truncating table {} region {} on Datanode {:?}", + self.data.table_ref(), + region_id, + datanode + ); + + let request = RegionRequest { + header: Some(RegionRequestHeader { + trace_id: common_telemetry::trace_id().unwrap_or_default(), + ..Default::default() + }), + body: Some(region_request::Body::Truncate(PbTruncateRegionRequest { + region_id: region_id.as_u64(), + })), + }; + + let datanode = datanode.clone(); + let requester = requester.clone(); + + truncate_region_tasks.push(async move { + if let Err(err) = requester.handle(request).await { + return Err(handle_operate_region_error(datanode)(err)); + } + Ok(()) + }); + } + } + + join_all(truncate_region_tasks) + .await + .into_iter() + .collect::>>()?; + + Ok(Status::Done) + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct TruncateTableData { + state: TruncateTableState, + cluster_id: u64, + task: TruncateTableTask, + table_info_value: TableInfoValue, + region_routes: Vec, +} + +impl TruncateTableData { + pub fn new( + cluster_id: u64, + task: TruncateTableTask, + table_info_value: TableInfoValue, + region_routes: Vec, + ) -> Self { + Self { + state: TruncateTableState::Prepare, + cluster_id, + task, + table_info_value, + region_routes, + } + } + + pub fn table_ref(&self) -> TableReference { + self.task.table_ref() + } + + pub fn table_name(&self) -> TableName { + self.task.table_name() + } + + fn table_info(&self) -> &RawTableInfo { + &self.table_info_value.table_info + } + + fn table_id(&self) -> TableId { + self.table_info().ident.table_id + } +} + +#[derive(Debug, Serialize, Deserialize, AsRefStr)] +enum TruncateTableState { + /// Prepares to truncate the table + Prepare, + /// Truncates regions on Datanode + DatanodeTruncateRegions, +} diff --git a/src/common/meta/src/ddl_manager.rs b/src/common/meta/src/ddl_manager.rs index aaa1e1c52104..62af640a3c57 100644 --- a/src/common/meta/src/ddl_manager.rs +++ b/src/common/meta/src/ddl_manager.rs @@ -15,7 +15,7 @@ use std::sync::Arc; use common_procedure::{watcher, ProcedureId, ProcedureManagerRef, ProcedureWithId}; -use common_telemetry::{error, info}; +use common_telemetry::info; use snafu::{OptionExt, ResultExt}; use crate::cache_invalidator::CacheInvalidatorRef; @@ -23,13 +23,14 @@ use crate::datanode_manager::DatanodeManagerRef; use crate::ddl::alter_table::AlterTableProcedure; use crate::ddl::create_table::CreateTableProcedure; use crate::ddl::drop_table::DropTableProcedure; +use crate::ddl::truncate_table::TruncateTableProcedure; use crate::ddl::{ DdlContext, DdlTaskExecutor, ExecutorContext, TableMetadataAllocatorContext, TableMetadataAllocatorRef, }; use crate::error::{ self, RegisterProcedureLoaderSnafu, Result, SubmitProcedureSnafu, TableNotFoundSnafu, - UnsupportedSnafu, WaitProcedureSnafu, + WaitProcedureSnafu, }; use crate::key::table_info::TableInfoValue; use crate::key::table_name::TableNameKey; @@ -122,6 +123,20 @@ impl DdlManager { ) .context(RegisterProcedureLoaderSnafu { type_name: AlterTableProcedure::TYPE_NAME, + })?; + + let context = self.create_context(); + + self.procedure_manager + .register_loader( + TruncateTableProcedure::TYPE_NAME, + Box::new(move |json| { + let context = context.clone(); + TruncateTableProcedure::from_json(json, context).map(|p| Box::new(p) as _) + }), + ) + .context(RegisterProcedureLoaderSnafu { + type_name: TruncateTableProcedure::TYPE_NAME, }) } @@ -183,15 +198,21 @@ impl DdlManager { &self, cluster_id: u64, truncate_table_task: TruncateTableTask, + table_info_value: TableInfoValue, region_routes: Vec, ) -> Result { - error!("Truncate table procedure is not supported, cluster_id = {}, truncate_table_task = {:?}, region_routes = {:?}", - cluster_id, truncate_table_task, region_routes); + let context = self.create_context(); + let procedure = TruncateTableProcedure::new( + cluster_id, + truncate_table_task, + table_info_value, + region_routes, + context, + ); - UnsupportedSnafu { - operation: "TRUNCATE TABLE", - } - .fail() + let procedure_with_id = ProcedureWithId::with_random_id(Box::new(procedure)); + + self.submit_procedure(procedure_with_id).await } async fn submit_procedure(&self, procedure_with_id: ProcedureWithId) -> Result { @@ -216,32 +237,34 @@ async fn handle_truncate_table_task( cluster_id: u64, truncate_table_task: TruncateTableTask, ) -> Result { - let truncate_table = &truncate_table_task.truncate_table; - let table_id = truncate_table - .table_id - .as_ref() - .context(error::UnexpectedSnafu { - err_msg: "expected table id ", - })? - .id; - + let table_id = truncate_table_task.table_id; + let table_metadata_manager = &ddl_manager.table_metadata_manager(); let table_ref = truncate_table_task.table_ref(); - let table_route_value = ddl_manager - .table_metadata_manager() - .table_route_manager() - .get(table_id) - .await? - .with_context(|| error::TableRouteNotFoundSnafu { - table_name: table_ref.to_string(), - })?; + let (table_info_value, table_route_value) = + table_metadata_manager.get_full_table_info(table_id).await?; + + let table_info_value = table_info_value.with_context(|| error::TableInfoNotFoundSnafu { + table_name: table_ref.to_string(), + })?; + + let table_route_value = table_route_value.with_context(|| error::TableRouteNotFoundSnafu { + table_name: table_ref.to_string(), + })?; let table_route = table_route_value.region_routes; let id = ddl_manager - .submit_truncate_table_task(cluster_id, truncate_table_task, table_route) + .submit_truncate_table_task( + cluster_id, + truncate_table_task, + table_info_value, + table_route, + ) .await?; + info!("Table: {table_id} is truncated via procedure_id {id:?}"); + Ok(SubmitDdlTaskResponse { key: id.to_string().into(), ..Default::default() diff --git a/src/common/meta/src/error.rs b/src/common/meta/src/error.rs index 605ee0aa46c5..4484a82a7cfb 100644 --- a/src/common/meta/src/error.rs +++ b/src/common/meta/src/error.rs @@ -16,6 +16,7 @@ use std::str::Utf8Error; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use serde_json::error::Error as JsonError; use snafu::{Location, Snafu}; use store_api::storage::RegionNumber; @@ -23,8 +24,9 @@ use table::metadata::TableId; use crate::peer::Peer; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to get sequence: {}", err_msg))] NextSequence { err_msg: String, location: Location }, @@ -83,7 +85,8 @@ pub enum Error { #[snafu(display("Failed to build table meta for table: {}", table_name))] BuildTableMeta { table_name: String, - source: table::metadata::TableMetaBuilderError, + #[snafu(source)] + error: table::metadata::TableMetaBuilderError, location: Location, }, @@ -102,19 +105,22 @@ pub enum Error { #[snafu(display("Failed to decode protobuf"))] DecodeProto { location: Location, - source: prost::DecodeError, + #[snafu(source)] + error: prost::DecodeError, }, #[snafu(display("Failed to encode object into json"))] EncodeJson { location: Location, - source: JsonError, + #[snafu(source)] + error: JsonError, }, #[snafu(display("Failed to decode object from json"))] DecodeJson { location: Location, - source: JsonError, + #[snafu(source)] + error: JsonError, }, #[snafu(display("Payload not exist"))] @@ -125,7 +131,8 @@ pub enum Error { #[snafu(display("Failed to serde json"))] SerdeJson { - source: serde_json::error::Error, + #[snafu(source)] + error: serde_json::error::Error, location: Location, }, @@ -177,7 +184,8 @@ pub enum Error { #[snafu(display("Failed to convert raw key to str"))] ConvertRawKey { location: Location, - source: Utf8Error, + #[snafu(source)] + error: Utf8Error, }, #[snafu(display("Table nod found, table: {}", table_name))] diff --git a/src/common/meta/src/metrics.rs b/src/common/meta/src/metrics.rs index 49535607af72..815c8aacb1cf 100644 --- a/src/common/meta/src/metrics.rs +++ b/src/common/meta/src/metrics.rs @@ -19,3 +19,4 @@ pub(crate) const METRIC_META_CREATE_SCHEMA: &str = "meta.create_schema"; pub(crate) const METRIC_META_PROCEDURE_CREATE_TABLE: &str = "meta.procedure.create_table"; pub(crate) const METRIC_META_PROCEDURE_DROP_TABLE: &str = "meta.procedure.drop_table"; pub(crate) const METRIC_META_PROCEDURE_ALTER_TABLE: &str = "meta.procedure.alter_table"; +pub(crate) const METRIC_META_PROCEDURE_TRUNCATE_TABLE: &str = "meta.procedure.truncate_table"; diff --git a/src/common/meta/src/rpc/ddl.rs b/src/common/meta/src/rpc/ddl.rs index d1ca0dea94f7..aed5fa1131b3 100644 --- a/src/common/meta/src/rpc/ddl.rs +++ b/src/common/meta/src/rpc/ddl.rs @@ -65,8 +65,18 @@ impl DdlTask { DdlTask::AlterTable(AlterTableTask { alter_table }) } - pub fn new_truncate_table(truncate_table: TruncateTableExpr) -> Self { - DdlTask::TruncateTable(TruncateTableTask { truncate_table }) + pub fn new_truncate_table( + catalog: String, + schema: String, + table: String, + table_id: TableId, + ) -> Self { + DdlTask::TruncateTable(TruncateTableTask { + catalog, + schema, + table, + table_id, + }) } } @@ -112,7 +122,12 @@ impl TryFrom for PbSubmitDdlTaskRequest { alter_table: Some(task.alter_table), }), DdlTask::TruncateTable(task) => Task::TruncateTableTask(PbTruncateTableTask { - truncate_table: Some(task.truncate_table), + truncate_table: Some(TruncateTableExpr { + catalog_name: task.catalog, + schema_name: task.schema, + table_name: task.table, + table_id: Some(api::v1::TableId { id: task.table_id }), + }), }), }; @@ -358,27 +373,28 @@ impl<'de> Deserialize<'de> for AlterTableTask { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct TruncateTableTask { - pub truncate_table: TruncateTableExpr, + pub catalog: String, + pub schema: String, + pub table: String, + pub table_id: TableId, } impl TruncateTableTask { pub fn table_ref(&self) -> TableReference { TableReference { - catalog: &self.truncate_table.catalog_name, - schema: &self.truncate_table.schema_name, - table: &self.truncate_table.table_name, + catalog: &self.catalog, + schema: &self.schema, + table: &self.table, } } pub fn table_name(&self) -> TableName { - let table = &self.truncate_table; - TableName { - catalog_name: table.catalog_name.to_string(), - schema_name: table.schema_name.to_string(), - table_name: table.table_name.to_string(), + catalog_name: self.catalog.to_string(), + schema_name: self.schema.to_string(), + table_name: self.table.to_string(), } } } @@ -388,39 +404,20 @@ impl TryFrom for TruncateTableTask { fn try_from(pb: PbTruncateTableTask) -> Result { let truncate_table = pb.truncate_table.context(error::InvalidProtoMsgSnafu { - err_msg: "expected truncate_table", + err_msg: "expected drop table", })?; - Ok(TruncateTableTask { truncate_table }) - } -} - -impl Serialize for TruncateTableTask { - fn serialize(&self, serializer: S) -> result::Result - where - S: serde::Serializer, - { - let pb = PbTruncateTableTask { - truncate_table: Some(self.truncate_table.clone()), - }; - let buf = pb.encode_to_vec(); - serializer.serialize_bytes(&buf) - } -} - -impl<'de> Deserialize<'de> for TruncateTableTask { - fn deserialize(deserializer: D) -> result::Result - where - D: serde::Deserializer<'de>, - { - let buf = Vec::::deserialize(deserializer)?; - let task: PbTruncateTableTask = PbTruncateTableTask::decode(&*buf) - .map_err(|err| serde::de::Error::custom(err.to_string()))?; - - let task = TruncateTableTask::try_from(task) - .map_err(|err| serde::de::Error::custom(err.to_string()))?; - - Ok(task) + Ok(Self { + catalog: truncate_table.catalog_name, + schema: truncate_table.schema_name, + table: truncate_table.table_name, + table_id: truncate_table + .table_id + .context(error::InvalidProtoMsgSnafu { + err_msg: "expected table_id", + })? + .id, + }) } } diff --git a/src/common/procedure/Cargo.toml b/src/common/procedure/Cargo.toml index 971653d136b9..21e8bb5beaff 100644 --- a/src/common/procedure/Cargo.toml +++ b/src/common/procedure/Cargo.toml @@ -9,6 +9,7 @@ async-stream.workspace = true async-trait.workspace = true backon = "0.4" common-error = { workspace = true } +common-macro = { workspace = true } common-runtime = { workspace = true } common-telemetry = { workspace = true } futures.workspace = true diff --git a/src/common/procedure/src/error.rs b/src/common/procedure/src/error.rs index 39266f4addb2..1cd63decd282 100644 --- a/src/common/procedure/src/error.rs +++ b/src/common/procedure/src/error.rs @@ -18,13 +18,15 @@ use std::sync::Arc; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use snafu::{Location, Snafu}; use crate::procedure::ProcedureId; /// Procedure error. -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to execute procedure due to external error"))] External { source: BoxedError }, @@ -34,7 +36,8 @@ pub enum Error { #[snafu(display("Failed to serialize to json"))] ToJson { - source: serde_json::Error, + #[snafu(source)] + error: serde_json::Error, location: Location, }, @@ -54,7 +57,8 @@ pub enum Error { #[snafu(display("Failed to delete {}", key))] DeleteState { key: String, - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, }, #[snafu(display("Failed to delete keys: '{keys}'"))] @@ -73,7 +77,8 @@ pub enum Error { #[snafu(display("Failed to deserialize from json"))] FromJson { - source: serde_json::Error, + #[snafu(source)] + error: serde_json::Error, location: Location, }, @@ -85,7 +90,8 @@ pub enum Error { #[snafu(display("Failed to wait watcher"))] WaitWatcher { - source: tokio::sync::watch::error::RecvError, + #[snafu(source)] + error: tokio::sync::watch::error::RecvError, location: Location, }, @@ -102,7 +108,10 @@ pub enum Error { }, #[snafu(display("Corrupted data, error: "))] - CorruptedData { source: FromUtf8Error }, + CorruptedData { + #[snafu(source)] + error: FromUtf8Error, + }, #[snafu(display("Failed to start the remove_outdated_meta method, error"))] StartRemoveOutdatedMetaTask { diff --git a/src/common/procedure/src/local.rs b/src/common/procedure/src/local.rs index 0848c7029de2..e32d5f90e8af 100644 --- a/src/common/procedure/src/local.rs +++ b/src/common/procedure/src/local.rs @@ -229,7 +229,7 @@ impl ManagerContext { let procedure = loader(&message.data) .map_err(|e| { logging::error!( - "Failed to load procedure data, key: {}, source: {}", + "Failed to load procedure data, key: {}, source: {:?}", procedure_id, e ); diff --git a/src/common/procedure/src/store.rs b/src/common/procedure/src/store.rs index 154040a85309..11aeec6551af 100644 --- a/src/common/procedure/src/store.rs +++ b/src/common/procedure/src/store.rs @@ -224,7 +224,7 @@ impl ProcedureStore { serde_json::from_slice(value) .map_err(|e| { // `e` doesn't impl ErrorExt so we print it as normal error. - logging::error!("Failed to parse value, key: {:?}, source: {}", key, e); + logging::error!("Failed to parse value, key: {:?}, source: {:?}", key, e); e }) .ok() diff --git a/src/common/query/Cargo.toml b/src/common/query/Cargo.toml index 60f6a8003d81..17ea5c06d308 100644 --- a/src/common/query/Cargo.toml +++ b/src/common/query/Cargo.toml @@ -8,6 +8,7 @@ license.workspace = true api = { workspace = true } async-trait.workspace = true common-error = { workspace = true } +common-macro = { workspace = true } common-recordbatch = { workspace = true } common-time = { workspace = true } datafusion-common.workspace = true diff --git a/src/common/query/src/error.rs b/src/common/query/src/error.rs index c968675f9b80..25f9d3c71523 100644 --- a/src/common/query/src/error.rs +++ b/src/common/query/src/error.rs @@ -17,6 +17,7 @@ use std::any::Any; use arrow::error::ArrowError; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use common_recordbatch::error::Error as RecordbatchError; use datafusion_common::DataFusionError; use datatypes::arrow; @@ -26,8 +27,9 @@ use datatypes::prelude::ConcreteDataType; use snafu::{Location, Snafu}; use statrs::StatsError; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to execute Python UDF: {}", msg))] PyUdf { @@ -44,7 +46,8 @@ pub enum Error { #[snafu(display("Failed to execute function"))] ExecuteFunction { - source: DataFusionError, + #[snafu(source)] + error: DataFusionError, location: Location, }, @@ -57,7 +60,8 @@ pub enum Error { #[snafu(display("Failed to generate function"))] GenerateFunction { - source: StatsError, + #[snafu(source)] + error: StatsError, location: Location, }, @@ -109,7 +113,8 @@ pub enum Error { #[snafu(display("General DataFusion error"))] GeneralDataFusion { - source: DataFusionError, + #[snafu(source)] + error: DataFusionError, location: Location, }, @@ -133,14 +138,16 @@ pub enum Error { #[snafu(display("Failed to cast array to {:?}", typ))] TypeCast { - source: ArrowError, + #[snafu(source)] + error: ArrowError, typ: arrow::datatypes::DataType, location: Location, }, #[snafu(display("Failed to perform compute operation on arrow arrays"))] ArrowCompute { - source: ArrowError, + #[snafu(source)] + error: ArrowError, location: Location, }, diff --git a/src/common/recordbatch/Cargo.toml b/src/common/recordbatch/Cargo.toml index bf46b9b43586..b9ca442a3da2 100644 --- a/src/common/recordbatch/Cargo.toml +++ b/src/common/recordbatch/Cargo.toml @@ -6,6 +6,7 @@ license.workspace = true [dependencies] common-error = { workspace = true } +common-macro = { workspace = true } datafusion-common.workspace = true datafusion.workspace = true datatypes = { workspace = true } diff --git a/src/common/recordbatch/src/error.rs b/src/common/recordbatch/src/error.rs index 2ddfe27e2d13..92dbbedc6a72 100644 --- a/src/common/recordbatch/src/error.rs +++ b/src/common/recordbatch/src/error.rs @@ -17,17 +17,20 @@ use std::any::Any; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use datatypes::prelude::ConcreteDataType; use snafu::{Location, Snafu}; pub type Result = std::result::Result; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Fail to create datafusion record batch"))] NewDfRecordBatch { - source: datatypes::arrow::error::ArrowError, + #[snafu(source)] + error: datatypes::arrow::error::ArrowError, location: Location, }, @@ -54,19 +57,22 @@ pub enum Error { #[snafu(display("Failed to poll stream"))] PollStream { - source: datafusion::error::DataFusionError, + #[snafu(source)] + error: datafusion::error::DataFusionError, location: Location, }, #[snafu(display("Fail to format record batch"))] Format { - source: datatypes::arrow::error::ArrowError, + #[snafu(source)] + error: datatypes::arrow::error::ArrowError, location: Location, }, #[snafu(display("Failed to init Recordbatch stream"))] InitRecordbatchStream { - source: datafusion_common::DataFusionError, + #[snafu(source)] + error: datafusion_common::DataFusionError, location: Location, }, @@ -76,7 +82,8 @@ pub enum Error { projection, ))] ProjectArrowRecordBatch { - source: datatypes::arrow::error::ArrowError, + #[snafu(source)] + error: datatypes::arrow::error::ArrowError, location: Location, schema: datatypes::schema::SchemaRef, projection: Vec, diff --git a/src/common/runtime/Cargo.toml b/src/common/runtime/Cargo.toml index 658e4f4f182b..553a50504ea4 100644 --- a/src/common/runtime/Cargo.toml +++ b/src/common/runtime/Cargo.toml @@ -7,6 +7,7 @@ license.workspace = true [dependencies] async-trait.workspace = true common-error = { workspace = true } +common-macro = { workspace = true } common-telemetry = { workspace = true } metrics.workspace = true once_cell.workspace = true diff --git a/src/common/runtime/src/error.rs b/src/common/runtime/src/error.rs index c2e414216de8..35d053510126 100644 --- a/src/common/runtime/src/error.rs +++ b/src/common/runtime/src/error.rs @@ -15,17 +15,20 @@ use std::any::Any; use common_error::ext::ErrorExt; +use common_macro::stack_trace_debug; use snafu::{Location, Snafu}; use tokio::task::JoinError; pub type Result = std::result::Result; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub(crate)))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to build runtime"))] BuildRuntime { - source: std::io::Error, + #[snafu(source)] + error: std::io::Error, location: Location, }, @@ -35,7 +38,8 @@ pub enum Error { #[snafu(display("Failed to wait for repeated task {} to stop", name))] WaitGcTaskStop { name: String, - source: JoinError, + #[snafu(source)] + error: JoinError, location: Location, }, } diff --git a/src/common/substrait/Cargo.toml b/src/common/substrait/Cargo.toml index edd635d8e3d6..6ebe26fa02c0 100644 --- a/src/common/substrait/Cargo.toml +++ b/src/common/substrait/Cargo.toml @@ -11,6 +11,7 @@ bytes = "1.1" catalog = { workspace = true } common-catalog = { workspace = true } common-error = { workspace = true } +common-macro = { workspace = true } common-telemetry = { workspace = true } datafusion-common.workspace = true datafusion-expr.workspace = true diff --git a/src/common/substrait/src/error.rs b/src/common/substrait/src/error.rs index f130a78a7ce1..8c235964639e 100644 --- a/src/common/substrait/src/error.rs +++ b/src/common/substrait/src/error.rs @@ -16,13 +16,15 @@ use std::any::Any; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use datafusion::error::DataFusionError; use datatypes::prelude::ConcreteDataType; use prost::{DecodeError, EncodeError}; use snafu::{Location, Snafu}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Unsupported physical plan: {}", name))] UnsupportedPlan { name: String, location: Location }, @@ -41,13 +43,15 @@ pub enum Error { #[snafu(display("Failed to decode substrait relation"))] DecodeRel { - source: DecodeError, + #[snafu(source)] + error: DecodeError, location: Location, }, #[snafu(display("Failed to encode substrait relation"))] EncodeRel { - source: EncodeError, + #[snafu(source)] + error: EncodeError, location: Location, }, @@ -69,7 +73,8 @@ pub enum Error { #[snafu(display("Internal error from DataFusion"))] DFInternal { - source: DataFusionError, + #[snafu(source)] + error: DataFusionError, location: Location, }, @@ -110,13 +115,15 @@ pub enum Error { #[snafu(display("Failed to encode DataFusion plan"))] EncodeDfPlan { - source: datafusion::error::DataFusionError, + #[snafu(source)] + error: datafusion::error::DataFusionError, location: Location, }, #[snafu(display("Failed to decode DataFusion plan"))] DecodeDfPlan { - source: datafusion::error::DataFusionError, + #[snafu(source)] + error: datafusion::error::DataFusionError, location: Location, }, } diff --git a/src/common/telemetry/src/macros.rs b/src/common/telemetry/src/macros.rs index fed42bdb6dc9..4d5f6003b754 100644 --- a/src/common/telemetry/src/macros.rs +++ b/src/common/telemetry/src/macros.rs @@ -39,93 +39,36 @@ macro_rules! error { // error!(e; target: "my_target", "a {} event", "log") ($e:expr; target: $target:expr, $($arg:tt)+) => ({ use $crate::common_error::ext::ErrorExt; - use std::error::Error; - match ($e.source(), $e.location_opt()) { - (Some(source), Some(location)) => { - $crate::log!( - target: $target, - $crate::logging::Level::ERROR, - err.msg = %$e, - err.code = %$e.status_code(), - err.source = source, - err.location = %location, - $($arg)+ - ) - }, - (Some(source), None) => { - $crate::log!( - target: $target, - $crate::logging::Level::ERROR, - err.msg = %$e, - err.code = %$e.status_code(), - err.source = source, - $($arg)+ - ) - }, - (None, Some(location)) => { - $crate::log!( - target: $target, - $crate::logging::Level::ERROR, - err.msg = %$e, - err.code = %$e.status_code(), - err.location = %location, - $($arg)+ - ) - }, - (None, None) => { - $crate::log!( - target: $target, - $crate::logging::Level::ERROR, - err.msg = %$e, - err.code = %$e.status_code(), - $($arg)+ - ) - } - } + use $crate::common_error::ext::StackError; + + let mut stacks = vec![]; + $e.debug_fmt(0, &mut stacks); + let stacks = stacks.join("\n"); + + $crate::log!( + target: $target, + $crate::logging::Level::ERROR, + err.msg = %stacks, + err.code = %$e.status_code(), + $($arg)+ + ) }); // error!(e; "a {} event", "log") ($e:expr; $($arg:tt)+) => ({ - use std::error::Error; use $crate::common_error::ext::ErrorExt; - match ($e.source(), $e.location_opt()) { - (Some(source), Some(location)) => { - $crate::log!( - $crate::logging::Level::ERROR, - err.msg = %$e, - err.code = %$e.status_code(), - err.source = source, - err.location = %location, - $($arg)+ - ) - }, - (Some(source), None) => { - $crate::log!( - $crate::logging::Level::ERROR, - err.msg = %$e, - err.code = %$e.status_code(), - err.source = source, - $($arg)+ - ) - }, - (None, Some(location)) => { - $crate::log!( - $crate::logging::Level::ERROR, - err.msg = %$e, - err.code = %$e.status_code(), - err.location = %location, - $($arg)+ - ) - }, - (None, None) => { - $crate::log!( - $crate::logging::Level::ERROR, - err.msg = %$e, - err.code = %$e.status_code(), - $($arg)+ - ) - } - } + use $crate::common_error::ext::StackError; + + let mut stacks = vec![]; + $e.debug_fmt(0, &mut stacks); + let stacks = stacks.join("\n"); + + $crate::log!( + $crate::logging::Level::ERROR, + err.msg = %stacks, + err.code = %$e.status_code(), + $($arg)+ + ) }); // error!("a {} event", "log") @@ -144,46 +87,19 @@ macro_rules! warn { // warn!(e; "a {} event", "log") ($e:expr; $($arg:tt)+) => ({ - use std::error::Error; use $crate::common_error::ext::ErrorExt; - match ($e.source(), $e.location_opt()) { - (Some(source), Some(location)) => { - $crate::log!( - $crate::logging::Level::WARN, - err.msg = %$e, - err.code = %$e.status_code(), - err.source = source, - err.location = %location, - $($arg)+ - ) - }, - (Some(source), None) => { - $crate::log!( - $crate::logging::Level::WARN, - err.msg = %$e, - err.code = %$e.status_code(), - err.source = source, - $($arg)+ - ) - }, - (None, Some(location)) => { - $crate::log!( - $crate::logging::Level::WARN, - err.msg = %$e, - err.code = %$e.status_code(), - err.location = %location, - $($arg)+ - ) - }, - (None, None) => { - $crate::log!( - $crate::logging::Level::WARN, - err.msg = %$e, - err.code = %$e.status_code(), - $($arg)+ - ) - } - } + use $crate::common_error::ext::StackError; + + let mut stacks = vec![]; + $e.debug_fmt(0, &mut stacks); + let stacks = stacks.join("\n"); + + $crate::log!( + $crate::logging::Level::WARN, + err.msg = %$e, + err.code = %$e.status_code(), + $($arg)+ + ) }); // warn!("a {} event", "log") diff --git a/src/common/time/Cargo.toml b/src/common/time/Cargo.toml index 6a1a38af1b63..b8aa229e4ccd 100644 --- a/src/common/time/Cargo.toml +++ b/src/common/time/Cargo.toml @@ -9,6 +9,7 @@ arrow.workspace = true chrono-tz = "0.8" chrono.workspace = true common-error = { workspace = true } +common-macro = { workspace = true } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" snafu = { version = "0.7", features = ["backtraces"] } diff --git a/src/common/time/src/datetime.rs b/src/common/time/src/datetime.rs index 5bdec5dc25c9..39f451db8e11 100644 --- a/src/common/time/src/datetime.rs +++ b/src/common/time/src/datetime.rs @@ -102,7 +102,7 @@ impl DateTime { } pub fn to_chrono_datetime(&self) -> Option { - NaiveDateTime::from_timestamp_opt(self.0, 0) + NaiveDateTime::from_timestamp_millis(self.0) } pub fn to_date(&self) -> Option { @@ -162,4 +162,15 @@ mod tests { let datetime = DateTime::from(date); assert_eq!(datetime.val(), 185542587100800000); } + + #[test] + fn test_conversion_between_datetime_and_chrono_datetime() { + let cases = [1, 10, 100, 1000, 100000]; + for case in cases { + let dt = DateTime::new(case); + let ndt = dt.to_chrono_datetime().unwrap(); + let dt2 = DateTime::from(ndt); + assert_eq!(dt, dt2); + } + } } diff --git a/src/common/time/src/error.rs b/src/common/time/src/error.rs index 1ce675b30f52..2cd4527d2d07 100644 --- a/src/common/time/src/error.rs +++ b/src/common/time/src/error.rs @@ -18,13 +18,19 @@ use std::num::{ParseIntError, TryFromIntError}; use chrono::ParseError; use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use snafu::{Location, Snafu}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to parse string to date, raw: {}", raw))] - ParseDateStr { raw: String, source: ParseError }, + ParseDateStr { + raw: String, + #[snafu(source)] + error: ParseError, + }, #[snafu(display("Invalid date string, raw: {}", raw))] InvalidDateStr { raw: String, location: Location }, @@ -37,7 +43,8 @@ pub enum Error { #[snafu(display("Current timestamp overflow"))] TimestampOverflow { - source: TryFromIntError, + #[snafu(source)] + error: TryFromIntError, location: Location, }, @@ -54,7 +61,8 @@ pub enum Error { #[snafu(display("Invalid offset string {raw}: "))] ParseOffsetStr { raw: String, - source: ParseIntError, + #[snafu(source)] + error: ParseIntError, location: Location, }, diff --git a/src/datanode/Cargo.toml b/src/datanode/Cargo.toml index adb84270b90f..cc505c7d419c 100644 --- a/src/datanode/Cargo.toml +++ b/src/datanode/Cargo.toml @@ -23,6 +23,7 @@ common-function = { workspace = true } common-greptimedb-telemetry = { workspace = true } common-grpc = { workspace = true } common-grpc-expr = { workspace = true } +common-macro = { workspace = true } common-meta = { workspace = true } common-procedure = { workspace = true } common-query = { workspace = true } diff --git a/src/datanode/src/error.rs b/src/datanode/src/error.rs index 41af9faa5006..ab315954aadf 100644 --- a/src/datanode/src/error.rs +++ b/src/datanode/src/error.rs @@ -16,6 +16,7 @@ use std::any::Any; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use common_procedure::ProcedureId; use serde_json::error::Error as JsonError; use servers::define_into_tonic_status; @@ -24,8 +25,9 @@ use store_api::storage::RegionId; use table::error::Error as TableError; /// Business error of datanode. -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to handle heartbeat response"))] HandleHeartbeatResponse { @@ -170,14 +172,23 @@ pub enum Error { #[snafu(display("Failed to parse address {}", addr))] ParseAddr { addr: String, - source: std::net::AddrParseError, + #[snafu(source)] + error: std::net::AddrParseError, }, #[snafu(display("Failed to create directory {}", dir))] - CreateDir { dir: String, source: std::io::Error }, + CreateDir { + dir: String, + #[snafu(source)] + error: std::io::Error, + }, #[snafu(display("Failed to remove directory {}", dir))] - RemoveDir { dir: String, source: std::io::Error }, + RemoveDir { + dir: String, + #[snafu(source)] + error: std::io::Error, + }, #[snafu(display("Failed to open log store"))] OpenLogStore { @@ -187,7 +198,8 @@ pub enum Error { #[snafu(display("Failed to init backend"))] InitBackend { - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, location: Location, }, @@ -340,7 +352,8 @@ pub enum Error { #[snafu(display("Failed to encode object into json"))] EncodeJson { location: Location, - source: JsonError, + #[snafu(source)] + error: JsonError, }, #[snafu(display("Payload not exist"))] @@ -351,7 +364,8 @@ pub enum Error { #[snafu(display("Failed to join task"))] JoinTask { - source: common_runtime::JoinError, + #[snafu(source)] + error: common_runtime::JoinError, location: Location, }, diff --git a/src/datatypes/Cargo.toml b/src/datatypes/Cargo.toml index e1bf3db1f1e1..e0b0df8c6269 100644 --- a/src/datatypes/Cargo.toml +++ b/src/datatypes/Cargo.toml @@ -14,6 +14,7 @@ arrow-schema.workspace = true arrow.workspace = true common-base = { workspace = true } common-error = { workspace = true } +common-macro = { workspace = true } common-telemetry = { workspace = true } common-time = { workspace = true } datafusion-common.workspace = true diff --git a/src/datatypes/src/error.rs b/src/datatypes/src/error.rs index fd7cddc0a5f3..f96239bf3a36 100644 --- a/src/datatypes/src/error.rs +++ b/src/datatypes/src/error.rs @@ -16,20 +16,24 @@ use std::any::Any; use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use snafu::{Location, Snafu}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to serialize data"))] Serialize { - source: serde_json::Error, + #[snafu(source)] + error: serde_json::Error, location: Location, }, #[snafu(display("Failed to deserialize data, json: {}", json))] Deserialize { - source: serde_json::Error, + #[snafu(source)] + error: serde_json::Error, location: Location, json: String, }, @@ -63,7 +67,8 @@ pub enum Error { #[snafu(display("Failed to parse version in schema meta, value: {}", value))] ParseSchemaVersion { value: String, - source: std::num::ParseIntError, + #[snafu(source)] + error: std::num::ParseIntError, location: Location, }, @@ -75,19 +80,22 @@ pub enum Error { #[snafu(display("Failed to cast arrow time i32 type into i64"))] CastTimeType { - source: std::num::TryFromIntError, + #[snafu(source)] + error: std::num::TryFromIntError, location: Location, }, #[snafu(display("Arrow failed to compute"))] ArrowCompute { - source: arrow::error::ArrowError, + #[snafu(source)] + error: arrow::error::ArrowError, location: Location, }, #[snafu(display("Failed to project arrow schema"))] ProjectArrowSchema { - source: arrow::error::ArrowError, + #[snafu(source)] + error: arrow::error::ArrowError, location: Location, }, diff --git a/src/file-engine/Cargo.toml b/src/file-engine/Cargo.toml index 77a4ebb521f4..f8687df7970e 100644 --- a/src/file-engine/Cargo.toml +++ b/src/file-engine/Cargo.toml @@ -13,6 +13,7 @@ async-trait = "0.1" common-catalog = { workspace = true } common-datasource = { workspace = true } common-error = { workspace = true } +common-macro = { workspace = true } common-procedure = { workspace = true } common-query = { workspace = true } common-recordbatch = { workspace = true } diff --git a/src/file-engine/src/error.rs b/src/file-engine/src/error.rs index 87cf49278315..5a23354fc3ef 100644 --- a/src/file-engine/src/error.rs +++ b/src/file-engine/src/error.rs @@ -16,14 +16,16 @@ use std::any::Any; use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use datafusion::arrow::error::ArrowError; use datafusion::error::DataFusionError; use serde_json::error::Error as JsonError; use snafu::{Location, Snafu}; use store_api::storage::RegionId; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Unsupported operation: {}", operation))] Unsupported { @@ -50,38 +52,44 @@ pub enum Error { CheckObject { path: String, location: Location, - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, }, #[snafu(display("Fail to encode object into json"))] EncodeJson { location: Location, - source: JsonError, + #[snafu(source)] + error: JsonError, }, #[snafu(display("Fail to decode object from json"))] DecodeJson { location: Location, - source: JsonError, + #[snafu(source)] + error: JsonError, }, #[snafu(display("Failed to store region manifest, region_id: {}", region_id))] StoreRegionManifest { - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, region_id: RegionId, location: Location, }, #[snafu(display("Failed to load region manifest, region_id: {}", region_id))] LoadRegionManifest { - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, region_id: RegionId, location: Location, }, #[snafu(display("Failed to delete region manifest, region_id: {},", region_id))] DeleteRegionManifest { - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, region_id: RegionId, location: Location, }, @@ -100,19 +108,22 @@ pub enum Error { #[snafu(display("Failed to build csv config"))] BuildCsvConfig { - source: common_datasource::file_format::csv::CsvConfigBuilderError, + #[snafu(source)] + error: common_datasource::file_format::csv::CsvConfigBuilderError, location: Location, }, #[snafu(display("Failed to build stream"))] BuildStream { - source: DataFusionError, + #[snafu(source)] + error: DataFusionError, location: Location, }, #[snafu(display("Failed to project schema"))] ProjectArrowSchema { - source: ArrowError, + #[snafu(source)] + error: ArrowError, location: Location, }, @@ -136,7 +147,8 @@ pub enum Error { #[snafu(display("Failed to generate parquet scan plan"))] ParquetScanPlan { - source: DataFusionError, + #[snafu(source)] + error: DataFusionError, location: Location, }, @@ -153,7 +165,8 @@ pub enum Error { #[snafu(display("Failed to extract column from filter"))] ExtractColumnFromFilter { - source: DataFusionError, + #[snafu(source)] + error: DataFusionError, location: Location, }, diff --git a/src/frontend/Cargo.toml b/src/frontend/Cargo.toml index 285ad121ba63..b85a18008eca 100644 --- a/src/frontend/Cargo.toml +++ b/src/frontend/Cargo.toml @@ -28,6 +28,7 @@ common-error = { workspace = true } common-function = { workspace = true } common-grpc = { workspace = true } common-grpc-expr = { workspace = true } +common-macro = { workspace = true } common-meta = { workspace = true } common-procedure = { workspace = true } common-query = { workspace = true } diff --git a/src/frontend/src/error.rs b/src/frontend/src/error.rs index c418cb11252f..a176d663b5bb 100644 --- a/src/frontend/src/error.rs +++ b/src/frontend/src/error.rs @@ -17,12 +17,14 @@ use std::any::Any; use common_datasource::file_format::Format; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use servers::define_into_tonic_status; use snafu::{Location, Snafu}; use store_api::storage::RegionNumber; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to invalidate table cache"))] InvalidateTableCache { @@ -44,43 +46,44 @@ pub enum Error { #[snafu(display(""))] External { - #[snafu(backtrace)] + location: Location, source: BoxedError, }, #[snafu(display("Failed to query"))] RequestQuery { - #[snafu(backtrace)] + location: Location, source: common_meta::error::Error, }, #[snafu(display("Runtime resource error"))] RuntimeResource { - #[snafu(backtrace)] + location: Location, source: common_runtime::error::Error, }, #[snafu(display("Failed to start server"))] StartServer { - #[snafu(backtrace)] + location: Location, source: servers::error::Error, }, #[snafu(display("Failed to shutdown server"))] ShutdownServer { - #[snafu(backtrace)] + location: Location, source: servers::error::Error, }, #[snafu(display("Failed to parse address {}", addr))] ParseAddr { addr: String, - source: std::net::AddrParseError, + #[snafu(source)] + error: std::net::AddrParseError, }, #[snafu(display("Failed to parse SQL"))] ParseSql { - #[snafu(backtrace)] + location: Location, source: sql::error::Error, }, @@ -113,13 +116,13 @@ pub enum Error { #[snafu(display("General catalog error"))] Catalog { - #[snafu(backtrace)] + location: Location, source: catalog::error::Error, }, #[snafu(display("Failed to start Meta client"))] StartMetaClient { - #[snafu(backtrace)] + location: Location, source: meta_client::error::Error, }, @@ -132,7 +135,7 @@ pub enum Error { #[snafu(display("Failed to find table route for table id {}", table_id))] FindTableRoute { table_id: u32, - #[snafu(backtrace)] + location: Location, source: partition::error::Error, }, @@ -141,7 +144,7 @@ pub enum Error { #[snafu(display("Table occurs error"))] Table { - #[snafu(backtrace)] + location: Location, source: table::error::Error, }, @@ -150,26 +153,26 @@ pub enum Error { #[snafu(display("Failed to plan statement"))] PlanStatement { - #[snafu(backtrace)] + location: Location, source: query::error::Error, }, #[snafu(display("Failed to read table: {table_name}"))] ReadTable { table_name: String, - #[snafu(backtrace)] + location: Location, source: query::error::Error, }, #[snafu(display("Failed to execute logical plan"))] ExecLogicalPlan { - #[snafu(backtrace)] + location: Location, source: query::error::Error, }, #[snafu(display(""))] InvokeRegionServer { - #[snafu(backtrace)] + location: Location, source: servers::error::Error, }, @@ -190,7 +193,7 @@ pub enum Error { #[snafu(display("SQL execution intercepted"))] SqlExecIntercepted { - #[snafu(backtrace)] + location: Location, source: BoxedError, }, @@ -198,19 +201,19 @@ pub enum Error { #[snafu(display("Failed to execute PromQL query {}", query))] ExecutePromql { query: String, - #[snafu(backtrace)] + location: Location, source: servers::error::Error, }, #[snafu(display("Failed to create logical plan for prometheus query"))] PromStoreRemoteQueryPlan { - #[snafu(backtrace)] + location: Location, source: servers::error::Error, }, #[snafu(display("Failed to describe schema for given statement"))] DescribeStatement { - #[snafu(backtrace)] + location: Location, source: query::error::Error, }, @@ -219,21 +222,21 @@ pub enum Error { #[snafu(display("Failed to start script manager"))] StartScriptManager { - #[snafu(backtrace)] + location: Location, source: script::error::Error, }, #[snafu(display("Failed to copy table: {}", table_name))] CopyTable { table_name: String, - #[snafu(backtrace)] + location: Location, source: table::error::Error, }, #[snafu(display("Failed to insert value into table: {}", table_name))] Insert { table_name: String, - #[snafu(backtrace)] + location: Location, source: table::error::Error, }, @@ -293,7 +296,7 @@ impl ErrorExt for Error { Error::Permission { source, .. } => source.status_code(), - Error::DescribeStatement { source } => source.status_code(), + Error::DescribeStatement { source, .. } => source.status_code(), Error::HandleHeartbeatResponse { source, .. } | Error::TableMetadataManager { source, .. } => source.status_code(), @@ -306,17 +309,17 @@ impl ErrorExt for Error { Error::StartServer { source, .. } => source.status_code(), Error::ShutdownServer { source, .. } => source.status_code(), - Error::ParseSql { source } => source.status_code(), + Error::ParseSql { source, .. } => source.status_code(), Error::InvalidateTableCache { source, .. } => source.status_code(), - Error::Table { source } + Error::Table { source, .. } | Error::CopyTable { source, .. } | Error::Insert { source, .. } => source.status_code(), Error::OpenRaftEngineBackend { .. } => StatusCode::StorageUnavailable, - Error::RequestQuery { source } => source.status_code(), + Error::RequestQuery { source, .. } => source.status_code(), Error::FindDatanode { .. } | Error::VectorToGrpcColumn { .. } @@ -330,22 +333,21 @@ impl ErrorExt for Error { Error::Catalog { source, .. } => source.status_code(), - Error::StartMetaClient { source } | Error::CreateMetaHeartbeatStream { source, .. } => { - source.status_code() - } + Error::StartMetaClient { source, .. } + | Error::CreateMetaHeartbeatStream { source, .. } => source.status_code(), - Error::PlanStatement { source } + Error::PlanStatement { source, .. } | Error::ReadTable { source, .. } - | Error::ExecLogicalPlan { source } => source.status_code(), + | Error::ExecLogicalPlan { source, .. } => source.status_code(), Error::LeaderNotFound { .. } => StatusCode::StorageUnavailable, Error::TableAlreadyExist { .. } => StatusCode::TableAlreadyExists, - Error::InvokeRegionServer { source } => source.status_code(), + Error::InvokeRegionServer { source, .. } => source.status_code(), - Error::External { source } => source.status_code(), + Error::External { source, .. } => source.status_code(), Error::FindTableRoute { source, .. } => source.status_code(), - Error::StartScriptManager { source } => source.status_code(), + Error::StartScriptManager { source, .. } => source.status_code(), Error::TableOperation { source, .. } => source.status_code(), } diff --git a/src/frontend/src/server.rs b/src/frontend/src/server.rs index 5a61c3b48834..794c7000a875 100644 --- a/src/frontend/src/server.rs +++ b/src/frontend/src/server.rs @@ -21,7 +21,7 @@ use common_base::Plugins; use common_runtime::Builder as RuntimeBuilder; use common_telemetry::info; use servers::configurator::ConfiguratorRef; -use servers::error::Error::InternalIo; +use servers::error::InternalIoSnafu; use servers::grpc::{GrpcServer, GrpcServerConfig}; use servers::http::HttpServerBuilder; use servers::metrics_handler::MetricsHandler; @@ -33,8 +33,7 @@ use servers::query_handler::sql::ServerSqlQueryHandlerAdaptor; use servers::server::Server; use snafu::ResultExt; -use crate::error::Error::StartServer; -use crate::error::{self, Result}; +use crate::error::{self, Result, StartServerSnafu}; use crate::frontend::FrontendOptions; use crate::instance::FrontendInstance; @@ -149,9 +148,8 @@ impl Services { opts.tls.should_force_tls(), opts.tls .setup() - .map_err(|e| StartServer { - source: InternalIo { source: e }, - })? + .context(InternalIoSnafu) + .context(StartServerSnafu)? .map(Arc::new), opts.reject_no_database.unwrap_or(false), )), diff --git a/src/log-store/Cargo.toml b/src/log-store/Cargo.toml index b02b7c6a5af9..bedf1fc64f65 100644 --- a/src/log-store/Cargo.toml +++ b/src/log-store/Cargo.toml @@ -18,6 +18,7 @@ bytes = "1.1" common-base = { workspace = true } common-config = { workspace = true } common-error = { workspace = true } +common-macro = { workspace = true } common-meta = { workspace = true } common-runtime = { workspace = true } common-telemetry = { workspace = true } diff --git a/src/log-store/src/error.rs b/src/log-store/src/error.rs index 6865bbed22c6..a24a48d84be2 100644 --- a/src/log-store/src/error.rs +++ b/src/log-store/src/error.rs @@ -15,11 +15,13 @@ use std::any::Any; use common_error::ext::ErrorExt; +use common_macro::stack_trace_debug; use common_runtime::error::Error as RuntimeError; use snafu::{Location, Snafu}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to start log store gc task"))] StartGcTask { @@ -35,13 +37,15 @@ pub enum Error { #[snafu(display("Failed to add entry to LogBatch"))] AddEntryLogBatch { - source: raft_engine::Error, + #[snafu(source)] + error: raft_engine::Error, location: Location, }, #[snafu(display("Failed to perform raft-engine operation"))] RaftEngine { - source: raft_engine::Error, + #[snafu(source)] + error: raft_engine::Error, location: Location, }, @@ -63,7 +67,8 @@ pub enum Error { start: u64, end: u64, max_size: usize, - source: raft_engine::Error, + #[snafu(source)] + error: raft_engine::Error, location: Location, }, diff --git a/src/meta-client/Cargo.toml b/src/meta-client/Cargo.toml index 85b5b55b14ac..7f8a9035d8de 100644 --- a/src/meta-client/Cargo.toml +++ b/src/meta-client/Cargo.toml @@ -10,6 +10,7 @@ async-trait = "0.1" chrono.workspace = true common-error = { workspace = true } common-grpc = { workspace = true } +common-macro = { workspace = true } common-meta = { workspace = true } common-telemetry = { workspace = true } etcd-client.workspace = true diff --git a/src/meta-client/src/error.rs b/src/meta-client/src/error.rs index 8644e18948ad..a86ec822802f 100644 --- a/src/meta-client/src/error.rs +++ b/src/meta-client/src/error.rs @@ -15,11 +15,13 @@ use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; use common_error::{GREPTIME_ERROR_CODE, GREPTIME_ERROR_MSG}; +use common_macro::stack_trace_debug; use snafu::{Location, Snafu}; use tonic::Status; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Illegal GRPC client state: {}", err_msg))] IllegalGrpcClientState { err_msg: String, location: Location }, @@ -36,7 +38,8 @@ pub enum Error { #[snafu(display("Ask leader timeout"))] AskLeaderTimeout { location: Location, - source: tokio::time::error::Elapsed, + #[snafu(source)] + error: tokio::time::error::Elapsed, }, #[snafu(display("Failed to create gRPC channel"))] diff --git a/src/meta-srv/Cargo.toml b/src/meta-srv/Cargo.toml index 0942583b380e..0836485e0a89 100644 --- a/src/meta-srv/Cargo.toml +++ b/src/meta-srv/Cargo.toml @@ -20,6 +20,7 @@ common-error = { workspace = true } common-greptimedb-telemetry = { workspace = true } common-grpc = { workspace = true } common-grpc-expr = { workspace = true } +common-macro = { workspace = true } common-meta = { workspace = true } common-procedure = { workspace = true } common-runtime = { workspace = true } diff --git a/src/meta-srv/src/cluster.rs b/src/meta-srv/src/cluster.rs index 14ba5b735475..a314e43b58d0 100644 --- a/src/meta-srv/src/cluster.rs +++ b/src/meta-srv/src/cluster.rs @@ -256,8 +256,8 @@ fn check_resp_header(header: &Option, ctx: Context) -> Result<() fn need_retry(error: &error::Error) -> bool { match error { error::Error::IsNotLeader { .. } => true, - error::Error::Range { source, .. } | error::Error::BatchGet { source, .. } => { - match_for_io_error(source).is_some() + error::Error::Range { error, .. } | error::Error::BatchGet { error, .. } => { + match_for_io_error(error).is_some() } _ => false, } diff --git a/src/meta-srv/src/error.rs b/src/meta-srv/src/error.rs index 2ce6c565aa71..16ee839ce928 100644 --- a/src/meta-srv/src/error.rs +++ b/src/meta-srv/src/error.rs @@ -14,6 +14,7 @@ use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use common_meta::peer::Peer; use common_runtime::JoinError; use servers::define_into_tonic_status; @@ -24,8 +25,9 @@ use tonic::codegen::http; use crate::pubsub::Message; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to create default catalog and schema"))] InitMetadata { @@ -74,7 +76,8 @@ pub enum Error { #[snafu(display("Failed to join a future"))] Join { location: Location, - source: JoinError, + #[snafu(source)] + error: JoinError, }, #[snafu(display("Failed to execute transaction: {}", msg))] @@ -110,7 +113,10 @@ pub enum Error { }, #[snafu(display("Failed to send shutdown signal"))] - SendShutdownSignal { source: SendError<()> }, + SendShutdownSignal { + #[snafu(source)] + error: SendError<()>, + }, #[snafu(display("Failed to shutdown {} server", server))] ShutdownServer { @@ -124,26 +130,30 @@ pub enum Error { #[snafu(display("Failed to execute via Etcd"))] EtcdFailed { - source: etcd_client::Error, + #[snafu(source)] + error: etcd_client::Error, location: Location, }, #[snafu(display("Failed to connect to Etcd"))] ConnectEtcd { - source: etcd_client::Error, + #[snafu(source)] + error: etcd_client::Error, location: Location, }, #[snafu(display("Failed to bind address {}", addr))] TcpBind { addr: String, - source: std::io::Error, + #[snafu(source)] + error: std::io::Error, location: Location, }, #[snafu(display("Failed to start gRPC server"))] StartGrpc { - source: tonic::transport::Error, + #[snafu(source)] + error: tonic::transport::Error, location: Location, }, #[snafu(display("Failed to start http server"))] @@ -154,7 +164,8 @@ pub enum Error { #[snafu(display("Failed to parse address {}", addr))] ParseAddr { addr: String, - source: std::net::AddrParseError, + #[snafu(source)] + error: std::net::AddrParseError, }, #[snafu(display("Empty table name"))] EmptyTableName { location: Location }, @@ -170,52 +181,60 @@ pub enum Error { #[snafu(display("Failed to parse datanode lease key from utf8"))] LeaseKeyFromUtf8 { - source: std::string::FromUtf8Error, + #[snafu(source)] + error: std::string::FromUtf8Error, location: Location, }, #[snafu(display("Failed to parse datanode lease value from utf8"))] LeaseValueFromUtf8 { - source: std::string::FromUtf8Error, + #[snafu(source)] + error: std::string::FromUtf8Error, location: Location, }, #[snafu(display("Failed to parse datanode stat key from utf8"))] StatKeyFromUtf8 { - source: std::string::FromUtf8Error, + #[snafu(source)] + error: std::string::FromUtf8Error, location: Location, }, #[snafu(display("Failed to parse datanode stat value from utf8"))] StatValueFromUtf8 { - source: std::string::FromUtf8Error, + #[snafu(source)] + error: std::string::FromUtf8Error, location: Location, }, #[snafu(display("Failed to parse invalid region key from utf8"))] InvalidRegionKeyFromUtf8 { - source: std::string::FromUtf8Error, + #[snafu(source)] + error: std::string::FromUtf8Error, location: Location, }, #[snafu(display("Failed to serialize to json: {}", input))] SerializeToJson { input: String, - source: serde_json::error::Error, + #[snafu(source)] + error: serde_json::error::Error, location: Location, }, #[snafu(display("Failed to deserialize from json: {}", input))] DeserializeFromJson { input: String, - source: serde_json::error::Error, + #[snafu(source)] + error: serde_json::error::Error, location: Location, }, #[snafu(display("Failed to parse number: {}", err_msg))] ParseNum { err_msg: String, - source: std::num::ParseIntError, + #[snafu(source)] + error: std::num::ParseIntError, location: Location, }, @@ -239,7 +258,8 @@ pub enum Error { #[snafu(display("Failed to decode table route"))] DecodeTableRoute { - source: prost::DecodeError, + #[snafu(source)] + error: prost::DecodeError, location: Location, }, @@ -294,13 +314,15 @@ pub enum Error { #[snafu(display("Failed to batch get KVs from leader's in_memory kv store"))] BatchGet { - source: tonic::Status, + #[snafu(source)] + error: tonic::Status, location: Location, }, #[snafu(display("Failed to batch range KVs from leader's in_memory kv store"))] Range { - source: tonic::Status, + #[snafu(source)] + error: tonic::Status, location: Location, }, @@ -315,7 +337,8 @@ pub enum Error { #[snafu(display("Invalid http body"))] InvalidHttpBody { - source: http::Error, + #[snafu(source)] + error: http::Error, location: Location, }, @@ -332,19 +355,22 @@ pub enum Error { #[snafu(display("Failed to lock based on etcd"))] Lock { - source: etcd_client::Error, + #[snafu(source)] + error: etcd_client::Error, location: Location, }, #[snafu(display("Failed to unlock based on etcd"))] Unlock { - source: etcd_client::Error, + #[snafu(source)] + error: etcd_client::Error, location: Location, }, #[snafu(display("Failed to grant lease"))] LeaseGrant { - source: etcd_client::Error, + #[snafu(source)] + error: etcd_client::Error, location: Location, }, @@ -353,7 +379,8 @@ pub enum Error { #[snafu(display("Invalid utf-8 value"))] InvalidUtf8Value { - source: std::string::FromUtf8Error, + #[snafu(source)] + error: std::string::FromUtf8Error, location: Location, }, @@ -494,7 +521,8 @@ pub enum Error { #[snafu(display("Failed to publish message"))] PublishMessage { - source: SendError, + #[snafu(source)] + error: SendError, location: Location, }, diff --git a/src/mito2/Cargo.toml b/src/mito2/Cargo.toml index 0a1ff27f9e4c..cdd2d8d71b56 100644 --- a/src/mito2/Cargo.toml +++ b/src/mito2/Cargo.toml @@ -22,6 +22,7 @@ common-base = { workspace = true } common-catalog = { workspace = true } common-datasource = { workspace = true } common-error = { workspace = true } +common-macro = { workspace = true } common-procedure = { workspace = true } common-query = { workspace = true } common-recordbatch = { workspace = true } diff --git a/src/mito2/src/error.rs b/src/mito2/src/error.rs index 06aa47a9cd74..fcc3842111d1 100644 --- a/src/mito2/src/error.rs +++ b/src/mito2/src/error.rs @@ -18,6 +18,7 @@ use std::sync::Arc; use common_datasource::compression::CompressionType; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use common_runtime::JoinError; use datatypes::arrow::error::ArrowError; use datatypes::prelude::ConcreteDataType; @@ -29,33 +30,38 @@ use store_api::storage::RegionId; use crate::sst::file::FileId; use crate::worker::WorkerId; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("OpenDAL operator failed"))] OpenDal { location: Location, - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, }, #[snafu(display("Fail to compress object by {}, path: {}", compress_type, path))] CompressObject { compress_type: CompressionType, path: String, - source: std::io::Error, + #[snafu(source)] + error: std::io::Error, }, #[snafu(display("Fail to decompress object by {}, path: {}", compress_type, path))] DecompressObject { compress_type: CompressionType, path: String, - source: std::io::Error, + #[snafu(source)] + error: std::io::Error, }, #[snafu(display("Failed to ser/de json object"))] SerdeJson { location: Location, - source: serde_json::Error, + #[snafu(source)] + error: serde_json::Error, }, #[snafu(display("Invalid scan index, start: {}, end: {}", start, end))] @@ -68,7 +74,8 @@ pub enum Error { #[snafu(display("Invalid UTF-8 content"))] Utf8 { location: Location, - source: std::str::Utf8Error, + #[snafu(source)] + error: std::str::Utf8Error, }, #[snafu(display("Cannot find RegionMetadata"))] @@ -76,7 +83,8 @@ pub enum Error { #[snafu(display("Failed to join handle"))] Join { - source: common_runtime::JoinError, + #[snafu(source)] + error: common_runtime::JoinError, location: Location, }, @@ -85,7 +93,8 @@ pub enum Error { #[snafu(display("Failed to recv result"))] Recv { - source: tokio::sync::oneshot::error::RecvError, + #[snafu(source)] + error: tokio::sync::oneshot::error::RecvError, location: Location, }, @@ -101,7 +110,8 @@ pub enum Error { #[snafu(display("Failed to create RecordBatch from vectors"))] NewRecordBatch { location: Location, - source: ArrowError, + #[snafu(source)] + error: ArrowError, }, #[snafu(display("Failed to write to buffer"))] @@ -114,13 +124,15 @@ pub enum Error { WriteParquet { path: String, location: Location, - source: parquet::errors::ParquetError, + #[snafu(source)] + error: parquet::errors::ParquetError, }, #[snafu(display("Failed to read parquet file, path: {}", path))] ReadParquet { path: String, - source: parquet::errors::ParquetError, + #[snafu(source)] + error: parquet::errors::ParquetError, location: Location, }, @@ -167,7 +179,8 @@ pub enum Error { EncodeWal { region_id: RegionId, location: Location, - source: EncodeError, + #[snafu(source)] + error: EncodeError, }, #[snafu(display("Failed to write WAL"))] @@ -187,7 +200,8 @@ pub enum Error { DecodeWal { region_id: RegionId, location: Location, - source: DecodeError, + #[snafu(source)] + error: DecodeError, }, #[snafu(display("Failed to delete WAL, region_id: {}", region_id))] @@ -206,7 +220,8 @@ pub enum Error { #[snafu(display("Failed to serialize field"))] SerializeField { - source: memcomparable::Error, + #[snafu(source)] + error: memcomparable::Error, location: Location, }, @@ -221,7 +236,8 @@ pub enum Error { #[snafu(display("Failed to deserialize field"))] DeserializeField { - source: memcomparable::Error, + #[snafu(source)] + error: memcomparable::Error, location: Location, }, @@ -247,7 +263,8 @@ pub enum Error { #[snafu(display("Failed to compute arrow arrays"))] ComputeArrow { location: Location, - source: datatypes::arrow::error::ArrowError, + #[snafu(source)] + error: datatypes::arrow::error::ArrowError, }, #[snafu(display("Failed to compute vector"))] @@ -271,7 +288,8 @@ pub enum Error { #[snafu(display("Failed to stop scheduler"))] StopScheduler { - source: JoinError, + #[snafu(source)] + error: JoinError, location: Location, }, @@ -284,7 +302,8 @@ pub enum Error { #[snafu(display("Failed to delete SST file, file id: {}", file_id))] DeleteSst { file_id: FileId, - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, location: Location, }, @@ -352,9 +371,10 @@ pub enum Error { location: Location, }, - #[snafu(display("Invalid options, source: {}", source))] + #[snafu(display("Invalid options"))] JsonOptions { - source: serde_json::Error, + #[snafu(source)] + error: serde_json::Error, location: Location, }, diff --git a/src/operator/Cargo.toml b/src/operator/Cargo.toml index c87ee3b9c58f..2de2f326745b 100644 --- a/src/operator/Cargo.toml +++ b/src/operator/Cargo.toml @@ -20,6 +20,7 @@ common-catalog = { workspace = true } common-datasource = { workspace = true } common-error = { workspace = true } common-grpc-expr = { workspace = true } +common-macro = { workspace = true } common-meta = { workspace = true } common-query = { workspace = true } common-recordbatch = { workspace = true } diff --git a/src/operator/src/error.rs b/src/operator/src/error.rs index 8194c196f9a1..3939bb28a453 100644 --- a/src/operator/src/error.rs +++ b/src/operator/src/error.rs @@ -17,14 +17,16 @@ use std::any::Any; use common_datasource::file_format::Format; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use datafusion::parquet; use datatypes::arrow::error::ArrowError; use datatypes::value::Value; use servers::define_into_tonic_status; use snafu::{Location, Snafu}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to invalidate table cache"))] InvalidateTableCache { @@ -46,52 +48,52 @@ pub enum Error { #[snafu(display("external error"))] External { - #[snafu(backtrace)] + location: Location, source: BoxedError, }, #[snafu(display("Failed to insert data"))] RequestInserts { - #[snafu(backtrace)] + location: Location, source: common_meta::error::Error, }, #[snafu(display("Failed to delete data"))] RequestDeletes { - #[snafu(backtrace)] + location: Location, source: common_meta::error::Error, }, #[snafu(display("Failed to parse SQL"))] ParseSql { - #[snafu(backtrace)] + location: Location, source: sql::error::Error, }, #[snafu(display("Failed to convert value to sql value: {}", value))] ConvertSqlValue { value: Value, - #[snafu(backtrace)] + location: Location, source: sql::error::Error, }, #[snafu(display("Column datatype error"))] ColumnDataType { - #[snafu(backtrace)] + location: Location, source: api::error::Error, }, #[snafu(display("Invalid column proto definition, column: {}", column))] InvalidColumnDef { column: String, - #[snafu(backtrace)] + location: Location, source: api::error::Error, }, #[snafu(display("Failed to convert column default constraint, column: {}", column_name))] ConvertColumnDefaultConstraint { column_name: String, - #[snafu(backtrace)] + location: Location, source: datatypes::error::Error, }, @@ -109,20 +111,21 @@ pub enum Error { #[snafu(display("Failed to join task"))] JoinTask { - source: common_runtime::JoinError, + #[snafu(source)] + error: common_runtime::JoinError, location: Location, }, #[snafu(display("General catalog error"))] Catalog { - #[snafu(backtrace)] + location: Location, source: catalog::error::Error, }, #[snafu(display("Failed to find table partition rule for table {}", table_name))] FindTablePartitionRule { table_name: String, - #[snafu(backtrace)] + location: Location, source: partition::error::Error, }, @@ -146,13 +149,13 @@ pub enum Error { #[snafu(display("Failed to create table info"))] CreateTableInfo { - #[snafu(backtrace)] + location: Location, source: datatypes::error::Error, }, #[snafu(display("Failed to build CreateExpr on insertion"))] BuildCreateExprOnInsertion { - #[snafu(backtrace)] + location: Location, source: common_grpc_expr::error::Error, }, @@ -167,7 +170,7 @@ pub enum Error { #[snafu(display("Table occurs error"))] Table { - #[snafu(backtrace)] + location: Location, source: table::error::Error, }, @@ -176,44 +179,46 @@ pub enum Error { #[snafu(display("Failed to execute statement"))] ExecuteStatement { - #[snafu(backtrace)] + location: Location, source: query::error::Error, }, #[snafu(display("Failed to plan statement"))] PlanStatement { - #[snafu(backtrace)] + location: Location, source: query::error::Error, }, #[snafu(display("Failed to parse query"))] ParseQuery { - #[snafu(backtrace)] + location: Location, source: query::error::Error, }, #[snafu(display("Failed to execute logical plan"))] ExecLogicalPlan { - #[snafu(backtrace)] + location: Location, source: query::error::Error, }, #[snafu(display("Failed to build DataFusion logical plan"))] BuildDfLogicalPlan { - source: datafusion_common::DataFusionError, + #[snafu(source)] + error: datafusion_common::DataFusionError, location: Location, }, #[snafu(display("Failed to convert AlterExpr to AlterRequest"))] AlterExprToRequest { - #[snafu(backtrace)] + location: Location, source: common_grpc_expr::error::Error, }, #[snafu(display("Failed to build table meta for table: {}", table_name))] BuildTableMeta { table_name: String, - source: table::metadata::TableMetaBuilderError, + #[snafu(source)] + error: table::metadata::TableMetaBuilderError, location: Location, }, @@ -222,25 +227,25 @@ pub enum Error { #[snafu(display("Failed to find new columns on insertion"))] FindNewColumnsOnInsertion { - #[snafu(backtrace)] + location: Location, source: common_grpc_expr::error::Error, }, #[snafu(display("Failed to convert into vectors"))] IntoVectors { - #[snafu(backtrace)] + location: Location, source: datatypes::error::Error, }, #[snafu(display("Failed to deserialize partition in meta to partition def"))] DeserializePartition { - #[snafu(backtrace)] + location: Location, source: partition::error::Error, }, #[snafu(display("Failed to describe schema for given statement"))] DescribeStatement { - #[snafu(backtrace)] + location: Location, source: query::error::Error, }, @@ -249,7 +254,7 @@ pub enum Error { #[snafu(display("Unrecognized table option"))] UnrecognizedTableOption { - #[snafu(backtrace)] + location: Location, source: table::error::Error, }, @@ -262,26 +267,27 @@ pub enum Error { #[snafu(display("Failed to build regex"))] BuildRegex { location: Location, - source: regex::Error, + #[snafu(source)] + error: regex::Error, }, #[snafu(display("Failed to copy table: {}", table_name))] CopyTable { table_name: String, - #[snafu(backtrace)] + location: Location, source: table::error::Error, }, #[snafu(display("Failed to insert value into table: {}", table_name))] Insert { table_name: String, - #[snafu(backtrace)] + location: Location, source: table::error::Error, }, #[snafu(display("Failed to parse data source url"))] ParseUrl { - #[snafu(backtrace)] + location: Location, source: common_datasource::error::Error, }, @@ -290,39 +296,40 @@ pub enum Error { #[snafu(display("Failed to parse file format"))] ParseFileFormat { - #[snafu(backtrace)] + location: Location, source: common_datasource::error::Error, }, #[snafu(display("Failed to build data source backend"))] BuildBackend { - #[snafu(backtrace)] + location: Location, source: common_datasource::error::Error, }, #[snafu(display("Failed to list objects"))] ListObjects { - #[snafu(backtrace)] + location: Location, source: common_datasource::error::Error, }, #[snafu(display("Failed to infer schema from path: {}", path))] InferSchema { path: String, - #[snafu(backtrace)] + location: Location, source: common_datasource::error::Error, }, #[snafu(display("Failed to build csv config"))] BuildCsvConfig { - source: common_datasource::file_format::csv::CsvConfigBuilderError, + #[snafu(source)] + error: common_datasource::file_format::csv::CsvConfigBuilderError, location: Location, }, #[snafu(display("Failed to write stream to path: {}", path))] WriteStreamToFile { path: String, - #[snafu(backtrace)] + location: Location, source: common_datasource::error::Error, }, @@ -330,18 +337,21 @@ pub enum Error { ReadObject { path: String, location: Location, - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, }, #[snafu(display("Failed to read record batch"))] ReadDfRecordBatch { - source: datafusion::error::DataFusionError, + #[snafu(source)] + error: datafusion::error::DataFusionError, location: Location, }, #[snafu(display("Failed to read parquet file"))] ReadParquet { - source: parquet::errors::ParquetError, + #[snafu(source)] + error: parquet::errors::ParquetError, location: Location, }, @@ -354,18 +364,20 @@ pub enum Error { #[snafu(display("Failed to build parquet record batch stream"))] BuildParquetRecordBatchStream { location: Location, - source: parquet::errors::ParquetError, + #[snafu(source)] + error: parquet::errors::ParquetError, }, #[snafu(display("Failed to build file stream"))] BuildFileStream { location: Location, - source: datafusion::error::DataFusionError, + #[snafu(source)] + error: datafusion::error::DataFusionError, }, #[snafu(display("Failed to write parquet file"))] WriteParquet { - #[snafu(backtrace)] + location: Location, source: storage::error::Error, }, @@ -384,19 +396,21 @@ pub enum Error { #[snafu(display("Failed to project schema"))] ProjectSchema { - source: ArrowError, + #[snafu(source)] + error: ArrowError, location: Location, }, #[snafu(display("Failed to encode object into json"))] EncodeJson { - source: serde_json::error::Error, + #[snafu(source)] + error: serde_json::error::Error, location: Location, }, #[snafu(display("Failed to prepare immutable table"))] PrepareImmutableTable { - #[snafu(backtrace)] + location: Location, source: query::error::Error, }, @@ -457,19 +471,19 @@ pub enum Error { #[snafu(display("Failed to prepare file table"))] PrepareFileTable { - #[snafu(backtrace)] + location: Location, source: query::error::Error, }, #[snafu(display("Failed to infer file table schema"))] InferFileTableSchema { - #[snafu(backtrace)] + location: Location, source: query::error::Error, }, #[snafu(display("The schema of the file table is incompatible with the table schema"))] SchemaIncompatible { - #[snafu(backtrace)] + location: Location, source: query::error::Error, }, } @@ -502,7 +516,7 @@ impl ErrorExt for Error { Error::TableMetadataManager { source, .. } => source.status_code(), - Error::ConvertSqlValue { source, .. } | Error::ParseSql { source } => { + Error::ConvertSqlValue { source, .. } | Error::ParseSql { source, .. } => { source.status_code() } @@ -512,18 +526,18 @@ impl ErrorExt for Error { source.status_code() } - Error::Table { source } + Error::Table { source, .. } | Error::CopyTable { source, .. } | Error::Insert { source, .. } => source.status_code(), Error::ConvertColumnDefaultConstraint { source, .. } - | Error::CreateTableInfo { source } - | Error::IntoVectors { source } => source.status_code(), + | Error::CreateTableInfo { source, .. } + | Error::IntoVectors { source, .. } => source.status_code(), - Error::RequestInserts { source } => source.status_code(), - Error::RequestDeletes { source } => source.status_code(), + Error::RequestInserts { source, .. } => source.status_code(), + Error::RequestDeletes { source, .. } => source.status_code(), - Error::ColumnDataType { source } | Error::InvalidColumnDef { source, .. } => { + Error::ColumnDataType { source, .. } | Error::InvalidColumnDef { source, .. } => { source.status_code() } @@ -546,18 +560,18 @@ impl ErrorExt for Error { Error::Catalog { source, .. } => source.status_code(), - Error::BuildCreateExprOnInsertion { source } - | Error::FindNewColumnsOnInsertion { source } => source.status_code(), + Error::BuildCreateExprOnInsertion { source, .. } + | Error::FindNewColumnsOnInsertion { source, .. } => source.status_code(), Error::ExecuteStatement { source, .. } - | Error::PlanStatement { source } - | Error::ParseQuery { source } - | Error::ExecLogicalPlan { source } - | Error::DescribeStatement { source } => source.status_code(), + | Error::PlanStatement { source, .. } + | Error::ParseQuery { source, .. } + | Error::ExecLogicalPlan { source, .. } + | Error::DescribeStatement { source, .. } => source.status_code(), Error::AlterExprToRequest { source, .. } => source.status_code(), - Error::External { source } => source.status_code(), + Error::External { source, .. } => source.status_code(), Error::DeserializePartition { source, .. } | Error::FindTablePartitionRule { source, .. } | Error::SplitInsert { source, .. } @@ -570,9 +584,9 @@ impl ErrorExt for Error { StatusCode::StorageUnavailable } - Error::ListObjects { source } - | Error::ParseUrl { source } - | Error::BuildBackend { source } => source.status_code(), + Error::ListObjects { source, .. } + | Error::ParseUrl { source, .. } + | Error::BuildBackend { source, .. } => source.status_code(), Error::WriteParquet { source, .. } => source.status_code(), Error::ExecuteDdl { source, .. } => source.status_code(), diff --git a/src/operator/src/statement/ddl.rs b/src/operator/src/statement/ddl.rs index f2752eba6b46..2173e030c772 100644 --- a/src/operator/src/statement/ddl.rs +++ b/src/operator/src/statement/ddl.rs @@ -16,7 +16,7 @@ use std::collections::HashMap; use std::sync::Arc; use api::helper::ColumnDataTypeWrapper; -use api::v1::{column_def, AlterExpr, CreateTableExpr, TruncateTableExpr}; +use api::v1::{column_def, AlterExpr, CreateTableExpr}; use catalog::CatalogManagerRef; use chrono::DateTime; use common_catalog::consts::{DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME}; @@ -169,15 +169,8 @@ impl StatementExecutor { .with_context(|| TableNotFoundSnafu { table_name: table_name.to_string(), })?; - let table_id = table.table_info().ident.table_id; - - let expr = TruncateTableExpr { - catalog_name: table_name.catalog_name.clone(), - schema_name: table_name.schema_name.clone(), - table_name: table_name.table_name.clone(), - table_id: Some(api::v1::TableId { id: table_id }), - }; - self.truncate_table_procedure(&expr).await?; + let table_id = table.table_info().table_id(); + self.truncate_table_procedure(&table_name, table_id).await?; Ok(Output::AffectedRows(0)) } @@ -312,10 +305,16 @@ impl StatementExecutor { async fn truncate_table_procedure( &self, - truncate_table: &TruncateTableExpr, + table_name: &TableName, + table_id: TableId, ) -> Result { let request = SubmitDdlTaskRequest { - task: DdlTask::new_truncate_table(truncate_table.clone()), + task: DdlTask::new_truncate_table( + table_name.catalog_name.to_string(), + table_name.schema_name.to_string(), + table_name.table_name.to_string(), + table_id, + ), }; self.ddl_executor diff --git a/src/partition/Cargo.toml b/src/partition/Cargo.toml index a36962289d85..e902f7ca6faf 100644 --- a/src/partition/Cargo.toml +++ b/src/partition/Cargo.toml @@ -11,6 +11,7 @@ api = { workspace = true } async-trait = "0.1" common-catalog = { workspace = true } common-error = { workspace = true } +common-macro = { workspace = true } common-meta = { workspace = true } common-query = { workspace = true } common-telemetry = { workspace = true } diff --git a/src/partition/src/error.rs b/src/partition/src/error.rs index a8c14296e38c..44582d3270f6 100644 --- a/src/partition/src/error.rs +++ b/src/partition/src/error.rs @@ -16,14 +16,16 @@ use std::any::Any; use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use common_query::prelude::Expr; use datafusion_common::ScalarValue; use snafu::{Location, Snafu}; use store_api::storage::{RegionId, RegionNumber}; use table::metadata::TableId; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Table route manager error"))] TableRouteManager { @@ -66,13 +68,15 @@ pub enum Error { #[snafu(display("Failed to serialize value to json"))] SerializeJson { - source: serde_json::Error, + #[snafu(source)] + error: serde_json::Error, location: Location, }, #[snafu(display("Failed to deserialize value from json"))] DeserializeJson { - source: serde_json::Error, + #[snafu(source)] + error: serde_json::Error, location: Location, }, diff --git a/src/promql/src/error.rs b/src/promql/src/error.rs index ead6948aa12b..01f48c7d2478 100644 --- a/src/promql/src/error.rs +++ b/src/promql/src/error.rs @@ -16,12 +16,14 @@ use std::any::Any; use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use datafusion::error::DataFusionError; use promql_parser::parser::{Expr as PromExpr, TokenType}; use snafu::{Location, Snafu}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Unsupported expr type: {}", name))] UnsupportedExpr { name: String, location: Location }, @@ -34,7 +36,8 @@ pub enum Error { #[snafu(display("Internal error during building DataFusion plan"))] DataFusionPlanning { - source: datafusion::error::DataFusionError, + #[snafu(source)] + error: datafusion::error::DataFusionError, location: Location, }, @@ -73,7 +76,8 @@ pub enum Error { #[snafu(display("Failed to deserialize"))] Deserialize { - source: prost::DecodeError, + #[snafu(source)] + error: prost::DecodeError, location: Location, }, diff --git a/src/query/Cargo.toml b/src/query/Cargo.toml index a3cfcae78937..b922708821bd 100644 --- a/src/query/Cargo.toml +++ b/src/query/Cargo.toml @@ -21,6 +21,7 @@ common-catalog.workspace = true common-datasource.workspace = true common-error.workspace = true common-function.workspace = true +common-macro.workspace = true common-meta.workspace = true common-query.workspace = true common-recordbatch.workspace = true diff --git a/src/query/src/datafusion/error.rs b/src/query/src/datafusion/error.rs index 45d6d745b9e6..486172cf70e5 100644 --- a/src/query/src/datafusion/error.rs +++ b/src/query/src/datafusion/error.rs @@ -16,17 +16,20 @@ use std::any::Any; use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use datafusion::error::DataFusionError; use snafu::{Location, Snafu}; /// Inner error of datafusion based query engine. -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum InnerError { #[snafu(display("msg: {}", msg))] Datafusion { msg: &'static str, - source: DataFusionError, + #[snafu(source)] + error: DataFusionError, location: Location, }, diff --git a/src/query/src/error.rs b/src/query/src/error.rs index 5bbdab347261..639bb3e78f5b 100644 --- a/src/query/src/error.rs +++ b/src/query/src/error.rs @@ -17,14 +17,16 @@ use std::time::Duration; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use common_meta::table_name::TableName; use datafusion::error::DataFusionError; use datatypes::prelude::ConcreteDataType; use datatypes::value::Value; use snafu::{Location, Snafu}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Unsupported expr type: {}", name))] UnsupportedExpr { name: String, location: Location }, @@ -106,20 +108,23 @@ pub enum Error { #[snafu(display("Failed to parse timestamp `{}`", raw))] ParseTimestamp { raw: String, - source: chrono::ParseError, + #[snafu(source)] + error: chrono::ParseError, location: Location, }, #[snafu(display("Failed to parse float number `{}`", raw))] ParseFloat { raw: String, - source: std::num::ParseFloatError, + #[snafu(source)] + error: std::num::ParseFloatError, location: Location, }, #[snafu(display("DataFusion error"))] DataFusion { - source: DataFusionError, + #[snafu(source)] + error: DataFusionError, location: Location, }, @@ -138,7 +143,8 @@ pub enum Error { #[snafu(display("Cannot plan SQL: {}", sql))] PlanSql { sql: String, - source: DataFusionError, + #[snafu(source)] + error: DataFusionError, location: Location, }, @@ -194,7 +200,8 @@ pub enum Error { #[snafu(display("Failed to regex"))] BuildRegex { location: Location, - source: regex::Error, + #[snafu(source)] + error: regex::Error, }, #[snafu(display("Failed to build data source backend"))] diff --git a/src/script/Cargo.toml b/src/script/Cargo.toml index b1e0b6ba08cf..0d42ab96f9ad 100644 --- a/src/script/Cargo.toml +++ b/src/script/Cargo.toml @@ -32,6 +32,7 @@ catalog = { workspace = true } common-catalog = { workspace = true } common-error = { workspace = true } common-function = { workspace = true } +common-macro = { workspace = true } common-query = { workspace = true } common-recordbatch = { workspace = true } common-runtime = { workspace = true } diff --git a/src/script/src/error.rs b/src/script/src/error.rs index 0a1e2e6d5d2c..40ac698b6a1a 100644 --- a/src/script/src/error.rs +++ b/src/script/src/error.rs @@ -16,10 +16,12 @@ use std::any::Any; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use snafu::{Location, Snafu}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to find column in scripts table, name: {}", name))] FindColumnInScriptsTable { name: String, location: Location }, @@ -62,7 +64,8 @@ pub enum Error { #[snafu(display("Failed to build DataFusion logical plan"))] BuildDfLogicalPlan { - source: datafusion_common::DataFusionError, + #[snafu(source)] + error: datafusion_common::DataFusionError, location: Location, }, diff --git a/src/script/src/python/error.rs b/src/script/src/python/error.rs index 096cde70dc80..ad00998f3a4c 100644 --- a/src/script/src/python/error.rs +++ b/src/script/src/python/error.rs @@ -14,6 +14,7 @@ use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use console::{style, Style}; use datafusion::error::DataFusionError; use datatypes::arrow::error::ArrowError; @@ -31,8 +32,9 @@ pub(crate) fn ret_other_error_with(reason: String) -> OtherSnafu { OtherSnafu { reason } } -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub(crate)))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Datatype error"))] TypeCast { @@ -49,13 +51,15 @@ pub enum Error { #[snafu(display("Failed to parse script"))] PyParse { location: SnafuLocation, - source: ParseError, + #[snafu(source)] + error: ParseError, }, #[snafu(display("Failed to compile script"))] PyCompile { location: SnafuLocation, - source: CodegenError, + #[snafu(source)] + error: CodegenError, }, /// rustpython problem, using python virtual machines' backtrace instead @@ -68,13 +72,15 @@ pub enum Error { #[snafu(display("Arrow error"))] Arrow { location: SnafuLocation, - source: ArrowError, + #[snafu(source)] + error: ArrowError, }, #[snafu(display("DataFusion error"))] DataFusion { location: SnafuLocation, - source: DataFusionError, + #[snafu(source)] + error: DataFusionError, }, /// errors in coprocessors' parse check for types and etc. @@ -116,7 +122,10 @@ pub enum Error { source: common_recordbatch::error::Error, }, #[snafu(display("Failed to create tokio task"))] - TokioJoin { source: tokio::task::JoinError }, + TokioJoin { + #[snafu(source)] + error: tokio::task::JoinError, + }, } impl ErrorExt for Error { @@ -210,8 +219,8 @@ pub fn get_error_reason_loc(err: &Error) -> (String, Option) { Error::CoprParse { reason, loc, .. } => (reason.clone(), *loc), Error::Other { reason, .. } => (reason.clone(), None), Error::PyRuntime { msg, .. } => (msg.clone(), None), - Error::PyParse { source, .. } => (source.error.to_string(), Some(source.location)), - Error::PyCompile { source, .. } => (source.error.to_string(), Some(source.location)), + Error::PyParse { error, .. } => (error.error.to_string(), Some(error.location)), + Error::PyCompile { error, .. } => (error.error.to_string(), Some(error.location)), _ => (format!("Unknown error: {err:?}"), None), } } diff --git a/src/script/src/python/rspython/test.rs b/src/script/src/python/rspython/test.rs index 6cd2208b1ef0..a5ce5bd7b7b3 100644 --- a/src/script/src/python/rspython/test.rs +++ b/src/script/src/python/rspython/test.rs @@ -253,16 +253,12 @@ def calc_rvs(open_time, close): ) .unwrap(); let ret = exec_coprocessor(python_source, &Some(rb)); - if let Err(Error::PyParse { - location: _, - source, - }) = ret - { + if let Err(Error::PyParse { location: _, error }) = ret { let res = visualize_loc( python_source, - &source.location, + &error.location, "unknown tokens", - source.error.to_string().as_str(), + error.error.to_string().as_str(), 0, "copr.py", ); @@ -303,16 +299,12 @@ def a(cpu, mem): ) .unwrap(); let ret = exec_coprocessor(python_source, &Some(rb)); - if let Err(Error::PyParse { - location: _, - source, - }) = ret - { + if let Err(Error::PyParse { location: _, error }) = ret { let res = visualize_loc( python_source, - &source.location, + &error.location, "unknown tokens", - source.error.to_string().as_str(), + error.error.to_string().as_str(), 0, "copr.py", ); diff --git a/src/servers/Cargo.toml b/src/servers/Cargo.toml index 176ded04da08..962375a2a255 100644 --- a/src/servers/Cargo.toml +++ b/src/servers/Cargo.toml @@ -27,6 +27,7 @@ common-catalog = { workspace = true } common-error = { workspace = true } common-grpc = { workspace = true } common-grpc-expr = { workspace = true } +common-macro = { workspace = true } common-mem-prof = { workspace = true, optional = true } common-meta = { workspace = true } common-query = { workspace = true } diff --git a/src/servers/src/error.rs b/src/servers/src/error.rs index 474d5a1d9131..c1a34177e7eb 100644 --- a/src/servers/src/error.rs +++ b/src/servers/src/error.rs @@ -22,6 +22,7 @@ use base64::DecodeError; use catalog; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use common_telemetry::logging; use datatypes::prelude::ConcreteDataType; use query::parser::PromQuery; @@ -29,19 +30,24 @@ use serde_json::json; use snafu::{ErrorCompat, Location, Snafu}; use tonic::Code; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Internal error: {}", err_msg))] Internal { err_msg: String }, #[snafu(display("Internal IO error"))] - InternalIo { source: std::io::Error }, + InternalIo { + #[snafu(source)] + error: std::io::Error, + }, #[snafu(display("Tokio IO error: {}", err_msg))] TokioIo { err_msg: String, - source: std::io::Error, + #[snafu(source)] + error: std::io::Error, }, #[snafu(display("Failed to collect recordbatch"))] @@ -51,10 +57,16 @@ pub enum Error { }, #[snafu(display("Failed to start HTTP server"))] - StartHttp { source: hyper::Error }, + StartHttp { + #[snafu(source)] + error: hyper::Error, + }, #[snafu(display("Failed to start gRPC server"))] - StartGrpc { source: tonic::transport::Error }, + StartGrpc { + #[snafu(source)] + error: tonic::transport::Error, + }, #[snafu(display("{} server is already started", server))] AlreadyStarted { server: String, location: Location }, @@ -62,7 +74,8 @@ pub enum Error { #[snafu(display("Failed to bind address {}", addr))] TcpBind { addr: SocketAddr, - source: std::io::Error, + #[snafu(source)] + error: std::io::Error, }, #[snafu(display("Failed to execute query, query: {}", query))] @@ -125,7 +138,8 @@ pub enum Error { #[snafu(display("Failed to parse InfluxDB line protocol"))] InfluxdbLineProtocol { location: Location, - source: influxdb_line_protocol::Error, + #[snafu(source)] + error: influxdb_line_protocol::Error, }, #[snafu(display("Failed to write InfluxDB line protocol"))] @@ -153,36 +167,44 @@ pub enum Error { ConnResetByPeer { location: Location }, #[snafu(display("Hyper error"))] - Hyper { source: hyper::Error }, + Hyper { + #[snafu(source)] + error: hyper::Error, + }, #[snafu(display("Invalid OpenTSDB line"))] InvalidOpentsdbLine { - source: FromUtf8Error, + #[snafu(source)] + error: FromUtf8Error, location: Location, }, #[snafu(display("Invalid OpenTSDB Json request"))] InvalidOpentsdbJsonRequest { - source: serde_json::error::Error, + #[snafu(source)] + error: serde_json::error::Error, location: Location, }, #[snafu(display("Failed to decode prometheus remote request"))] DecodePromRemoteRequest { location: Location, - source: prost::DecodeError, + #[snafu(source)] + error: prost::DecodeError, }, #[snafu(display("Failed to decode OTLP request"))] DecodeOtlpRequest { location: Location, - source: prost::DecodeError, + #[snafu(source)] + error: prost::DecodeError, }, #[snafu(display("Failed to decompress prometheus remote request"))] DecompressPromRemoteRequest { location: Location, - source: snap::Error, + #[snafu(source)] + error: snap::Error, }, #[snafu(display("Invalid prometheus remote request, msg: {}", msg))] @@ -193,7 +215,8 @@ pub enum Error { #[snafu(display("Invalid Flight ticket"))] InvalidFlightTicket { - source: api::DecodeError, + #[snafu(source)] + error: api::DecodeError, location: Location, }, @@ -214,7 +237,8 @@ pub enum Error { #[snafu(display("Invalid visibility ASCII chars"))] InvisibleASCII { - source: hyper::header::ToStrError, + #[snafu(source)] + error: hyper::header::ToStrError, location: Location, }, @@ -226,13 +250,15 @@ pub enum Error { #[snafu(display("Invalid base64 value"))] InvalidBase64Value { - source: DecodeError, + #[snafu(source)] + error: DecodeError, location: Location, }, #[snafu(display("Invalid utf-8 value"))] InvalidUtf8Value { - source: FromUtf8Error, + #[snafu(source)] + error: FromUtf8Error, location: Location, }, @@ -246,7 +272,8 @@ pub enum Error { #[snafu(display("Failed to dump profile data"))] DumpProfileData { location: Location, - source: common_mem_prof::error::Error, + #[snafu(source)] + error: common_mem_prof::error::Error, }, #[snafu(display("Invalid prepare statement: {}", err_msg))] @@ -257,13 +284,15 @@ pub enum Error { #[snafu(display("Failed to build gRPC reflection service"))] GrpcReflectionService { - source: tonic_reflection::server::Error, + #[snafu(source)] + error: tonic_reflection::server::Error, location: Location, }, #[snafu(display("Failed to build HTTP response"))] BuildHttpResponse { - source: http::Error, + #[snafu(source)] + error: http::Error, location: Location, }, @@ -293,7 +322,8 @@ pub enum Error { #[snafu(display("Failed to join task"))] JoinTask { - source: tokio::task::JoinError, + #[snafu(source)] + error: tokio::task::JoinError, location: Location, }, @@ -306,7 +336,8 @@ pub enum Error { #[snafu(display("DataFrame operation error"))] DataFrame { - source: datafusion::error::DataFusionError, + #[snafu(source)] + error: datafusion::error::DataFusionError, location: Location, }, @@ -418,10 +449,10 @@ impl ErrorExt for Error { UnexpectedResult { .. } => StatusCode::Unexpected, - JoinTask { source, .. } => { - if source.is_cancelled() { + JoinTask { error, .. } => { + if error.is_cancelled() { StatusCode::Cancelled - } else if source.is_panic() { + } else if error.is_panic() { StatusCode::Unexpected } else { StatusCode::Unknown @@ -511,7 +542,7 @@ define_into_tonic_status!(Error); impl From for Error { fn from(e: std::io::Error) -> Self { - Error::InternalIo { source: e } + Error::InternalIo { error: e } } } diff --git a/src/servers/src/metrics/jemalloc/error.rs b/src/servers/src/metrics/jemalloc/error.rs index 4bbd463a360f..14c125ce6f86 100644 --- a/src/servers/src/metrics/jemalloc/error.rs +++ b/src/servers/src/metrics/jemalloc/error.rs @@ -16,14 +16,17 @@ use std::any::Any; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use snafu::{Location, Snafu}; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Failed to update jemalloc metrics"))] UpdateJemallocMetrics { - source: tikv_jemalloc_ctl::Error, + #[snafu(source)] + error: tikv_jemalloc_ctl::Error, location: Location, }, } diff --git a/src/sql/Cargo.toml b/src/sql/Cargo.toml index 3e17e1fbe36f..8472214db730 100644 --- a/src/sql/Cargo.toml +++ b/src/sql/Cargo.toml @@ -9,6 +9,7 @@ api = { workspace = true } common-base = { workspace = true } common-catalog = { workspace = true } common-error = { workspace = true } +common-macro = { workspace = true } common-query = { workspace = true } common-time = { workspace = true } datafusion-sql.workspace = true diff --git a/src/sql/src/error.rs b/src/sql/src/error.rs index 157924c3571e..9fa62dc9075d 100644 --- a/src/sql/src/error.rs +++ b/src/sql/src/error.rs @@ -16,6 +16,7 @@ use std::any::Any; use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use common_time::timestamp::TimeUnit; use common_time::Timestamp; use datatypes::prelude::{ConcreteDataType, Value}; @@ -29,8 +30,9 @@ pub type Result = std::result::Result; /// SQL parser errors. // Now the error in parser does not contains backtrace to avoid generating backtrace // every time the parser parses an invalid SQL. -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("SQL statement is not supported: {}, keyword: {}", sql, keyword))] Unsupported { sql: String, keyword: String }, @@ -45,7 +47,8 @@ pub enum Error { sql: String, expected: String, actual: String, - source: ParserError, + #[snafu(source)] + error: ParserError, }, #[snafu(display( @@ -57,7 +60,11 @@ pub enum Error { // Syntax error from sql parser. #[snafu(display("Syntax error, sql: {}", sql))] - Syntax { sql: String, source: ParserError }, + Syntax { + sql: String, + #[snafu(source)] + error: ParserError, + }, #[snafu(display("Missing time index constraint"))] MissingTimeIndex {}, diff --git a/src/sql/src/statements.rs b/src/sql/src/statements.rs index 3bb715f41fbf..743f6496c8f7 100644 --- a/src/sql/src/statements.rs +++ b/src/sql/src/statements.rs @@ -602,7 +602,7 @@ mod tests { assert!(v.is_err()); assert!( format!("{v:?}").contains( - "column_name: \"a\", expect: Float64(Float64Type), actual: Boolean(BooleanType)" + "Column a expect type: Float64(Float64Type), actual: Boolean(BooleanType))" ), "v is {v:?}", ); diff --git a/src/storage/Cargo.toml b/src/storage/Cargo.toml index a2b9a0cac6df..5b097c30ac6d 100644 --- a/src/storage/Cargo.toml +++ b/src/storage/Cargo.toml @@ -16,6 +16,7 @@ bytes = "1.1" common-base = { workspace = true } common-datasource = { workspace = true } common-error = { workspace = true } +common-macro = { workspace = true } common-query = { workspace = true } common-recordbatch = { workspace = true } common-runtime = { workspace = true } diff --git a/src/storage/src/error.rs b/src/storage/src/error.rs index 7ad09595a211..c2a043e6d07a 100644 --- a/src/storage/src/error.rs +++ b/src/storage/src/error.rs @@ -19,6 +19,7 @@ use std::str::Utf8Error; use common_datasource::compression::CompressionType; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use common_runtime::error::Error as RuntimeError; use datatypes::arrow::error::ArrowError; use datatypes::prelude::ConcreteDataType; @@ -33,8 +34,9 @@ use tokio::task::JoinError; use crate::metadata::Error as MetadataError; use crate::write_batch; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Invalid region descriptor, region: {}", region))] InvalidRegionDesc { @@ -48,7 +50,8 @@ pub enum Error { #[snafu(display("Failed to write parquet file"))] WriteParquet { - source: parquet::errors::ParquetError, + #[snafu(source)] + error: parquet::errors::ParquetError, location: Location, }, @@ -61,67 +64,77 @@ pub enum Error { #[snafu(display("Failed to create RecordBatch from vectors"))] NewRecordBatch { location: Location, - source: ArrowError, + #[snafu(source)] + error: ArrowError, }, #[snafu(display("Fail to read object from path: {}", path))] ReadObject { path: String, location: Location, - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, }, #[snafu(display("Fail to write object into path: {}", path))] WriteObject { path: String, location: Location, - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, }, #[snafu(display("Fail to delete object from path: {}", path))] DeleteObject { path: String, location: Location, - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, }, #[snafu(display("Fail to compress object by {}, path: {}", compress_type, path))] CompressObject { compress_type: CompressionType, path: String, - source: std::io::Error, + #[snafu(source)] + error: std::io::Error, }, #[snafu(display("Fail to decompress object by {}, path: {}", compress_type, path))] DecompressObject { compress_type: CompressionType, path: String, - source: std::io::Error, + #[snafu(source)] + error: std::io::Error, }, #[snafu(display("Fail to list objects in path: {}", path))] ListObjects { path: String, location: Location, - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, }, #[snafu(display("Fail to create str from bytes"))] Utf8 { location: Location, - source: Utf8Error, + #[snafu(source)] + error: Utf8Error, }, #[snafu(display("Fail to encode object into json "))] EncodeJson { location: Location, - source: JsonError, + #[snafu(source)] + error: JsonError, }, #[snafu(display("Fail to decode object from json "))] DecodeJson { location: Location, - source: JsonError, + #[snafu(source)] + error: JsonError, }, #[snafu(display("Invalid scan index, start: {}, end: {}", start, end))] @@ -141,19 +154,22 @@ pub enum Error { #[snafu(display("Failed to encode WAL header"))] EncodeWalHeader { location: Location, - source: std::io::Error, + #[snafu(source)] + error: std::io::Error, }, #[snafu(display("Failed to decode WAL header"))] DecodeWalHeader { location: Location, - source: std::io::Error, + #[snafu(source)] + error: std::io::Error, }, #[snafu(display("Failed to wait flushing, region_id: {}", region_id))] WaitFlush { region_id: RegionId, - source: tokio::sync::oneshot::error::RecvError, + #[snafu(source)] + error: tokio::sync::oneshot::error::RecvError, location: Location, }, @@ -183,12 +199,16 @@ pub enum Error { DecodeMetaActionList { msg: String, location: Location }, #[snafu(display("Failed to read line, err"))] - Readline { source: IoError }, + Readline { + #[snafu(source)] + error: IoError, + }, #[snafu(display("Failed to read Parquet file: {}", file))] ReadParquet { file: String, - source: parquet::errors::ParquetError, + #[snafu(source)] + error: parquet::errors::ParquetError, location: Location, }, @@ -385,13 +405,15 @@ pub enum Error { #[snafu(display("Failed to decode arrow data"))] DecodeArrow { location: Location, - source: ArrowError, + #[snafu(source)] + error: ArrowError, }, #[snafu(display("Failed to encode arrow data"))] EncodeArrow { location: Location, - source: ArrowError, + #[snafu(source)] + error: ArrowError, }, #[snafu(display("Failed to parse schema"))] @@ -426,13 +448,15 @@ pub enum Error { #[snafu(display("Failed to stop scheduler"))] StopScheduler { - source: JoinError, + #[snafu(source)] + error: JoinError, location: Location, }, #[snafu(display("Failed to delete SST file"))] DeleteSst { - source: object_store::Error, + #[snafu(source)] + error: object_store::Error, location: Location, }, @@ -448,7 +472,8 @@ pub enum Error { #[snafu(display("The compaction task is cancelled, region_id: {}", region_id))] CompactTaskCancel { region_id: RegionId, - source: tokio::sync::oneshot::error::RecvError, + #[snafu(source)] + error: tokio::sync::oneshot::error::RecvError, }, #[snafu(display( @@ -476,13 +501,15 @@ pub enum Error { #[snafu(display("Failed to convert columns to rows"))] ConvertColumnsToRows { - source: ArrowError, + #[snafu(source)] + error: ArrowError, location: Location, }, #[snafu(display("Failed to sort arrays"))] SortArrays { - source: ArrowError, + #[snafu(source)] + error: ArrowError, location: Location, }, @@ -494,7 +521,8 @@ pub enum Error { #[snafu(display("Failed to join spawned tasks"))] JoinError { - source: JoinError, + #[snafu(source)] + error: JoinError, location: Location, }, } @@ -505,8 +533,8 @@ impl Error { /// Returns true if the error is the object path to delete /// doesn't exist. pub(crate) fn is_object_to_delete_not_found(&self) -> bool { - if let Error::DeleteObject { source, .. } = self { - source.kind() == ErrorKind::NotFound + if let Error::DeleteObject { error, .. } = self { + error.kind() == ErrorKind::NotFound } else { false } diff --git a/src/storage/src/metadata.rs b/src/storage/src/metadata.rs index 5b3d8fbf9909..2351674125c3 100644 --- a/src/storage/src/metadata.rs +++ b/src/storage/src/metadata.rs @@ -19,6 +19,7 @@ use std::sync::Arc; use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use datatypes::data_type::ConcreteDataType; use datatypes::schema::{ColumnSchema, Metadata, COMMENT_KEY}; use serde::{Deserialize, Serialize}; @@ -35,8 +36,9 @@ use crate::manifest::action::{RawColumnFamiliesMetadata, RawColumnsMetadata, Raw use crate::schema::{RegionSchema, RegionSchemaRef}; /// Error for handling metadata. -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub(crate)))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Column name {} already exists", name))] ColNameExists { name: String, location: Location }, @@ -95,7 +97,8 @@ pub enum Error { ParseMetaInt { // Store key and value in one string to reduce the enum size. key_value: String, - source: std::num::ParseIntError, + #[snafu(source)] + error: std::num::ParseIntError, location: Location, }, @@ -104,7 +107,8 @@ pub enum Error { #[snafu(display("Failed to build column descriptor"))] BuildColumnDescriptor { - source: ColumnDescriptorBuilderError, + #[snafu(source)] + error: ColumnDescriptorBuilderError, location: Location, }, diff --git a/src/store-api/Cargo.toml b/src/store-api/Cargo.toml index b0710a76e8da..3139f276622c 100644 --- a/src/store-api/Cargo.toml +++ b/src/store-api/Cargo.toml @@ -11,6 +11,7 @@ async-trait.workspace = true bytes = "1.1" common-base = { workspace = true } common-error = { workspace = true } +common-macro = { workspace = true } common-query = { workspace = true } common-recordbatch = { workspace = true } common-time = { workspace = true } diff --git a/src/store-api/src/error.rs b/src/store-api/src/error.rs index 9c2855a0a51e..6139232dd57c 100644 --- a/src/store-api/src/error.rs +++ b/src/store-api/src/error.rs @@ -14,12 +14,14 @@ use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use snafu::{Location, Snafu}; use crate::storage::ColumnDescriptorBuilderError; -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Invalid raw region request: {err}"))] InvalidRawRegionRequest { err: String, location: Location }, @@ -33,7 +35,8 @@ pub enum Error { #[snafu(display("Failed to build column descriptor: "))] BuildColumnDescriptor { - source: ColumnDescriptorBuilderError, + #[snafu(source)] + error: ColumnDescriptorBuilderError, location: Location, }, } diff --git a/src/store-api/src/logstore/entry_stream.rs b/src/store-api/src/logstore/entry_stream.rs index 9e7e5f0cf4ed..89a8bd192e42 100644 --- a/src/store-api/src/logstore/entry_stream.rs +++ b/src/store-api/src/logstore/entry_stream.rs @@ -33,6 +33,7 @@ mod tests { use std::any::Any; use std::task::{Context, Poll}; + use common_error::ext::StackError; use futures::StreamExt; use snafu::Snafu; @@ -63,6 +64,14 @@ mod tests { } } + impl StackError for Error { + fn debug_fmt(&self, _: usize, _: &mut Vec) {} + + fn next(&self) -> Option<&dyn StackError> { + None + } + } + impl Entry for SimpleEntry { type Error = Error; type Namespace = Namespace; diff --git a/src/store-api/src/metadata.rs b/src/store-api/src/metadata.rs index 123ce83c7663..f51284e6994d 100644 --- a/src/store-api/src/metadata.rs +++ b/src/store-api/src/metadata.rs @@ -25,6 +25,7 @@ use api::v1::region::RegionColumnDef; use api::v1::SemanticType; use common_error::ext::ErrorExt; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use datatypes::arrow::datatypes::FieldRef; use datatypes::schema::{ColumnDefaultConstraint, ColumnSchema, Schema, SchemaRef}; use serde::de::Error; @@ -558,8 +559,9 @@ impl SkippedFields { } } -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum MetadataError { #[snafu(display("Invalid schema"))] InvalidSchema { @@ -573,7 +575,8 @@ pub enum MetadataError { #[snafu(display("Failed to ser/de json object"))] SerdeJson { location: Location, - source: serde_json::Error, + #[snafu(source)] + error: serde_json::Error, }, #[snafu(display("Failed to convert struct from datatypes"))] diff --git a/src/store-api/src/region_request.rs b/src/store-api/src/region_request.rs index 9085943f21e0..3e202912c743 100644 --- a/src/store-api/src/region_request.rs +++ b/src/store-api/src/region_request.rs @@ -116,6 +116,10 @@ impl RegionRequest { compact.region_id.into(), Self::Compact(RegionCompactRequest {}), )]), + region_request::Body::Truncate(truncate) => Ok(vec![( + truncate.region_id.into(), + Self::Truncate(RegionTruncateRequest {}), + )]), } } } @@ -417,6 +421,7 @@ pub struct RegionFlushRequest {} #[derive(Debug)] pub struct RegionCompactRequest {} +/// Truncate region request. #[derive(Debug)] pub struct RegionTruncateRequest {} diff --git a/src/table/Cargo.toml b/src/table/Cargo.toml index 245ef06e25dd..5d04d17ed99c 100644 --- a/src/table/Cargo.toml +++ b/src/table/Cargo.toml @@ -15,6 +15,7 @@ common-base = { workspace = true } common-catalog = { workspace = true } common-datasource = { workspace = true } common-error = { workspace = true } +common-macro = { workspace = true } common-procedure = { workspace = true } common-query = { workspace = true } common-recordbatch = { workspace = true } diff --git a/src/table/src/error.rs b/src/table/src/error.rs index ab44d02bbb93..6146309d8ddf 100644 --- a/src/table/src/error.rs +++ b/src/table/src/error.rs @@ -16,6 +16,7 @@ use std::any::Any; use common_error::ext::{BoxedError, ErrorExt}; use common_error::status_code::StatusCode; +use common_macro::stack_trace_debug; use datafusion::error::DataFusionError; use datatypes::arrow::error::ArrowError; use snafu::{Location, Snafu}; @@ -25,12 +26,14 @@ use crate::metadata::TableId; pub type Result = std::result::Result; /// Default error implementation of table. -#[derive(Debug, Snafu)] +#[derive(Snafu)] #[snafu(visibility(pub))] +#[stack_trace_debug] pub enum Error { #[snafu(display("Datafusion error"))] Datafusion { - source: DataFusionError, + #[snafu(source)] + error: DataFusionError, location: Location, }, @@ -48,7 +51,8 @@ pub enum Error { #[snafu(display("Table projection error"))] TableProjection { - source: ArrowError, + #[snafu(source)] + error: ArrowError, location: Location, }, @@ -99,7 +103,8 @@ pub enum Error { column_name, ))] BuildColumnDescriptor { - source: store_api::storage::ColumnDescriptorBuilderError, + #[snafu(source)] + error: store_api::storage::ColumnDescriptorBuilderError, table_name: String, column_name: String, location: Location, diff --git a/tests/cases/standalone/common/truncate/truncate.result b/tests/cases/standalone/common/truncate/truncate.result new file mode 100644 index 000000000000..4267bc04d719 --- /dev/null +++ b/tests/cases/standalone/common/truncate/truncate.result @@ -0,0 +1,76 @@ +TRUNCATE TABLE not_exits_table; + +Error: 4001(TableNotFound), Table not found: greptime.public.not_exits_table + +CREATE TABLE monitor (host STRING, ts TIMESTAMP, cpu DOUBLE DEFAULT 0, memory DOUBLE, TIME INDEX (ts), PRIMARY KEY(host)); + +Affected Rows: 0 + +INSERT INTO monitor(ts, host, cpu, memory) VALUES +(1695217652000, 'host1', 66.6, 1024), +(1695217652000, 'host2', 66.6, 1024), +(1695217652000, 'host3', 66.6, 1024), +(1695217654000, 'host1', 77.7, 2048), +(1695217654000, 'host2', 77.7, 2048), +(1695217654000, 'host3', 77.7, 2048), +(1695217656000, 'host1', 88.8, 4096), +(1695217656000, 'host2', 88.8, 4096), +(1695217656000, 'host3', 88.8, 4096); + +Affected Rows: 9 + +SELECT ts, host, cpu, memory FROM monitor ORDER BY ts; + ++---------------------+-------+------+--------+ +| ts | host | cpu | memory | ++---------------------+-------+------+--------+ +| 2023-09-20T13:47:32 | host1 | 66.6 | 1024.0 | +| 2023-09-20T13:47:32 | host2 | 66.6 | 1024.0 | +| 2023-09-20T13:47:32 | host3 | 66.6 | 1024.0 | +| 2023-09-20T13:47:34 | host1 | 77.7 | 2048.0 | +| 2023-09-20T13:47:34 | host2 | 77.7 | 2048.0 | +| 2023-09-20T13:47:34 | host3 | 77.7 | 2048.0 | +| 2023-09-20T13:47:36 | host1 | 88.8 | 4096.0 | +| 2023-09-20T13:47:36 | host2 | 88.8 | 4096.0 | +| 2023-09-20T13:47:36 | host3 | 88.8 | 4096.0 | ++---------------------+-------+------+--------+ + +TRUNCATE monitor; + +Affected Rows: 0 + +SELECT ts, host, cpu, memory FROM monitor ORDER BY ts; + +++ +++ + +INSERT INTO monitor(ts, host, cpu, memory) VALUES +(1695217660000, 'host1', 88.8, 4096), +(1695217662000, 'host2', 88.8, 4096), +(1695217664000, 'host3', 88.8, 4096); + +Affected Rows: 3 + +SELECT ts, host, cpu, memory FROM monitor ORDER BY ts; + ++---------------------+-------+------+--------+ +| ts | host | cpu | memory | ++---------------------+-------+------+--------+ +| 2023-09-20T13:47:40 | host1 | 88.8 | 4096.0 | +| 2023-09-20T13:47:42 | host2 | 88.8 | 4096.0 | +| 2023-09-20T13:47:44 | host3 | 88.8 | 4096.0 | ++---------------------+-------+------+--------+ + +TRUNCATE monitor; + +Affected Rows: 0 + +SELECT ts, host, cpu, memory FROM monitor ORDER BY ts; + +++ +++ + +DROP TABLE monitor; + +Affected Rows: 1 + diff --git a/tests/cases/standalone/common/truncate/truncate.sql b/tests/cases/standalone/common/truncate/truncate.sql new file mode 100644 index 000000000000..61b69901254d --- /dev/null +++ b/tests/cases/standalone/common/truncate/truncate.sql @@ -0,0 +1,33 @@ +TRUNCATE TABLE not_exits_table; + +CREATE TABLE monitor (host STRING, ts TIMESTAMP, cpu DOUBLE DEFAULT 0, memory DOUBLE, TIME INDEX (ts), PRIMARY KEY(host)); + +INSERT INTO monitor(ts, host, cpu, memory) VALUES +(1695217652000, 'host1', 66.6, 1024), +(1695217652000, 'host2', 66.6, 1024), +(1695217652000, 'host3', 66.6, 1024), +(1695217654000, 'host1', 77.7, 2048), +(1695217654000, 'host2', 77.7, 2048), +(1695217654000, 'host3', 77.7, 2048), +(1695217656000, 'host1', 88.8, 4096), +(1695217656000, 'host2', 88.8, 4096), +(1695217656000, 'host3', 88.8, 4096); + +SELECT ts, host, cpu, memory FROM monitor ORDER BY ts; + +TRUNCATE monitor; + +SELECT ts, host, cpu, memory FROM monitor ORDER BY ts; + +INSERT INTO monitor(ts, host, cpu, memory) VALUES +(1695217660000, 'host1', 88.8, 4096), +(1695217662000, 'host2', 88.8, 4096), +(1695217664000, 'host3', 88.8, 4096); + +SELECT ts, host, cpu, memory FROM monitor ORDER BY ts; + +TRUNCATE monitor; + +SELECT ts, host, cpu, memory FROM monitor ORDER BY ts; + +DROP TABLE monitor;