This patch introduces throwing_assert(cond), a better and safer replacement for assert(cond) or SCYLLA_ASSERT(cond). It aims to eventually replace all assertions in Scylla and provide a real solution to issue #7871 ("exorcise assertions from Scylla"). throwing_assert() is based on the existing on_internal_error() and inherits all its benefits, but brings with it the *convenience* of assert() and SCYLLA_ASSERT(): No need for a separate if(), new strings, etc. For example, you can do write just one line of throwing_assert(): throwing_assert(p != nullptr); Instead of much more verbose on_internal_error: if (p == nullptr) { utils::on_internal_error("assertion failed: p != nullptr") } Like assert() and SCYLLA_ASSERT(), in our tests throwing_assert() dumps core on failure. But its advantage over the other assertion functions like becomes clear in production: * assert() is compiled-out in release builds. This means that the condition is not checked, and the code after the failed condition continues to run normally, potentially to disasterous consequences. In contrast, throwing_assert() continues to check the condition even in release builds, and if the condition is false it throws an exception. This ensures that the code following the condition doesn't run. * SCYLLA_ASSERT() in release builds checks the condition and *crashes* Scylla if the condition is not met. In contrast, throwing_assert() doesn't crash, but throws an exception. This means that the specific operation that encountered the error is aborted, instead of the entire server. It often also means that the user of this operation will see this error somehow and know which operation failed - instead of encountering a mysterious server (or even whole-cluster crash) without any indication which operation caused it. Another benefit of throwing_assert() is that it logs the error message (and also a backtrace!) to Scylla's usual logging mechanisms - not to stderr like assert and SCYLLA_ASSERT write, where users sometimes can't see what is written. Fixes #28308. Signed-off-by: Nadav Har'El <nyh@scylladb.com>
33 lines
899 B
C++
33 lines
899 B
C++
/*
|
|
* Copyright (C) 2024-present ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0
|
|
*/
|
|
|
|
#include <seastar/core/on_internal_error.hh>
|
|
#include <seastar/util/log.hh>
|
|
#include <seastar/core/format.hh>
|
|
|
|
#include "on_internal_error.hh"
|
|
|
|
static seastar::logger on_internal_error_logger("on_internal_error");
|
|
|
|
namespace utils {
|
|
|
|
[[noreturn]] void on_internal_error(std::string_view reason) {
|
|
seastar::on_internal_error(on_internal_error_logger, reason);
|
|
}
|
|
|
|
[[noreturn]] void on_fatal_internal_error(std::string_view reason) noexcept {
|
|
seastar::on_fatal_internal_error(on_internal_error_logger, reason);
|
|
}
|
|
|
|
[[noreturn]] void __assert_fail_on_internal_error(const char* expr, const char* file, int line, const char* function) {
|
|
on_internal_error(fmt::format("Assertion '{}' failed at {}:{} in {}",
|
|
expr, file, line, function));
|
|
}
|
|
|
|
} // namespace utils
|