Files
doris/be/src/common/exception.h
2024-01-25 13:24:09 +08:00

125 lines
6.0 KiB
C++

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
#pragma once
#include <fmt/format.h>
#include <gen_cpp/Status_types.h>
#include <stdint.h>
#include <exception>
#include <memory>
#include <ostream>
#include <string>
#include <string_view>
#include <utility>
#include "common/status.h"
#include "util/defer_op.h"
namespace doris {
inline thread_local int enable_thread_catch_bad_alloc = 0;
class Exception : public std::exception {
public:
Exception() : _code(ErrorCode::OK) {}
Exception(int code, const std::string_view& msg);
Exception(const Status& status) : Exception(status.code(), status.msg()) {}
// add nested exception as first param, or the template may could not find
// the correct method for ...args
Exception(const Exception& nested, int code, const std::string_view& msg);
// Format message with fmt::format, like the logging functions.
template <typename... Args>
Exception(int code, const std::string_view& fmt, Args&&... args)
: Exception(code, fmt::format(fmt, std::forward<Args>(args)...)) {}
int code() const { return _code; }
const std::string& to_string() const;
const char* what() const noexcept override { return to_string().c_str(); }
Status to_status() const { return Status(code(), _err_msg->_msg, _err_msg->_stack); }
private:
int _code;
struct ErrMsg {
std::string _msg;
std::string _stack;
};
std::unique_ptr<ErrMsg> _err_msg;
std::unique_ptr<Exception> _nested_excption;
mutable std::string _cache_string;
};
inline const std::string& Exception::to_string() const {
if (!_cache_string.empty()) {
return _cache_string;
}
std::stringstream ostr;
ostr << "[E" << _code << "] ";
ostr << (_err_msg ? _err_msg->_msg : "");
if (_err_msg && !_err_msg->_stack.empty()) {
ostr << '\n' << _err_msg->_stack;
}
if (_nested_excption != nullptr) {
ostr << '\n' << "Caused by:" << _nested_excption->to_string();
}
_cache_string = ostr.str();
return _cache_string;
}
} // namespace doris
#define RETURN_IF_CATCH_EXCEPTION(stmt) \
do { \
try { \
doris::enable_thread_catch_bad_alloc++; \
Defer defer {[&]() { doris::enable_thread_catch_bad_alloc--; }}; \
{ stmt; } \
} catch (const doris::Exception& e) { \
if (e.code() == doris::ErrorCode::MEM_ALLOC_FAILED) { \
return Status::MemoryLimitExceeded(fmt::format( \
"PreCatch error code:{}, {}, __FILE__:{}, __LINE__:{}, __FUNCTION__:{}", \
e.code(), e.to_string(), __FILE__, __LINE__, __PRETTY_FUNCTION__)); \
} \
return Status::Error<false>(e.code(), e.to_string()); \
} \
} while (0)
#define RETURN_IF_ERROR_OR_CATCH_EXCEPTION(stmt) \
do { \
try { \
doris::enable_thread_catch_bad_alloc++; \
Defer defer {[&]() { doris::enable_thread_catch_bad_alloc--; }}; \
{ \
Status _status_ = (stmt); \
if (UNLIKELY(!_status_.ok())) { \
return _status_; \
} \
} \
} catch (const doris::Exception& e) { \
if (e.code() == doris::ErrorCode::MEM_ALLOC_FAILED) { \
return Status::MemoryLimitExceeded(fmt::format( \
"PreCatch error code:{}, {}, __FILE__:{}, __LINE__:{}, __FUNCTION__:{}", \
e.code(), e.to_string(), __FILE__, __LINE__, __PRETTY_FUNCTION__)); \
} \
return Status::Error<false>(e.code(), e.to_string()); \
} \
} while (0)