ClickHouse/dbms/Common/Exception.cpp

374 lines
10 KiB
C++
Raw Normal View History

2019-03-27 15:42:24 +00:00
#include "Exception.h"
2012-05-14 20:37:10 +00:00
#include <string.h>
2014-07-21 09:11:20 +00:00
#include <cxxabi.h>
2017-02-07 16:36:12 +00:00
#include <Poco/String.h>
2015-09-29 19:19:54 +00:00
#include <common/logger_useful.h>
#include <IO/WriteHelpers.h>
#include <IO/Operators.h>
#include <IO/ReadBufferFromString.h>
#include <common/demangle.h>
2019-03-27 15:42:24 +00:00
#include <Common/config_version.h>
2019-08-05 19:41:20 +00:00
#include <Common/formatReadable.h>
2019-11-27 09:39:44 +00:00
#include <Common/filesystemHelpers.h>
2019-08-05 19:41:20 +00:00
#include <filesystem>
2010-03-01 16:59:51 +00:00
namespace DB
{
2011-12-12 06:15:34 +00:00
namespace ErrorCodes
{
extern const int POCO_EXCEPTION;
extern const int STD_EXCEPTION;
extern const int UNKNOWN_EXCEPTION;
extern const int LOGICAL_ERROR;
}
Exception::Exception(const std::string & msg, int code)
: Poco::Exception(msg, code)
{
// In debug builds, treat LOGICAL_ERROR as an assertion failure.
// Log the message before we fail.
#ifndef NDEBUG
if (code == ErrorCodes::LOGICAL_ERROR)
{
LOG_ERROR(&Poco::Logger::root(), "Logical error: '" + msg + "'.");
assert(false);
}
#endif
}
Exception::Exception(CreateFromPocoTag, const Poco::Exception & exc)
: Poco::Exception(exc.displayText(), ErrorCodes::POCO_EXCEPTION)
{
2020-01-02 10:29:59 +00:00
#ifdef STD_EXCEPTION_HAS_STACK_TRACE
set_stack_trace(exc.get_stack_trace_frames(), exc.get_stack_trace_size());
2020-01-02 10:29:59 +00:00
#endif
}
Exception::Exception(CreateFromSTDTag, const std::exception & exc)
: Poco::Exception(String(typeid(exc).name()) + ": " + String(exc.what()), ErrorCodes::STD_EXCEPTION)
{
2020-01-02 10:29:59 +00:00
#ifdef STD_EXCEPTION_HAS_STACK_TRACE
set_stack_trace(exc.get_stack_trace_frames(), exc.get_stack_trace_size());
2020-01-02 10:29:59 +00:00
#endif
}
std::string getExceptionStackTraceString(const std::exception & e)
{
#ifdef STD_EXCEPTION_HAS_STACK_TRACE
return StackTrace::toString(e.get_stack_trace_frames(), 0, e.get_stack_trace_size());
#else
2020-01-02 18:55:45 +00:00
if (const auto * db_exception = dynamic_cast<const Exception *>(&e))
2020-01-02 16:32:17 +00:00
return db_exception->getStackTraceString();
return {};
#endif
}
std::string Exception::getStackTraceString() const
{
#ifdef STD_EXCEPTION_HAS_STACK_TRACE
return StackTrace::toString(get_stack_trace_frames(), 0, get_stack_trace_size());
#else
return trace.toString();
#endif
}
2020-03-08 21:04:10 +00:00
std::string errnoToString(int code, int the_errno)
2012-05-14 20:37:10 +00:00
{
const size_t buf_size = 128;
char buf[buf_size];
#ifndef _GNU_SOURCE
2020-03-08 21:04:10 +00:00
int rc = strerror_r(the_errno, buf, buf_size);
#ifdef __APPLE__
if (rc != 0 && rc != EINVAL)
#else
if (rc != 0)
#endif
{
std::string tmp = std::to_string(code);
const char * code_str = tmp.c_str();
const char * unknown_message = "Unknown error ";
strcpy(buf, unknown_message);
strcpy(buf + strlen(unknown_message), code_str);
}
2020-03-08 21:04:10 +00:00
return "errno: " + toString(the_errno) + ", strerror: " + std::string(buf);
#else
(void)code;
2020-03-08 21:04:10 +00:00
return "errno: " + toString(the_errno) + ", strerror: " + std::string(strerror_r(the_errno, buf, sizeof(buf)));
#endif
2012-05-14 20:37:10 +00:00
}
2020-03-08 21:04:10 +00:00
void throwFromErrno(const std::string & s, int code, int the_errno)
{
2020-03-08 21:04:10 +00:00
throw ErrnoException(s + ", " + errnoToString(code, the_errno), code, the_errno);
}
2019-08-07 12:52:47 +00:00
void throwFromErrnoWithPath(const std::string & s, const std::string & path, int code, int the_errno)
2019-08-06 18:54:06 +00:00
{
throw ErrnoException(s + ", " + errnoToString(code, the_errno), code, the_errno, path);
}
void tryLogCurrentException(const char * log_name, const std::string & start_of_message)
{
tryLogCurrentException(&Logger::get(log_name), start_of_message);
}
void tryLogCurrentException(Poco::Logger * logger, const std::string & start_of_message)
2013-11-18 19:18:03 +00:00
{
try
{
LOG_ERROR(logger, start_of_message << (start_of_message.empty() ? "" : ": ") << getCurrentExceptionMessage(true));
}
catch (...)
{
}
}
2019-12-15 06:34:43 +00:00
static void getNoSpaceLeftInfoMessage(std::filesystem::path path, std::string & msg)
2019-08-05 19:41:20 +00:00
{
2019-08-06 18:54:06 +00:00
path = std::filesystem::absolute(path);
2019-08-05 19:41:20 +00:00
/// It's possible to get ENOSPC for non existent file (e.g. if there are no free inodes and creat() fails)
/// So try to get info for existent parent directory.
while (!std::filesystem::exists(path) && path.has_relative_path())
path = path.parent_path();
2019-11-27 09:39:44 +00:00
auto fs = getStatVFS(path);
2019-08-05 19:41:20 +00:00
msg += "\nTotal space: " + formatReadableSizeWithBinarySuffix(fs.f_blocks * fs.f_bsize)
+ "\nAvailable space: " + formatReadableSizeWithBinarySuffix(fs.f_bavail * fs.f_bsize)
+ "\nTotal inodes: " + formatReadableQuantity(fs.f_files)
+ "\nAvailable inodes: " + formatReadableQuantity(fs.f_favail);
2019-11-27 09:39:44 +00:00
auto mount_point = getMountPoint(path).string();
2019-08-05 19:41:20 +00:00
msg += "\nMount point: " + mount_point;
2019-08-07 12:52:47 +00:00
#if defined(__linux__)
2019-11-27 09:39:44 +00:00
msg += "\nFilesystem: " + getFilesystemName(mount_point);
2019-08-07 12:52:47 +00:00
#endif
2019-08-05 19:41:20 +00:00
}
2019-12-15 06:34:43 +00:00
static std::string getExtraExceptionInfo(const std::exception & e)
2019-08-05 19:41:20 +00:00
{
String msg;
try
{
if (auto file_exception = dynamic_cast<const Poco::FileException *>(&e))
{
if (file_exception->code() == ENOSPC)
2019-08-06 12:51:10 +00:00
getNoSpaceLeftInfoMessage(file_exception->message(), msg);
2019-08-05 19:41:20 +00:00
}
else if (auto errno_exception = dynamic_cast<const DB::ErrnoException *>(&e))
{
2019-08-06 18:54:06 +00:00
if (errno_exception->getErrno() == ENOSPC && errno_exception->getPath())
getNoSpaceLeftInfoMessage(errno_exception->getPath().value(), msg);
2019-08-05 19:41:20 +00:00
}
}
2019-08-06 20:39:07 +00:00
catch (...)
{
2019-08-06 14:46:17 +00:00
msg += "\nCannot print extra info: " + getCurrentExceptionMessage(false, false, false);
2019-08-05 19:41:20 +00:00
}
return msg;
}
2019-08-06 12:51:10 +00:00
std::string getCurrentExceptionMessage(bool with_stacktrace, bool check_embedded_stacktrace /*= false*/, bool with_extra_info /*= true*/)
{
std::stringstream stream;
try
{
throw;
}
catch (const Exception & e)
{
2019-08-05 19:41:20 +00:00
stream << getExceptionMessage(e, with_stacktrace, check_embedded_stacktrace)
2019-08-06 12:51:10 +00:00
<< (with_extra_info ? getExtraExceptionInfo(e) : "")
2019-08-05 19:41:20 +00:00
<< " (version " << VERSION_STRING << VERSION_OFFICIAL << ")";
}
catch (const Poco::Exception & e)
{
try
{
2019-04-04 12:34:49 +00:00
stream << "Poco::Exception. Code: " << ErrorCodes::POCO_EXCEPTION << ", e.code() = " << e.code()
<< ", e.displayText() = " << e.displayText()
<< (with_stacktrace ? ", Stack trace (when copying this message, always include the lines below):\n\n" + getExceptionStackTraceString(e) : "")
2019-08-06 12:51:10 +00:00
<< (with_extra_info ? getExtraExceptionInfo(e) : "")
2020-01-24 02:38:03 +00:00
<< " (version " << VERSION_STRING << VERSION_OFFICIAL << ")";
}
catch (...) {}
}
catch (const std::exception & e)
{
try
{
int status = 0;
auto name = demangle(typeid(e).name(), status);
if (status)
name += " (demangling status: " + toString(status) + ")";
2019-08-05 19:41:20 +00:00
stream << "std::exception. Code: " << ErrorCodes::STD_EXCEPTION << ", type: " << name << ", e.what() = " << e.what()
<< (with_stacktrace ? ", Stack trace (when copying this message, always include the lines below):\n\n" + getExceptionStackTraceString(e) : "")
<< (with_extra_info ? getExtraExceptionInfo(e) : "")
<< " (version " << VERSION_STRING << VERSION_OFFICIAL << ")";
}
catch (...) {}
}
catch (...)
{
try
{
int status = 0;
auto name = demangle(abi::__cxa_current_exception_type()->name(), status);
if (status)
name += " (demangling status: " + toString(status) + ")";
2019-04-04 12:34:49 +00:00
stream << "Unknown exception. Code: " << ErrorCodes::UNKNOWN_EXCEPTION << ", type: " << name << " (version " << VERSION_STRING << VERSION_OFFICIAL << ")";
}
catch (...) {}
}
return stream.str();
2013-11-18 19:18:03 +00:00
}
int getCurrentExceptionCode()
{
try
{
throw;
}
catch (const Exception & e)
{
return e.code();
}
catch (const Poco::Exception &)
{
return ErrorCodes::POCO_EXCEPTION;
}
catch (const std::exception &)
{
return ErrorCodes::STD_EXCEPTION;
}
catch (...)
{
return ErrorCodes::UNKNOWN_EXCEPTION;
}
}
2016-06-08 14:39:30 +00:00
void rethrowFirstException(const Exceptions & exceptions)
{
2020-03-08 21:04:10 +00:00
for (auto & exception : exceptions)
if (exception)
std::rethrow_exception(exception);
2015-10-05 05:40:27 +00:00
}
void tryLogException(std::exception_ptr e, const char * log_name, const std::string & start_of_message)
{
try
{
2020-03-18 03:27:32 +00:00
std::rethrow_exception(std::move(e)); // NOLINT
}
catch (...)
{
tryLogCurrentException(log_name, start_of_message);
}
2015-10-05 05:40:27 +00:00
}
void tryLogException(std::exception_ptr e, Poco::Logger * logger, const std::string & start_of_message)
{
try
{
2020-03-18 03:27:32 +00:00
std::rethrow_exception(std::move(e)); // NOLINT
}
catch (...)
{
tryLogCurrentException(logger, start_of_message);
}
2015-10-05 05:40:27 +00:00
}
std::string getExceptionMessage(const Exception & e, bool with_stacktrace, bool check_embedded_stacktrace)
{
std::stringstream stream;
try
{
std::string text = e.displayText();
bool has_embedded_stack_trace = false;
if (check_embedded_stacktrace)
{
auto embedded_stack_trace_pos = text.find("Stack trace");
has_embedded_stack_trace = embedded_stack_trace_pos != std::string::npos;
if (!with_stacktrace && has_embedded_stack_trace)
{
text.resize(embedded_stack_trace_pos);
Poco::trimRightInPlace(text);
}
}
stream << "Code: " << e.code() << ", e.displayText() = " << text;
if (with_stacktrace && !has_embedded_stack_trace)
stream << ", Stack trace (when copying this message, always include the lines below):\n\n" << e.getStackTraceString();
}
catch (...) {}
return stream.str();
}
2015-10-05 05:40:27 +00:00
std::string getExceptionMessage(std::exception_ptr e, bool with_stacktrace)
{
try
{
2020-03-18 03:27:32 +00:00
std::rethrow_exception(std::move(e)); // NOLINT
}
catch (...)
{
return getCurrentExceptionMessage(with_stacktrace);
}
}
std::string ExecutionStatus::serializeText() const
{
2017-07-31 21:39:24 +00:00
WriteBufferFromOwnString wb;
wb << code << "\n" << escape << message;
return wb.str();
}
void ExecutionStatus::deserializeText(const std::string & data)
{
ReadBufferFromString rb(data);
2017-05-31 14:01:08 +00:00
rb >> code >> "\n" >> escape >> message;
}
2017-07-27 13:11:16 +00:00
bool ExecutionStatus::tryDeserializeText(const std::string & data)
{
try
{
deserializeText(data);
}
catch (...)
{
return false;
}
return true;
}
ExecutionStatus ExecutionStatus::fromCurrentException(const std::string & start_of_message)
{
String msg = (start_of_message.empty() ? "" : (start_of_message + ": ")) + getCurrentExceptionMessage(false, true);
return ExecutionStatus(getCurrentExceptionCode(), msg);
}
2010-03-01 16:59:51 +00:00
}