diff --git a/include/wsrep/assert.hpp b/include/wsrep/assert.hpp new file mode 100644 index 00000000..04ebbf9b --- /dev/null +++ b/include/wsrep/assert.hpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2023 Codership Oy + * + * This file is part of wsrep-lib. + * + * Wsrep-lib is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Wsrep-lib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wsrep-lib. If not, see . + */ + +#ifndef WSREP_ASSERT_HPP +#define WSREP_ASSERT_HPP + +/** @file assert.hpp + * + * Wsrep library informative assert. + */ + +#include + +/** + * Function to do informative assert with actual file name, + * line and formatted info text. + * + * @param expr Assertion expression string + * @param file File name string + * @param line File line number + * @param info Formatted info text + * +*/ +void wsrep_info_assert(const char* expr, const char* file, const int line, const char* info); + +/** + * Function to create informative text from format + * and variable number of parameters + * + * @param format strict + * @param ... variable number of parameters + * + * @retval Formated informative text + * +*/ +char* wsrep_info_assert_text(const char* format, ...); + +/** + * Macro for informative assert. First actual expression + * is printed and then informative text provided by + * developer. + * + * @param exp assertion expression + * @param p Informative text format and parameters + * + * usage : WSREP_INFO_ASSERT((EXPR), (format, format_param,...)) + * example : WSREP_INFO_ASSERT(0, ("This is always false=%d", 0)); + * +*/ +#ifdef NDEBUG +#define WSREP_INFO_ASSERT(exp, p) (__ASSERT_VOID_CAST (0)) +#else +#define WSREP_INFO_ASSERT(exp, p) do { \ + if (__builtin_expect((!(exp)), false)) \ + { \ + wsrep_info_assert(#exp, __FILE__, __LINE__, \ + wsrep_info_assert_text p); \ + assert(exp); \ + } \ +} while (0) +#endif // NDEBUG + +#endif // WSREP_ASSERT_HPP diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 85524cea..ca3e1ea6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,6 +4,7 @@ add_library(wsrep-lib allowlist_service_v1.cpp + assert.cpp client_state.cpp config_service_v1.cpp event_service_v1.cpp diff --git a/src/assert.cpp b/src/assert.cpp new file mode 100644 index 00000000..b53f95dc --- /dev/null +++ b/src/assert.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023 Codership Oy + * + * This file is part of wsrep-lib. + * + * Wsrep-lib is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Wsrep-lib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wsrep-lib. If not, see . + */ + +/** @file assert.cpp + * + * Wsrep library informative assert. + */ + +#include +#include +#include +#include +#include "wsrep/logger.hpp" + +/** + * Function to create informative text from format + * and variable number of parameters + * + * @param format text format strict + * @param ... variable number of parameters + * + * @retval Formated informative text + * +*/ +#define WSREP_MAX_INFO_BUF 1024 + +char* wsrep_info_assert_text(const char* format, ...) +{ + static char wsrep_buf[WSREP_MAX_INFO_BUF]; + va_list ap; + + va_start(ap, format); + int n= vsnprintf(wsrep_buf, WSREP_MAX_INFO_BUF,(char *)format, ap); + if (n >= WSREP_MAX_INFO_BUF) + { + wsrep::log_debug() << "wsrep_info_assert_text too long and truncated" + << " used length: " << WSREP_MAX_INFO_BUF + << " needed lenght: " << n; + } + va_end(ap); + return wsrep_buf; +} + +/** + * Function to do informative assert with actual file name, + * line and formatted info text. Function will not return. + * + * @param file File name string + * @param line File line number + * @param info Formatted info text + * +*/ +void wsrep_info_assert(const char* expr, const char* file, const int line, const char* info) +{ + wsrep::log_error() << "Assertion: '" << expr << "' failed in: " << file << ":" << line + << " Info: " << info; +} diff --git a/src/transaction.cpp b/src/transaction.cpp index 098e7860..22fe33da 100644 --- a/src/transaction.cpp +++ b/src/transaction.cpp @@ -27,6 +27,7 @@ #include "wsrep/compiler.hpp" #include "wsrep/server_service.hpp" #include "wsrep/client_service.hpp" +#include "wsrep/assert.hpp" #include #include @@ -346,10 +347,14 @@ int wsrep::transaction::before_prepare( ret = certify_commit(lock); } - assert((ret == 0 && state() == s_preparing) || + WSREP_INFO_ASSERT(((ret == 0 && state() == s_preparing) || (state() == s_must_abort || state() == s_must_replay || - state() == s_cert_failed)); + state() == s_cert_failed)), + ("::before_prepare : ret=%d error=%s state=%s\n", + ret, + to_c_string(client_state_.current_error()), + to_c_string(state()))); if (ret) { @@ -379,12 +384,17 @@ int wsrep::transaction::before_prepare( break; } - assert(state() == s_preparing || + WSREP_INFO_ASSERT((state() == s_preparing || (is_xa() && state() == s_replaying) || (ret && (state() == s_must_abort || state() == s_must_replay || state() == s_cert_failed || - state() == s_aborted))); + state() == s_aborted))), + ("::before_prepare_leave : ret=%d error=%s state=%s\n", + ret, + to_c_string(client_state_.current_error()), + to_c_string(state()))); + debug_log_state("before_prepare_leave"); return ret; }