From b9977ce0aee6d9be31136d2aee557dfc8cd4ed39 Mon Sep 17 00:00:00 2001 From: Kamil Holubicki Date: Thu, 12 Sep 2024 12:59:51 +0200 Subject: [PATCH] PXC-4433: Create file with current MySQL state https://perconadev.atlassian.net/browse/PXC-4433 server.state file containing current server state is being created in data directory if the server is started with create_server_state_file=ON option. create_server_state_file default value is OFF. --- mysys/my_init.cc | 2 ++ sql/CMakeLists.txt | 1 + sql/dd/impl/bootstrap/bootstrapper.cc | 2 ++ sql/dd/impl/upgrade/server.cc | 5 +++++ sql/dd/upgrade_57/upgrade.cc | 2 ++ sql/mysqld.cc | 14 +++++++++++++- sql/mysqld.h | 1 + sql/signal_handler.cc | 12 ++++++++++++ sql/sys_vars.cc | 8 ++++++++ storage/innobase/ut/ut0dbg.cc | 2 ++ 10 files changed, 48 insertions(+), 1 deletion(-) diff --git a/mysys/my_init.cc b/mysys/my_init.cc index 2661a96d89a6..5dbefc00ae9a 100644 --- a/mysys/my_init.cc +++ b/mysys/my_init.cc @@ -71,6 +71,8 @@ #include "mysys/mysys_priv.h" #include "mysys_err.h" +#include "sql/server_status_file.h" + #ifdef HAVE_SYS_RESOURCE_H #include #endif diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 3a1e65a5d570..63a12a2e6c7c 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -480,6 +480,7 @@ SET(SQL_SHARED_SOURCES partition_info.cc partitioning/partition_handler.cc persisted_variable.cc + server_status_file.cc protocol_classic.cc psi_memory_key.cc psi_memory_resource.cc diff --git a/sql/dd/impl/bootstrap/bootstrapper.cc b/sql/dd/impl/bootstrap/bootstrapper.cc index 5c39c4b5098e..c0b8cbfc1575 100644 --- a/sql/dd/impl/bootstrap/bootstrapper.cc +++ b/sql/dd/impl/bootstrap/bootstrapper.cc @@ -73,6 +73,7 @@ #include "sql/sd_notify.h" // sysd::notify #include "sql/sql_zip_dict.h" #include "sql/thd_raii.h" +#include "sql/server_status_file.h" #include "storage/perfschema/pfs_dd_version.h" // PFS_DD_VERSION using namespace dd; @@ -1408,6 +1409,7 @@ bool initialize_dd_properties(THD *thd) { if (bootstrap::DD_bootstrap_ctx::instance().is_dd_upgrade()) { LogErr(SYSTEM_LEVEL, ER_DD_UPGRADE, actual_dd_version, dd::DD_VERSION); sysd::notify("STATUS=Data Dictionary upgrade in progress\n"); + Server_status_file::set_status(Server_status_file::Status::UPGRADING); } if (bootstrap::DD_bootstrap_ctx::instance().is_server_upgrade()) { // This condition is hit only if upgrade has been skipped before diff --git a/sql/dd/impl/upgrade/server.cc b/sql/dd/impl/upgrade/server.cc index 4d96b16bc3a3..0924e21acad9 100644 --- a/sql/dd/impl/upgrade/server.cc +++ b/sql/dd/impl/upgrade/server.cc @@ -64,6 +64,7 @@ #include "sql/thd_raii.h" #include "sql/trigger.h" // Trigger #include "sql/trigger_def.h" +#include "sql/server_status_file.h" typedef ulonglong sql_mode_t; extern const char *mysql_sys_schema[]; @@ -977,11 +978,15 @@ bool upgrade_system_schemas(THD *thd) { LogErr(SYSTEM_LEVEL, ER_SERVER_DOWNGRADE_STATUS, server_version, MYSQL_VERSION_ID, "started"); sysd::notify("STATUS=Server downgrade in progress\n"); + Server_status_file::set_status(Server_status_file::Status::DOWNGRADING); + /* purecov: end */ } else { LogErr(SYSTEM_LEVEL, ER_SERVER_UPGRADE_STATUS, server_version, MYSQL_VERSION_ID, "started"); sysd::notify("STATUS=Server upgrade in progress\n"); + Server_status_file::set_status(Server_status_file::Status::UPGRADING); + } bootstrap_error_handler.set_log_error(false); diff --git a/sql/dd/upgrade_57/upgrade.cc b/sql/dd/upgrade_57/upgrade.cc index f020e0cd2e1f..192ba1e4d584 100644 --- a/sql/dd/upgrade_57/upgrade.cc +++ b/sql/dd/upgrade_57/upgrade.cc @@ -86,6 +86,7 @@ #include "sql/table.h" #include "sql/thd_raii.h" #include "sql/transaction.h" // trans_rollback +#include "sql/server_status_file.h" namespace dd { @@ -904,6 +905,7 @@ bool do_pre_checks_and_initialize_dd(THD *thd) { */ LogErr(SYSTEM_LEVEL, ER_DD_UPGRADE_START); sysd::notify("STATUS=Data Dictionary upgrade from MySQL 5.7 in progress\n"); + Server_status_file::set_status(Server_status_file::Status::UPGRADING); } /* diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5896fd00da89..ddc97dbc46f1 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -809,6 +809,7 @@ MySQL clients support the protocol: #include "sql/options_mysqld.h" // OPT_THREAD_CACHE_SIZE #include "sql/partitioning/partition_handler.h" // partitioning_init #include "sql/persisted_variable.h" // Persisted_variables_cache +#include "sql/server_status_file.h" #include "sql/plugin_table.h" #include "sql/protocol.h" #include "sql/psi_memory_key.h" // key_memory_MYSQL_RELAY_LOG_index @@ -1448,6 +1449,8 @@ bool avoid_temporal_upgrade; bool persisted_globals_load = true; +bool create_server_state_file = false; + bool opt_keyring_operations = true; bool opt_table_encryption_privilege_check = false; @@ -2773,6 +2776,7 @@ static void unireg_abort(int exit_code) { #endif /* WITH_WSREP */ DBUG_TRACE; + Server_status_file::set_status(Server_status_file::Status::STOPPING); if (errno) { sysd::notify("ERRNO=", errno, "\n"); } @@ -2899,6 +2903,8 @@ static void mysqld_exit(int exit_code) { close_service_status_pipe_in_mysqld(); #endif // _WIN32 + Server_status_file::set_status(Server_status_file::Status::STOPPED); + exit(exit_code); /* purecov: inspected */ } @@ -8424,6 +8430,9 @@ int mysqld_main(int argc, char **argv) strmake(mysql_real_data_home, get_relative_path(MYSQL_DATADIR), sizeof(mysql_real_data_home) - 1); + Server_status_file::init(&argc, &argv); + Server_status_file::set_status(Server_status_file::Status::INITIALIZING); + /* Must be initialized early for comparison of options name */ system_charset_info = &my_charset_utf8mb3_general_ci; @@ -9468,9 +9477,12 @@ int mysqld_main(int argc, char **argv) } mysqld_socket_acceptor->check_and_spawn_admin_connection_handler_thread(); - mysqld_socket_acceptor->connection_event_loop(); + Server_status_file::set_status(Server_status_file::Status::READY); + mysqld_socket_acceptor->connection_event_loop(); // KH: end of limbo state #endif /* _WIN32 */ server_operational_state = SERVER_SHUTTING_DOWN; + Server_status_file::set_status(Server_status_file::Status::STOPPING); + sysd::notify("STOPPING=1\nSTATUS=Server shutdown in progress\n"); DBUG_PRINT("info", ("No longer listening for incoming connections")); diff --git a/sql/mysqld.h b/sql/mysqld.h index f13044a6f00b..c754cc4c5257 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -441,6 +441,7 @@ extern ulonglong utility_user_privileges; extern char *utility_user_dynamic_privileges; extern bool persisted_globals_load; +extern bool create_server_state_file; extern bool opt_keyring_operations; extern bool opt_table_encryption_privilege_check; extern char *opt_keyring_migration_user; diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc index ceca808eef67..ad7669eae913 100644 --- a/sql/signal_handler.cc +++ b/sql/signal_handler.cc @@ -43,6 +43,7 @@ #include "sql/mysqld.h" #include "sql/sql_class.h" #include "sql/sql_const.h" +#include "sql/server_status_file.h" #ifdef WITH_WSREP #include "wsrep_mysqld.h" @@ -227,9 +228,11 @@ void print_fatal_signal(int sig) { extern "C" void handle_fatal_signal(int sig) { if (s_handler_being_processed) { my_safe_printf_stderr("Fatal " SIGNAL_FMT " while backtracing\n", sig); + Server_status_file::set_status(Server_status_file::Status::STOPPED); _exit(MYSQLD_FAILURE_EXIT); /* Quit without running destructors */ } + Server_status_file::set_status(Server_status_file::Status::STOPPING); s_handler_being_processed = true; #ifdef WITH_WSREP @@ -246,6 +249,10 @@ extern "C" void handle_fatal_signal(int sig) { buffered_error_log.write_to_disk(); + // This is the last chance to report in the file. + // Below coredump will exit the process + Server_status_file::set_status(Server_status_file::Status::STOPPED); + if ((test_flags & TEST_CORE_ON_SIGNAL) != 0) { #if HAVE_LIBCOREDUMPER if (opt_libcoredumper) { @@ -290,6 +297,9 @@ void my_server_abort() { static std::atomic_bool abort_processing{false}; /* Broadcast that this thread wants to print the signal info. */ aborts_pending++; + + Server_status_file::set_status(Server_status_file::Status::STOPPING); + /* Wait for the exclusive right to print the signal info. This assures the output is not interleaved. @@ -319,6 +329,8 @@ void my_server_abort() { while (abort_processing.exchange(true)) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } + + Server_status_file::set_status(Server_status_file::Status::STOPPED); abort(); } /* diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index feeb3afb0f23..0af9c1babba2 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -7868,6 +7868,14 @@ static Sys_var_bool Sys_persisted_globals_load( DEFAULT(true), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(nullptr), ON_UPDATE(nullptr)); +static Sys_var_bool Sys_create_server_state_file( + "create_server_state_file", + "When this option is enabled, server reports its state in server.state " + "file located in datadir.", + READ_ONLY NON_PERSIST GLOBAL_VAR(create_server_state_file), CMD_LINE(OPT_ARG), + DEFAULT(false), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(nullptr), + ON_UPDATE(nullptr)); + static bool sysvar_check_authid_string(sys_var *, THD *thd, set_var *var) { /* Since mandatory_roles is similar to a GRANT role statement without a diff --git a/storage/innobase/ut/ut0dbg.cc b/storage/innobase/ut/ut0dbg.cc index 421a260829e4..bfbec7775619 100644 --- a/storage/innobase/ut/ut0dbg.cc +++ b/storage/innobase/ut/ut0dbg.cc @@ -41,6 +41,7 @@ this program; if not, write to the Free Software Foundation, Inc., #endif /* !UNIV_HOTBACKUP */ #include "ut0dbg.h" +#include "sql/server_status_file.h" static std::function assert_callback; @@ -78,6 +79,7 @@ void ut_set_assert_callback(std::function &callback) { to_string(std::this_thread::get_id()).c_str()); #endif /* !UNIV_HOTBACKUP */ + Server_status_file::set_status(Server_status_file::Status::STOPPING); fputs( "InnoDB: We intentionally generate a memory trap.\n" "InnoDB: Submit a detailed bug report"