| // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. See the AUTHORS file for names of contributors. |
| |
| #pragma once |
| |
| #include <fmt/format.h> |
| #include <gen_cpp/Status_types.h> // for TStatus |
| #include <gen_cpp/types.pb.h> |
| #include <glog/logging.h> |
| |
| #include <cstdint> |
| #include <iostream> |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| #include <utility> |
| |
| #include "common/compiler_util.h" // IWYU pragma: keep |
| #include "common/config.h" |
| #include "common/expected.h" |
| #include "util/stack_util.h" |
| |
| namespace doris { |
| |
| namespace io { |
| struct ObjectStorageStatus; |
| } |
| |
| class Status; |
| |
| extern io::ObjectStorageStatus convert_to_obj_response(Status st); |
| |
| class PStatus; |
| |
| namespace ErrorCode { |
| |
| // E thrift_error_name, print_stacktrace |
| #define APPLY_FOR_THRIFT_ERROR_CODES(TStatusError) \ |
| TStatusError(PUBLISH_TIMEOUT, false); \ |
| TStatusError(MEM_ALLOC_FAILED, true); \ |
| TStatusError(BUFFER_ALLOCATION_FAILED, true); \ |
| TStatusError(INVALID_ARGUMENT, false); \ |
| TStatusError(INVALID_JSON_PATH, false); \ |
| TStatusError(MINIMUM_RESERVATION_UNAVAILABLE, true); \ |
| TStatusError(CORRUPTION, true); \ |
| TStatusError(IO_ERROR, true); \ |
| TStatusError(NOT_FOUND, true); \ |
| TStatusError(ALREADY_EXIST, true); \ |
| TStatusError(DIRECTORY_NOT_EMPTY, true); \ |
| TStatusError(NOT_IMPLEMENTED_ERROR, false); \ |
| TStatusError(END_OF_FILE, false); \ |
| TStatusError(INTERNAL_ERROR, true); \ |
| TStatusError(RUNTIME_ERROR, true); \ |
| TStatusError(JNI_ERROR, true); \ |
| TStatusError(CANCELLED, false); \ |
| TStatusError(ANALYSIS_ERROR, false); \ |
| TStatusError(MEM_LIMIT_EXCEEDED, false); \ |
| TStatusError(THRIFT_RPC_ERROR, true); \ |
| TStatusError(TIMEOUT, true); \ |
| TStatusError(LIMIT_REACH, false); \ |
| TStatusError(TOO_MANY_TASKS, true); \ |
| TStatusError(UNINITIALIZED, false); \ |
| TStatusError(INCOMPLETE, false); \ |
| TStatusError(OLAP_ERR_VERSION_ALREADY_MERGED, false); \ |
| TStatusError(ABORTED, false); \ |
| TStatusError(DATA_QUALITY_ERROR, false); \ |
| TStatusError(LABEL_ALREADY_EXISTS, true); \ |
| TStatusError(NOT_AUTHORIZED, true); \ |
| TStatusError(BINLOG_DISABLE, false); \ |
| TStatusError(BINLOG_TOO_OLD_COMMIT_SEQ, false); \ |
| TStatusError(BINLOG_TOO_NEW_COMMIT_SEQ, false); \ |
| TStatusError(BINLOG_NOT_FOUND_DB, false); \ |
| TStatusError(BINLOG_NOT_FOUND_TABLE, false); \ |
| TStatusError(NETWORK_ERROR, false); \ |
| TStatusError(ILLEGAL_STATE, false); \ |
| TStatusError(SNAPSHOT_NOT_EXIST, true); \ |
| TStatusError(HTTP_ERROR, true); \ |
| TStatusError(TABLET_MISSING, true); \ |
| TStatusError(NOT_MASTER, true); \ |
| TStatusError(OBTAIN_LOCK_FAILED, false); \ |
| TStatusError(SNAPSHOT_EXPIRED, false); \ |
| TStatusError(DELETE_BITMAP_LOCK_ERROR, false); \ |
| TStatusError(FINISHED, false); |
| // E error_name, error_code, print_stacktrace |
| #define APPLY_FOR_OLAP_ERROR_CODES(E) \ |
| E(OK, 0, false); \ |
| E(CALL_SEQUENCE_ERROR, -202, true); \ |
| E(BUFFER_OVERFLOW, -204, true); \ |
| E(CONFIG_ERROR, -205, true); \ |
| E(INIT_FAILED, -206, true); \ |
| E(INVALID_SCHEMA, -207, true); \ |
| E(CHECKSUM_ERROR, -208, true); \ |
| E(SIGNATURE_ERROR, -209, true); \ |
| E(CATCH_EXCEPTION, -210, true); \ |
| E(PARSE_PROTOBUF_ERROR, -211, true); \ |
| E(SERIALIZE_PROTOBUF_ERROR, -212, true); \ |
| E(WRITE_PROTOBUF_ERROR, -213, true); \ |
| E(VERSION_NOT_EXIST, -214, false); \ |
| E(TABLE_NOT_FOUND, -215, true); \ |
| E(TRY_LOCK_FAILED, -216, false); \ |
| E(EXCEEDED_LIMIT, -217, false); \ |
| E(OUT_OF_BOUND, -218, false); \ |
| E(INVALID_ROOT_PATH, -222, true); \ |
| E(NO_AVAILABLE_ROOT_PATH, -223, true); \ |
| E(CHECK_LINES_ERROR, -224, true); \ |
| E(INVALID_CLUSTER_INFO, -225, true); \ |
| E(TRANSACTION_NOT_EXIST, -226, false); \ |
| E(DISK_FAILURE, -227, true); \ |
| E(TRANSACTION_ALREADY_COMMITTED, -228, false); \ |
| E(TRANSACTION_ALREADY_VISIBLE, -229, false); \ |
| E(VERSION_ALREADY_MERGED, -230, true); \ |
| E(LZO_DISABLED, -231, true); \ |
| E(DISK_REACH_CAPACITY_LIMIT, -232, true); \ |
| E(TOO_MANY_TRANSACTIONS, -233, false); \ |
| E(INVALID_SNAPSHOT_VERSION, -234, true); \ |
| E(TOO_MANY_VERSION, -235, false); \ |
| E(NOT_INITIALIZED, -236, true); \ |
| E(ALREADY_CANCELLED, -237, false); \ |
| E(TOO_MANY_SEGMENTS, -238, false); \ |
| E(ALREADY_CLOSED, -239, false); \ |
| E(SERVICE_UNAVAILABLE, -240, true); \ |
| E(NEED_SEND_AGAIN, -241, false); \ |
| E(OS_ERROR, -242, true); \ |
| E(DIR_NOT_EXIST, -243, true); \ |
| E(CREATE_FILE_ERROR, -245, true); \ |
| E(STL_ERROR, -246, true); \ |
| E(MUTEX_ERROR, -247, true); \ |
| E(PTHREAD_ERROR, -248, true); \ |
| E(UB_FUNC_ERROR, -250, true); \ |
| E(COMPRESS_ERROR, -251, true); \ |
| E(DECOMPRESS_ERROR, -252, true); \ |
| E(FILE_ALREADY_EXIST, -253, true); \ |
| E(BAD_CAST, -254, true); \ |
| E(ARITHMETIC_OVERFLOW_ERRROR, -255, false); \ |
| E(PERMISSION_DENIED, -256, false); \ |
| E(QUERY_MEMORY_EXCEEDED, -257, false); \ |
| E(WORKLOAD_GROUP_MEMORY_EXCEEDED, -258, false); \ |
| E(PROCESS_MEMORY_EXCEEDED, -259, false); \ |
| E(INVALID_INPUT_SYNTAX, -260, false); \ |
| E(CE_CMD_PARAMS_ERROR, -300, true); \ |
| E(CE_BUFFER_TOO_SMALL, -301, true); \ |
| E(CE_CMD_NOT_VALID, -302, true); \ |
| E(CE_LOAD_TABLE_ERROR, -303, true); \ |
| E(CE_NOT_FINISHED, -304, true); \ |
| E(CE_TABLET_ID_EXIST, -305, true); \ |
| E(TABLE_VERSION_DUPLICATE_ERROR, -400, true); \ |
| E(TABLE_VERSION_INDEX_MISMATCH_ERROR, -401, true); \ |
| E(TABLE_INDEX_VALIDATE_ERROR, -402, true); \ |
| E(TABLE_INDEX_FIND_ERROR, -403, true); \ |
| E(TABLE_CREATE_FROM_HEADER_ERROR, -404, true); \ |
| E(TABLE_CREATE_META_ERROR, -405, true); \ |
| E(TABLE_ALREADY_DELETED_ERROR, -406, false); \ |
| E(ENGINE_INSERT_EXISTS_TABLE, -500, true); \ |
| E(ENGINE_DROP_NOEXISTS_TABLE, -501, true); \ |
| E(ENGINE_LOAD_INDEX_TABLE_ERROR, -502, true); \ |
| E(TABLE_INSERT_DUPLICATION_ERROR, -503, true); \ |
| E(DELETE_VERSION_ERROR, -504, true); \ |
| E(GC_SCAN_PATH_ERROR, -505, true); \ |
| E(ENGINE_INSERT_OLD_TABLET, -506, true); \ |
| E(FETCH_OTHER_ERROR, -600, true); \ |
| E(FETCH_TABLE_NOT_EXIST, -601, true); \ |
| E(FETCH_VERSION_ERROR, -602, true); \ |
| E(FETCH_SCHEMA_ERROR, -603, true); \ |
| E(FETCH_COMPRESSION_ERROR, -604, true); \ |
| E(FETCH_CONTEXT_NOT_EXIST, -605, true); \ |
| E(FETCH_GET_READER_PARAMS_ERR, -606, true); \ |
| E(FETCH_SAVE_SESSION_ERR, -607, true); \ |
| E(FETCH_MEMORY_EXCEEDED, -608, true); \ |
| E(READER_IS_UNINITIALIZED, -700, true); \ |
| E(READER_GET_ITERATOR_ERROR, -701, true); \ |
| E(CAPTURE_ROWSET_READER_ERROR, -702, true); \ |
| E(READER_READING_ERROR, -703, true); \ |
| E(READER_INITIALIZE_ERROR, -704, true); \ |
| E(BE_VERSION_NOT_MATCH, -800, true); \ |
| E(BE_REPLACE_VERSIONS_ERROR, -801, true); \ |
| E(BE_MERGE_ERROR, -802, true); \ |
| E(CAPTURE_ROWSET_ERROR, -804, true); \ |
| E(BE_SAVE_HEADER_ERROR, -805, true); \ |
| E(BE_INIT_OLAP_DATA, -806, true); \ |
| E(BE_TRY_OBTAIN_VERSION_LOCKS, -807, true); \ |
| E(BE_NO_SUITABLE_VERSION, -808, false); \ |
| E(BE_INVALID_NEED_MERGED_VERSIONS, -810, true); \ |
| E(BE_ERROR_DELETE_ACTION, -811, true); \ |
| E(BE_SEGMENTS_OVERLAPPING, -812, true); \ |
| E(PUSH_INIT_ERROR, -900, true); \ |
| E(PUSH_VERSION_INCORRECT, -902, true); \ |
| E(PUSH_SCHEMA_MISMATCH, -903, true); \ |
| E(PUSH_CHECKSUM_ERROR, -904, true); \ |
| E(PUSH_ACQUIRE_DATASOURCE_ERROR, -905, true); \ |
| E(PUSH_CREAT_CUMULATIVE_ERROR, -906, true); \ |
| E(PUSH_BUILD_DELTA_ERROR, -907, true); \ |
| E(PUSH_VERSION_ALREADY_EXIST, -908, false); \ |
| E(PUSH_TABLE_NOT_EXIST, -909, true); \ |
| E(PUSH_INPUT_DATA_ERROR, -910, true); \ |
| E(PUSH_TRANSACTION_ALREADY_EXIST, -911, false); \ |
| E(PUSH_BATCH_PROCESS_REMOVED, -912, true); \ |
| E(PUSH_COMMIT_ROWSET, -913, true); \ |
| E(PUSH_ROWSET_NOT_FOUND, -914, true); \ |
| E(INDEX_LOAD_ERROR, -1000, true); \ |
| E(INDEX_CHECKSUM_ERROR, -1002, true); \ |
| E(INDEX_DELTA_PRUNING, -1003, true); \ |
| E(DATA_ROW_BLOCK_ERROR, -1100, true); \ |
| E(DATA_FILE_TYPE_ERROR, -1101, true); \ |
| E(WRITER_INDEX_WRITE_ERROR, -1200, true); \ |
| E(WRITER_DATA_WRITE_ERROR, -1201, true); \ |
| E(WRITER_ROW_BLOCK_ERROR, -1202, true); \ |
| E(WRITER_SEGMENT_NOT_FINALIZED, -1203, true); \ |
| E(ROWBLOCK_DECOMPRESS_ERROR, -1300, true); \ |
| E(ROWBLOCK_FIND_ROW_EXCEPTION, -1301, true); \ |
| E(HEADER_ADD_VERSION, -1400, true); \ |
| E(HEADER_DELETE_VERSION, -1401, true); \ |
| E(HEADER_ADD_PENDING_DELTA, -1402, true); \ |
| E(HEADER_ADD_INCREMENTAL_VERSION, -1403, true); \ |
| E(HEADER_INVALID_FLAG, -1404, true); \ |
| E(HEADER_LOAD_INVALID_KEY, -1408, true); \ |
| E(HEADER_LOAD_JSON_HEADER, -1410, true); \ |
| E(HEADER_INIT_FAILED, -1411, true); \ |
| E(HEADER_PB_PARSE_FAILED, -1412, true); \ |
| E(HEADER_HAS_PENDING_DATA, -1413, true); \ |
| E(SCHEMA_SCHEMA_INVALID, -1500, true); \ |
| E(SCHEMA_SCHEMA_FIELD_INVALID, -1501, true); \ |
| E(ALTER_MULTI_TABLE_ERR, -1600, true); \ |
| E(ALTER_DELTA_DOES_NOT_EXISTS, -1601, true); \ |
| E(ALTER_STATUS_ERR, -1602, true); \ |
| E(PREVIOUS_SCHEMA_CHANGE_NOT_FINISHED, -1603, true); \ |
| E(SCHEMA_CHANGE_INFO_INVALID, -1604, true); \ |
| E(QUERY_SPLIT_KEY_ERR, -1605, true); \ |
| E(DATA_QUALITY_ERR, -1606, false); \ |
| E(COLUMN_DATA_LOAD_BLOCK, -1700, true); \ |
| E(COLUMN_DATA_RECORD_INDEX, -1701, true); \ |
| E(COLUMN_DATA_MAKE_FILE_HEADER, -1702, true); \ |
| E(COLUMN_DATA_READ_VAR_INT, -1703, true); \ |
| E(COLUMN_DATA_PATCH_LIST_NUM, -1704, true); \ |
| E(COLUMN_READ_STREAM, -1706, true); \ |
| E(COLUMN_STREAM_NOT_EXIST, -1716, true); \ |
| E(COLUMN_VALUE_NULL, -1717, true); \ |
| E(COLUMN_SEEK_ERROR, -1719, true); \ |
| E(COLUMN_NO_MATCH_OFFSETS_SIZE, -1720, true); \ |
| E(COLUMN_NO_MATCH_FILTER_SIZE, -1721, true); \ |
| E(DELETE_INVALID_CONDITION, -1900, true); \ |
| E(DELETE_UPDATE_HEADER_FAILED, -1901, true); \ |
| E(DELETE_SAVE_HEADER_FAILED, -1902, true); \ |
| E(DELETE_INVALID_PARAMETERS, -1903, true); \ |
| E(DELETE_INVALID_VERSION, -1904, true); \ |
| E(CUMULATIVE_NO_SUITABLE_VERSION, -2000, false); \ |
| E(CUMULATIVE_REPEAT_INIT, -2001, true); \ |
| E(CUMULATIVE_INVALID_PARAMETERS, -2002, true); \ |
| E(CUMULATIVE_FAILED_ACQUIRE_DATA_SOURCE, -2003, true); \ |
| E(CUMULATIVE_INVALID_NEED_MERGED_VERSIONS, -2004, true); \ |
| E(CUMULATIVE_ERROR_DELETE_ACTION, -2005, true); \ |
| E(CUMULATIVE_MISS_VERSION, -2006, true); \ |
| E(FULL_NO_SUITABLE_VERSION, -2008, false); \ |
| E(FULL_MISS_VERSION, -2009, true); \ |
| E(CUMULATIVE_MEET_DELETE_VERSION, -2010, false); \ |
| E(META_INVALID_ARGUMENT, -3000, true); \ |
| E(META_OPEN_DB_ERROR, -3001, true); \ |
| E(META_KEY_NOT_FOUND, -3002, false); \ |
| E(META_GET_ERROR, -3003, true); \ |
| E(META_PUT_ERROR, -3004, true); \ |
| E(META_ITERATOR_ERROR, -3005, true); \ |
| E(META_DELETE_ERROR, -3006, true); \ |
| E(META_ALREADY_EXIST, -3007, true); \ |
| E(ROWSET_WRITER_INIT, -3100, true); \ |
| E(ROWSET_SAVE_FAILED, -3101, true); \ |
| E(ROWSET_GENERATE_ID_FAILED, -3102, true); \ |
| E(ROWSET_DELETE_FILE_FAILED, -3103, true); \ |
| E(ROWSET_BUILDER_INIT, -3104, true); \ |
| E(ROWSET_TYPE_NOT_FOUND, -3105, true); \ |
| E(ROWSET_ALREADY_EXIST, -3106, true); \ |
| E(ROWSET_CREATE_READER, -3107, true); \ |
| E(ROWSET_INVALID, -3108, true); \ |
| E(ROWSET_READER_INIT, -3110, true); \ |
| E(ROWSET_INVALID_STATE_TRANSITION, -3112, true); \ |
| E(STRING_OVERFLOW_IN_VEC_ENGINE, -3113, true); \ |
| E(ROWSET_ADD_MIGRATION_V2, -3114, true); \ |
| E(PUBLISH_VERSION_NOT_CONTINUOUS, -3115, false); \ |
| E(ROWSET_RENAME_FILE_FAILED, -3116, false); \ |
| E(SEGCOMPACTION_INIT_READER, -3117, false); \ |
| E(SEGCOMPACTION_INIT_WRITER, -3118, false); \ |
| E(SEGCOMPACTION_FAILED, -3119, false); \ |
| E(ROWSET_ADD_TO_BINLOG_FAILED, -3122, true); \ |
| E(ROWSET_BINLOG_NOT_ONLY_ONE_VERSION, -3123, true); \ |
| E(INDEX_INVALID_PARAMETERS, -6000, false); \ |
| E(INVERTED_INDEX_NOT_SUPPORTED, -6001, false); \ |
| E(INVERTED_INDEX_CLUCENE_ERROR, -6002, false); \ |
| E(INVERTED_INDEX_FILE_NOT_FOUND, -6003, false); \ |
| E(INVERTED_INDEX_BYPASS, -6004, false); \ |
| E(INVERTED_INDEX_NO_TERMS, -6005, false); \ |
| E(INVERTED_INDEX_RENAME_FILE_FAILED, -6006, true); \ |
| E(INVERTED_INDEX_EVALUATE_SKIPPED, -6007, false); \ |
| E(INVERTED_INDEX_BUILD_WAITTING, -6008, false); \ |
| E(INVERTED_INDEX_NOT_IMPLEMENTED, -6009, false); \ |
| E(INVERTED_INDEX_COMPACTION_ERROR, -6010, false); \ |
| E(INVERTED_INDEX_ANALYZER_ERROR, -6011, false); \ |
| E(INVERTED_INDEX_FILE_CORRUPTED, -6012, false); \ |
| E(KEY_NOT_FOUND, -7000, false); \ |
| E(KEY_ALREADY_EXISTS, -7001, false); \ |
| E(ENTRY_NOT_FOUND, -7002, false); \ |
| E(NEW_ROWS_IN_PARTIAL_UPDATE, -7003, false); \ |
| E(INVALID_TABLET_STATE, -7211, false); \ |
| E(ROWSETS_EXPIRED, -7311, false); \ |
| E(CGROUP_ERROR, -7411, false); \ |
| E(FATAL_ERROR, -7412, true); |
| |
| // Define constexpr int error_code_name = error_code_value |
| #define M(NAME, ERRORCODE, ENABLESTACKTRACE) constexpr int NAME = ERRORCODE; |
| APPLY_FOR_OLAP_ERROR_CODES(M) |
| #undef M |
| |
| #define MM(name, ENABLESTACKTRACE) constexpr int name = TStatusCode::name; |
| APPLY_FOR_THRIFT_ERROR_CODES(MM) |
| #undef MM |
| |
| constexpr int MAX_ERROR_CODE_DEFINE_NUM = 65536; |
| struct ErrorCodeState { |
| int16_t error_code = 0; |
| bool stacktrace = true; |
| std::string description; |
| size_t count = 0; // Used for count the number of error happens |
| std::mutex mutex; // lock guard for count state |
| }; |
| extern ErrorCodeState error_states[MAX_ERROR_CODE_DEFINE_NUM]; |
| |
| class ErrorCodeInitializer { |
| public: |
| ErrorCodeInitializer(int temp) : signal_value(temp) { |
| for (auto& error_state : error_states) { |
| error_state.error_code = 0; |
| } |
| #define M(NAME, ENABLESTACKTRACE) \ |
| error_states[TStatusCode::NAME].stacktrace = ENABLESTACKTRACE; \ |
| error_states[TStatusCode::NAME].description = #NAME; \ |
| error_states[TStatusCode::NAME].error_code = TStatusCode::NAME; |
| APPLY_FOR_THRIFT_ERROR_CODES(M) |
| #undef M |
| // In status.h, if error code > 0, then it means it will be used in TStatusCode and will |
| // also be used in FE. |
| // Other error codes that with error code < 0, will only be used in BE. |
| // We use abs(error code) as the index in error_states, so that these two kinds of error |
| // codes MUST not have overlap. |
| // Add an assert here to make sure the code in TStatusCode and other error code are not |
| // overlapped. |
| #define M(NAME, ERRORCODE, ENABLESTACKTRACE) \ |
| assert(error_states[abs(ERRORCODE)].error_code == 0); \ |
| error_states[abs(ERRORCODE)].stacktrace = ENABLESTACKTRACE; \ |
| error_states[abs(ERRORCODE)].error_code = ERRORCODE; |
| APPLY_FOR_OLAP_ERROR_CODES(M) |
| #undef M |
| } |
| |
| void check_init() const { |
| //the signal value is 0, it means the global error states not inited, it's logical error |
| // DO NOT use dcheck here, because dcheck depend on glog, and glog maybe not inited at this time. |
| if (signal_value == 0) { |
| exit(-1); |
| } |
| } |
| |
| private: |
| int signal_value = 0; |
| }; |
| |
| extern ErrorCodeInitializer error_code_init; |
| } // namespace ErrorCode |
| |
| class [[nodiscard]] Status { |
| public: |
| Status() : _code(ErrorCode::OK), _err_msg(nullptr) {} |
| |
| // used to convert Exception to Status |
| Status(int code, std::string msg, std::string stack = "") : _code(code) { |
| _err_msg = std::make_unique<ErrMsg>(); |
| _err_msg->_msg = std::move(msg); |
| if (config::enable_stacktrace) { |
| _err_msg->_stack = std::move(stack); |
| } |
| } |
| |
| // copy c'tor makes copy of error detail so Status can be returned by value |
| Status(const Status& rhs) { *this = rhs; } |
| |
| // move c'tor |
| Status(Status&& rhs) noexcept = default; |
| |
| // same as copy c'tor |
| Status& operator=(const Status& rhs) { |
| _code = rhs._code; |
| if (rhs._err_msg) { |
| _err_msg = std::make_unique<ErrMsg>(*rhs._err_msg); |
| } else { |
| // If rhs error msg is empty, then should also clear current error msg |
| // For example, if rhs is OK and current status is error, then copy to current |
| // status, should clear current error message. |
| _err_msg.reset(); |
| } |
| return *this; |
| } |
| |
| // move assign |
| Status& operator=(Status&& rhs) noexcept { |
| _code = rhs._code; |
| if (rhs._err_msg) { |
| _err_msg = std::move(rhs._err_msg); |
| } else { |
| _err_msg.reset(); |
| } |
| return *this; |
| } |
| |
| template <bool stacktrace = true> |
| Status static create(const TStatus& status) { |
| return Error<stacktrace>( |
| status.status_code, |
| "TStatus: " + (status.error_msgs.empty() ? "" : status.error_msgs[0])); |
| } |
| |
| template <bool stacktrace = true> |
| Status static create(const PStatus& pstatus) { |
| return Error<stacktrace>( |
| pstatus.status_code(), |
| "PStatus: " + (pstatus.error_msgs_size() == 0 ? "" : pstatus.error_msgs(0))); |
| } |
| |
| template <int code, bool stacktrace = true, typename... Args> |
| Status static Error(std::string_view msg, Args&&... args) { |
| Status status; |
| status._code = code; |
| status._err_msg = std::make_unique<ErrMsg>(); |
| if constexpr (sizeof...(args) == 0) { |
| status._err_msg->_msg = msg; |
| } else { |
| status._err_msg->_msg = fmt::format(msg, std::forward<Args>(args)...); |
| } |
| if (stacktrace && ErrorCode::error_states[abs(code)].stacktrace && |
| config::enable_stacktrace) { |
| // Delete the first one frame pointers, which are inside the status.h |
| status._err_msg->_stack = get_stack_trace(1); |
| LOG(WARNING) << "meet error status: " << status; // may print too many stacks. |
| } |
| return status; |
| } |
| |
| template <bool stacktrace = true, typename... Args> |
| Status static Error(int code, std::string_view msg, Args&&... args) { |
| Status status; |
| status._code = code; |
| status._err_msg = std::make_unique<ErrMsg>(); |
| if constexpr (sizeof...(args) == 0) { |
| status._err_msg->_msg = msg; |
| } else { |
| status._err_msg->_msg = fmt::format(msg, std::forward<Args>(args)...); |
| } |
| if (stacktrace && ErrorCode::error_states[abs(code)].stacktrace && |
| config::enable_stacktrace) { |
| status._err_msg->_stack = get_stack_trace(1); |
| LOG(WARNING) << "meet error status: " << status; // may print too many stacks. |
| } |
| return status; |
| } |
| |
| static Status OK() { return {}; } |
| |
| template <bool stacktrace = true, typename... Args> |
| static Status FatalError(std::string_view msg, Args&&... args) { |
| #ifndef NDEBUG |
| LOG(FATAL) << fmt::format(msg, std::forward<Args>(args)...); |
| #endif |
| return Error<ErrorCode::FATAL_ERROR, stacktrace>(msg, std::forward<Args>(args)...); |
| } |
| |
| // default have stacktrace. could disable manually. |
| #define ERROR_CTOR(name, code) \ |
| template <bool stacktrace = true, typename... Args> \ |
| static Status name(std::string_view msg, Args&&... args) { \ |
| return Error<ErrorCode::code, stacktrace>(msg, std::forward<Args>(args)...); \ |
| } |
| |
| // default have no stacktrace. could enable manually. |
| #define ERROR_CTOR_NOSTACK(name, code) \ |
| template <bool stacktrace = false, typename... Args> \ |
| static Status name(std::string_view msg, Args&&... args) { \ |
| return Error<ErrorCode::code, stacktrace>(msg, std::forward<Args>(args)...); \ |
| } |
| |
| ERROR_CTOR(PublishTimeout, PUBLISH_TIMEOUT) |
| ERROR_CTOR(MemoryAllocFailed, MEM_ALLOC_FAILED) |
| ERROR_CTOR(BufferAllocFailed, BUFFER_ALLOCATION_FAILED) |
| ERROR_CTOR_NOSTACK(InvalidArgument, INVALID_ARGUMENT) |
| ERROR_CTOR_NOSTACK(InvalidJsonPath, INVALID_JSON_PATH) |
| ERROR_CTOR(MinimumReservationUnavailable, MINIMUM_RESERVATION_UNAVAILABLE) |
| ERROR_CTOR(Corruption, CORRUPTION) |
| ERROR_CTOR(IOError, IO_ERROR) |
| ERROR_CTOR(NotFound, NOT_FOUND) |
| ERROR_CTOR_NOSTACK(AlreadyExist, ALREADY_EXIST) |
| ERROR_CTOR_NOSTACK(DirectoryNotEmpty, DIRECTORY_NOT_EMPTY) |
| ERROR_CTOR(NotSupported, NOT_IMPLEMENTED_ERROR) |
| ERROR_CTOR_NOSTACK(EndOfFile, END_OF_FILE) |
| ERROR_CTOR(InternalError, INTERNAL_ERROR) |
| ERROR_CTOR(RuntimeError, RUNTIME_ERROR) |
| ERROR_CTOR(JniError, JNI_ERROR) |
| ERROR_CTOR_NOSTACK(Cancelled, CANCELLED) |
| ERROR_CTOR(MemoryLimitExceeded, MEM_LIMIT_EXCEEDED) |
| ERROR_CTOR(RpcError, THRIFT_RPC_ERROR) |
| ERROR_CTOR_NOSTACK(TimedOut, TIMEOUT) |
| ERROR_CTOR_NOSTACK(TooManyTasks, TOO_MANY_TASKS) |
| ERROR_CTOR(Uninitialized, UNINITIALIZED) |
| ERROR_CTOR(Aborted, ABORTED) |
| ERROR_CTOR_NOSTACK(DataQualityError, DATA_QUALITY_ERROR) |
| ERROR_CTOR_NOSTACK(NotAuthorized, NOT_AUTHORIZED) |
| ERROR_CTOR(HttpError, HTTP_ERROR) |
| ERROR_CTOR_NOSTACK(NeedSendAgain, NEED_SEND_AGAIN) |
| ERROR_CTOR_NOSTACK(CgroupError, CGROUP_ERROR) |
| ERROR_CTOR_NOSTACK(ObtainLockFailed, OBTAIN_LOCK_FAILED) |
| ERROR_CTOR_NOSTACK(NetworkError, NETWORK_ERROR) |
| #undef ERROR_CTOR |
| |
| template <int code> |
| bool is() const { |
| return code == _code; |
| } |
| |
| void set_code(int code) { _code = code; } |
| |
| bool ok() const { return _code == ErrorCode::OK || _code == ErrorCode::FINISHED; } |
| |
| // Convert into TStatus. |
| void to_thrift(TStatus* status) const; |
| TStatus to_thrift() const; |
| void to_protobuf(PStatus* status) const; |
| |
| std::string to_string() const; |
| std::string to_string_no_stack() const; |
| |
| /// @return A json representation of this status. |
| std::string to_json() const; |
| |
| int code() const { return _code; } |
| |
| /// Clone this status and add the specified prefix to the message. |
| /// |
| /// If this status is OK, then an OK status will be returned. |
| /// |
| /// @param [in] msg |
| /// The message to prepend. |
| /// @return A ref to Status object |
| Status& prepend(std::string_view msg); |
| |
| /// Add the specified suffix to the message. |
| /// |
| /// If this status is OK, then an OK status will be returned. |
| /// |
| /// @param [in] msg |
| /// The message to append. |
| /// @return A ref to Status object |
| Status& append(std::string_view msg); |
| |
| // if(!status) or if (status) will use this operator |
| operator bool() const { return this->ok(); } |
| |
| // Used like if ASSERT_EQ(res, Status::OK()) |
| // if the state is ok, then both code and precise code is not initialized properly, so that should check ok state |
| // ignore error messages during comparison |
| bool operator==(const Status& st) const { return _code == st._code; } |
| |
| // Used like if ASSERT_NE(res, Status::OK()) |
| bool operator!=(const Status& st) const { return _code != st._code; } |
| |
| friend std::ostream& operator<<(std::ostream& ostr, const Status& status); |
| |
| std::string_view msg() const { return _err_msg ? _err_msg->_msg : std::string_view(""); } |
| |
| std::pair<int, std::string> retrieve_error_msg() { return {_code, std::move(_err_msg->_msg)}; } |
| |
| friend io::ObjectStorageStatus convert_to_obj_response(Status st); |
| |
| private: |
| int _code; |
| struct ErrMsg { |
| std::string _msg; |
| std::string _stack; |
| }; |
| std::unique_ptr<ErrMsg> _err_msg; |
| |
| std::string code_as_string() const { |
| return (int)_code >= 0 ? doris::to_string(static_cast<TStatusCode::type>(_code)) |
| : fmt::format("E{}", (int16_t)_code); |
| } |
| }; |
| |
| // There are many thread using status to indicate the cancel state, one thread may update it and |
| // the other thread will read it. Status is not thread safe, for example, if one thread is update it |
| // and another thread is call to_string method, it may core, because the _err_msg is an unique ptr and |
| // it is deconstructed during copy method. |
| // And also we could not use lock, because we need get status frequently to check if it is cancelled. |
| // The default value is ok. |
| class AtomicStatus { |
| public: |
| AtomicStatus() : error_st_(Status::OK()) {} |
| |
| bool ok() const { return error_code_.load(std::memory_order_acquire) == 0; } |
| |
| bool update(const Status& new_status) { |
| // If new status is normal, or the old status is abnormal, then not need update |
| if (new_status.ok() || error_code_.load(std::memory_order_acquire) != 0) { |
| return false; |
| } |
| std::lock_guard l(mutex_); |
| if (error_code_.load(std::memory_order_acquire) != 0) { |
| return false; |
| } |
| error_st_ = new_status; |
| error_code_.store(static_cast<int16_t>(new_status.code()), std::memory_order_release); |
| return true; |
| } |
| |
| void reset() { |
| std::lock_guard l(mutex_); |
| error_st_ = Status::OK(); |
| error_code_ = 0; |
| } |
| |
| // will copy a new status object to avoid concurrency |
| // This stauts could only be called when ok==false |
| Status status() const { |
| std::lock_guard l(mutex_); |
| return error_st_; |
| } |
| |
| AtomicStatus(const AtomicStatus&) = delete; |
| void operator=(const AtomicStatus&) = delete; |
| |
| private: |
| std::atomic_int16_t error_code_ = 0; |
| Status error_st_; |
| // mutex's lock is not a const method, but we will use this mutex in |
| // some const method, so that it should be mutable. |
| mutable std::mutex mutex_; |
| }; |
| |
| inline std::ostream& operator<<(std::ostream& ostr, const Status& status) { |
| ostr << '[' << status.code_as_string() << ']'; |
| ostr << status.msg(); |
| if (status._err_msg && !status._err_msg->_stack.empty() && config::enable_stacktrace) { |
| ostr << '\n' << status._err_msg->_stack; |
| } |
| return ostr; |
| } |
| |
| inline std::string Status::to_string() const { |
| std::stringstream ss; |
| ss << *this; |
| return ss.str(); |
| } |
| |
| inline std::string Status::to_string_no_stack() const { |
| return fmt::format("[{}]{}", code_as_string(), msg()); |
| } |
| |
| // some generally useful macros |
| #define RETURN_IF_ERROR(stmt) \ |
| do { \ |
| Status _status_ = (stmt); \ |
| if (UNLIKELY(!_status_.ok())) { \ |
| return _status_; \ |
| } \ |
| } while (false) |
| |
| #define PROPAGATE_FALSE(stmt) \ |
| do { \ |
| if (UNLIKELY(!static_cast<bool>(stmt))) { \ |
| return false; \ |
| } \ |
| } while (false) |
| |
| #define THROW_IF_ERROR(stmt) \ |
| do { \ |
| Status _status_ = (stmt); \ |
| if (UNLIKELY(!_status_.ok())) { \ |
| throw Exception(_status_); \ |
| } \ |
| } while (false) |
| |
| #define RETURN_IF_STATUS_ERROR(status, stmt) \ |
| do { \ |
| status = (stmt); \ |
| if (UNLIKELY(!status.ok())) { \ |
| return; \ |
| } \ |
| } while (false) |
| |
| #define EXIT_IF_ERROR(stmt) \ |
| do { \ |
| Status _status_ = (stmt); \ |
| if (UNLIKELY(!_status_.ok())) { \ |
| LOG(ERROR) << _status_; \ |
| exit(1); \ |
| } \ |
| } while (false) |
| |
| #define RETURN_FALSE_IF_ERROR(stmt) \ |
| do { \ |
| Status status = (stmt); \ |
| if (UNLIKELY(!status.ok())) { \ |
| return false; \ |
| } \ |
| } while (false) |
| |
| /// @brief Emit a warning if @c to_call returns a bad status. |
| #define WARN_IF_ERROR(to_call, warning_prefix) \ |
| do { \ |
| Status _s = (to_call); \ |
| if (UNLIKELY(!_s.ok())) { \ |
| LOG(WARNING) << (warning_prefix) << ": " << _s; \ |
| } \ |
| } while (false); |
| |
| #define RETURN_NOT_OK_STATUS_WITH_WARN(stmt, warning_prefix) \ |
| do { \ |
| Status _s = (stmt); \ |
| if (UNLIKELY(!_s.ok())) { \ |
| LOG(WARNING) << (warning_prefix) << ", error: " << _s; \ |
| return _s; \ |
| } \ |
| } while (false); |
| |
| template <typename T> |
| using Result = expected<T, Status>; |
| |
| using ResultError = unexpected<Status>; |
| |
| #define RETURN_IF_ERROR_RESULT(stmt) \ |
| do { \ |
| Status _status_ = (stmt); \ |
| if (UNLIKELY(!_status_.ok())) { \ |
| return unexpected(std::move(_status_)); \ |
| } \ |
| } while (false) |
| |
| #define DORIS_TRY(stmt) \ |
| ({ \ |
| auto&& try_res = (stmt); \ |
| using T = std::decay_t<decltype(try_res)>; \ |
| if (!try_res.has_value()) [[unlikely]] { \ |
| return std::forward<T>(try_res).error(); \ |
| } \ |
| std::forward<T>(try_res).value(); \ |
| }); |
| |
| #define TEST_TRY(stmt) \ |
| ({ \ |
| auto&& res = (stmt); \ |
| using T = std::decay_t<decltype(res)>; \ |
| if (!res.has_value()) [[unlikely]] { \ |
| ASSERT_TRUE(res.has_value()) << "Expected success, but got error: " << res.error(); \ |
| } \ |
| std::forward<T>(res).value(); \ |
| }) |
| |
| } // namespace doris |
| |
| // specify formatter for Status |
| template <> |
| struct fmt::formatter<doris::Status> { |
| template <typename ParseContext> |
| constexpr auto parse(ParseContext& ctx) { |
| return ctx.begin(); |
| } |
| |
| template <typename FormatContext> |
| auto format(doris::Status const& status, FormatContext& ctx) { |
| return fmt::format_to(ctx.out(), "{}", status.to_string()); |
| } |
| }; |