diff options
Diffstat (limited to 'sql/mysqld.cc')
-rw-r--r-- | sql/mysqld.cc | 229 |
1 files changed, 125 insertions, 104 deletions
diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 738fd73e..d0619aa2 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -302,7 +302,8 @@ static TYPELIB tc_heuristic_recover_typelib= }; const char *first_keyword= "first"; -const char *my_localhost= "localhost", *delayed_user= "DELAYED"; +const char *my_localhost= "localhost", + *delayed_user= "delayed", *slave_user= "<replication_slave>"; bool opt_large_files= sizeof(my_off_t) > 4; static my_bool opt_autocommit; ///< for --autocommit command-line option @@ -737,9 +738,6 @@ mysql_mutex_t LOCK_thread_id; server may be fairly high, we need a dedicated lock. */ mysql_mutex_t LOCK_prepared_stmt_count; -#ifdef HAVE_OPENSSL -mysql_mutex_t LOCK_des_key_file; -#endif mysql_mutex_t LOCK_backup_log; mysql_rwlock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; mysql_rwlock_t LOCK_ssl_refresh; @@ -883,7 +881,7 @@ static struct my_option pfs_early_options[]= PSI_file_key key_file_binlog, key_file_binlog_cache, key_file_binlog_index, key_file_binlog_index_cache, key_file_casetest, - key_file_dbopt, key_file_des_key_file, key_file_ERRMSG, key_select_to_file, + key_file_dbopt, key_file_ERRMSG, key_select_to_file, key_file_fileparser, key_file_frm, key_file_global_ddl_log, key_file_load, key_file_loadfile, key_file_log_event_data, key_file_log_event_info, key_file_log_ddl, @@ -895,16 +893,19 @@ PSI_file_key key_file_relaylog, key_file_relaylog_index, key_file_relaylog_cache, key_file_relaylog_index_cache; PSI_file_key key_file_binlog_state; +#ifdef HAVE_des +char *des_key_file; +PSI_file_key key_file_des_key_file; +PSI_mutex_key key_LOCK_des_key_file; +mysql_mutex_t LOCK_des_key_file; +#endif /* HAVE_des */ + #ifdef HAVE_PSI_INTERFACE #ifdef HAVE_MMAP PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, key_LOCK_pool, key_LOCK_pending_checkpoint; #endif /* HAVE_MMAP */ -#ifdef HAVE_OPENSSL -PSI_mutex_key key_LOCK_des_key_file; -#endif /* HAVE_OPENSSL */ - PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list, key_BINLOG_LOCK_binlog_background_thread, key_LOCK_binlog_end_pos, @@ -962,9 +963,9 @@ static PSI_mutex_info all_server_mutexes[]= { &key_LOCK_pool, "TC_LOG_MMAP::LOCK_pending_checkpoint", 0}, #endif /* HAVE_MMAP */ -#ifdef HAVE_OPENSSL +#ifdef HAVE_des { &key_LOCK_des_key_file, "LOCK_des_key_file", PSI_FLAG_GLOBAL}, -#endif /* HAVE_OPENSSL */ +#endif /* HAVE_des */ { &key_BINLOG_LOCK_index, "MYSQL_BIN_LOG::LOCK_index", 0}, { &key_BINLOG_LOCK_xid_list, "MYSQL_BIN_LOG::LOCK_xid_list", 0}, @@ -1491,7 +1492,6 @@ static void openssl_dynlock_destroy(openssl_lock_t *, const char *, int); static void openssl_lock_function(int, int, const char *, int); static void openssl_lock(int, openssl_lock_t *, const char *, int); #endif /* HAVE_OPENSSL10 */ -char *des_key_file; #ifndef EMBEDDED_LIBRARY struct st_VioSSLFd *ssl_acceptor_fd; #endif @@ -1567,15 +1567,12 @@ static void kill_thread(THD *thd) /** First shutdown everything but slave threads and binlog dump connections */ -static my_bool kill_thread_phase_1(THD *thd, int *n_threads_awaiting_ack) +static my_bool kill_thread_phase_1(THD *thd, void *) { DBUG_PRINT("quit", ("Informing thread %ld that it's time to die", (ulong) thd->thread_id)); - if (thd->slave_thread || thd->is_binlog_dump_thread() || - (shutdown_wait_for_slaves && - repl_semisync_master.is_thd_awaiting_semisync_ack(thd) && - ++(*n_threads_awaiting_ack))) + if (thd->slave_thread || thd->is_binlog_dump_thread()) return 0; if (DBUG_IF("only_kill_system_threads") && !thd->system_thread) @@ -1773,31 +1770,20 @@ static void close_connections(void) This will give the threads some time to gracefully abort their statements and inform their clients that the server is about to die. */ - DBUG_EXECUTE_IF("mysqld_delay_kill_threads_phase_1", my_sleep(200000);); - int n_threads_awaiting_ack= 0; - server_threads.iterate(kill_thread_phase_1, &n_threads_awaiting_ack); + server_threads.iterate(kill_thread_phase_1); /* If we are waiting on any ACKs, delay killing the thread until either an ACK is received or the timeout is hit. - - Allow at max the number of sessions to await a timeout; however, if all - ACKs have been received in less iterations, then quit early */ if (shutdown_wait_for_slaves && repl_semisync_master.get_master_enabled()) { - int waiting_threads= repl_semisync_master.sync_get_master_wait_sessions(); - if (waiting_threads) - sql_print_information("Delaying shutdown to await semi-sync ACK"); - - while (waiting_threads-- > 0) - repl_semisync_master.await_slave_reply(); + repl_semisync_master.await_all_slave_replies( + "Delaying shutdown to await semi-sync ACK"); } - DBUG_EXECUTE_IF("delay_shutdown_phase_2_after_semisync_wait", - my_sleep(500000);); - - Events::deinit(); + if (Events::inited) + Events::stop(); slave_prepare_for_shutdown(); ack_receiver.stop(); @@ -1817,8 +1803,7 @@ static void close_connections(void) */ DBUG_PRINT("info", ("THD_count: %u", THD_count::value())); - for (int i= 0; THD_count::connection_thd_count() - n_threads_awaiting_ack - && i < 1000; i++) + for (int i= 0; THD_count::connection_thd_count() && i < 1000; i++) { if (DBUG_IF("only_kill_system_threads_no_loop")) break; @@ -1837,9 +1822,9 @@ static void close_connections(void) #endif /* All threads has now been aborted */ DBUG_PRINT("quit", ("Waiting for threads to die (count=%u)", - THD_count::connection_thd_count() - n_threads_awaiting_ack)); + THD_count::connection_thd_count())); - while (THD_count::connection_thd_count() - n_threads_awaiting_ack) + while (THD_count::connection_thd_count()) { if (DBUG_IF("only_kill_system_threads_no_loop")) break; @@ -1860,6 +1845,12 @@ static void close_connections(void) } /* End of kill phase 2 */ + /* + The signal thread can use server resources, e.g. when processing SIGHUP, + and it must end gracefully before clean_up() + */ + wait_for_signal_thread_to_end(); + DBUG_PRINT("quit",("close_connections thread")); DBUG_VOID_RETURN; } @@ -1928,6 +1919,7 @@ extern "C" void unireg_abort(int exit_code) wsrep_sst_auth_free(); #endif // WITH_WSREP + wait_for_signal_thread_to_end(); clean_up(!opt_abort && (exit_code || !opt_bootstrap)); /* purecov: inspected */ DBUG_PRINT("quit",("done with cleanup in unireg_abort")); mysqld_exit(exit_code); @@ -1936,14 +1928,8 @@ extern "C" void unireg_abort(int exit_code) static void mysqld_exit(int exit_code) { DBUG_ENTER("mysqld_exit"); - /* - Important note: we wait for the signal thread to end, - but if a kill -15 signal was sent, the signal thread did - spawn the kill_server_thread thread, which is running concurrently. - */ rpl_deinit_gtid_waiting(); rpl_deinit_gtid_slave_state(); - wait_for_signal_thread_to_end(); #ifdef WITH_WSREP wsrep_deinit_server(); wsrep_sst_auth_free(); @@ -2025,6 +2011,9 @@ static void clean_up(bool print_message) free_status_vars(); end_thr_alarm(1); /* Free allocated memory */ end_thr_timer(); +#ifndef EMBEDDED_LIBRARY + Events::deinit(); +#endif my_free_open_file_info(); if (defaults_argv) free_defaults(defaults_argv); @@ -2095,16 +2084,31 @@ static void clean_up(bool print_message) */ static void wait_for_signal_thread_to_end() { - uint i; + uint i, n_waits= DBUG_IF("force_sighup_processing_timeout") ? 5 : 100; + int err= 0; /* Wait up to 10 seconds for signal thread to die. We use this mainly to avoid getting warnings that my_thread_end has not been called */ - for (i= 0 ; i < 100 && signal_thread_in_use; i++) + for (i= 0 ; i < n_waits && signal_thread_in_use; i++) { - if (pthread_kill(signal_thread, MYSQL_KILL_SIGNAL) == ESRCH) + err= pthread_kill(signal_thread, MYSQL_KILL_SIGNAL); + if (err) break; - my_sleep(100); // Give it time to die + my_sleep(100000); // Give it time to die, .1s per iteration + } + + if (err && err != ESRCH) + { + sql_print_error("Failed to send kill signal to signal handler thread, " + "pthread_kill() errno: %d", err); + } + + if (i == n_waits && signal_thread_in_use && !opt_bootstrap) + { + sql_print_warning("Signal handler thread did not exit in a timely manner. " + "Continuing to wait for it to stop.."); + pthread_join(signal_thread, NULL); } } #endif /*EMBEDDED_LIBRARY*/ @@ -2129,7 +2133,9 @@ static void clean_up_mutexes() mysql_mutex_destroy(&LOCK_global_table_stats); mysql_mutex_destroy(&LOCK_global_index_stats); #ifdef HAVE_OPENSSL +#ifdef HAVE_des mysql_mutex_destroy(&LOCK_des_key_file); +#endif /* HAVE_des */ #if defined(HAVE_OPENSSL10) && !defined(HAVE_WOLFSSL) for (int i= 0; i < CRYPTO_num_locks(); ++i) mysql_rwlock_destroy(&openssl_stdlocks[i].lock); @@ -3140,10 +3146,8 @@ void init_signals(void) (void) sigemptyset(&set); my_sigset(SIGPIPE,SIG_IGN); sigaddset(&set,SIGPIPE); -#ifndef IGNORE_SIGHUP_SIGQUIT sigaddset(&set,SIGQUIT); sigaddset(&set,SIGHUP); -#endif sigaddset(&set,SIGTERM); /* Fix signals if blocked by parents (can happen on Mac OS X) */ @@ -3183,7 +3187,6 @@ static void start_signal_handler(void) (void) pthread_attr_init(&thr_attr); pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_SYSTEM); - (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); (void) my_setstacksize(&thr_attr,my_thread_stack_size); mysql_mutex_lock(&LOCK_start_thread); @@ -3203,18 +3206,6 @@ static void start_signal_handler(void) } -#if defined(USE_ONE_SIGNAL_HAND) -pthread_handler_t kill_server_thread(void *arg __attribute__((unused))) -{ - my_thread_init(); // Initialize new thread - break_connect_loop(); - my_thread_end(); - pthread_exit(0); - return 0; -} -#endif - - /** This threads handles all signals and alarms. */ /* ARGSUSED */ pthread_handler_t signal_hand(void *arg __attribute__((unused))) @@ -3222,7 +3213,6 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) sigset_t set; int sig; my_thread_init(); // Init new thread - DBUG_ENTER("signal_hand"); signal_thread_in_use= 1; /* @@ -3239,20 +3229,20 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) (void) sigaddset(&set,SIGINT); (void) pthread_sigmask(SIG_UNBLOCK,&set,NULL); } - (void) sigemptyset(&set); // Setup up SIGINT for debug + (void) sigemptyset(&set); #ifdef USE_ONE_SIGNAL_HAND (void) sigaddset(&set,THR_SERVER_ALARM); // For alarms #endif -#ifndef IGNORE_SIGHUP_SIGQUIT (void) sigaddset(&set,SIGQUIT); - (void) sigaddset(&set,SIGHUP); -#endif (void) sigaddset(&set,SIGTERM); (void) sigaddset(&set,SIGTSTP); /* Save pid to this process (or thread on Linux) */ if (!opt_bootstrap) + { + (void) sigaddset(&set,SIGHUP); create_pid_file(); + } /* signal to start_signal_handler that we are ready @@ -3272,11 +3262,10 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) int origin; while ((error= my_sigwait(&set, &sig, &origin)) == EINTR) /* no-op */; - if (cleanup_done) + if (abort_loop) { DBUG_PRINT("quit",("signal_handler: calling my_thread_end()")); my_thread_end(); - DBUG_LEAVE; // Must match DBUG_ENTER() signal_thread_in_use= 0; pthread_exit(0); // Safety return 0; // Avoid compiler warnings @@ -3296,18 +3285,8 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) { /* Delete the instrumentation for the signal thread */ PSI_CALL_delete_current_thread(); -#ifdef USE_ONE_SIGNAL_HAND - pthread_t tmp; - if (unlikely((error= mysql_thread_create(0, /* Not instrumented */ - &tmp, &connection_attrib, - kill_server_thread, - (void*) &sig)))) - sql_print_error("Can't create thread to kill server (errno= %d)", - error); -#else my_sigset(sig, SIG_IGN); break_connect_loop(); // MIT THREAD has a alarm thread -#endif } break; case SIGHUP: @@ -3794,20 +3773,35 @@ static void my_malloc_size_cb_func(long long size, my_bool is_thread_specific) thd->status_var.local_memory_used > (int64)thd->variables.max_mem_used && likely(!thd->killed) && !thd->get_stmt_da()->is_set()) { - /* Ensure we don't get called here again */ - char buf[50], *buf2; - thd->set_killed(KILL_QUERY); - my_snprintf(buf, sizeof(buf), "--max-session-mem-used=%llu", - thd->variables.max_mem_used); - if ((buf2= (char*) thd->alloc(256))) - { - my_snprintf(buf2, 256, ER_THD(thd, ER_OPTION_PREVENTS_STATEMENT), buf); - thd->set_killed(KILL_QUERY, ER_OPTION_PREVENTS_STATEMENT, buf2); - } - else - { - thd->set_killed(KILL_QUERY, ER_OPTION_PREVENTS_STATEMENT, - "--max-session-mem-used"); + /* + Ensure we don't get called here again. + + It is not safe to wait for LOCK_thd_kill here, as we could be called + from almost any context. For example while LOCK_plugin is being held; + but THD::awake() locks LOCK_thd_kill and LOCK_plugin in the opposite + order (MDEV-33443). + + So ignore the max_mem_used limit in the unlikely case we cannot obtain + LOCK_thd_kill here (the limit will be enforced on the next allocation). + */ + if (!mysql_mutex_trylock(&thd->LOCK_thd_kill)) { + char buf[50], *buf2; + thd->set_killed_no_mutex(KILL_QUERY); + my_snprintf(buf, sizeof(buf), "--max-session-mem-used=%llu", + thd->variables.max_mem_used); + if ((buf2= (char*) thd->alloc(256))) + { + my_snprintf(buf2, 256, + ER_THD(thd, ER_OPTION_PREVENTS_STATEMENT), buf); + thd->set_killed_no_mutex(KILL_QUERY, + ER_OPTION_PREVENTS_STATEMENT, buf2); + } + else + { + thd->set_killed_no_mutex(KILL_QUERY, ER_OPTION_PREVENTS_STATEMENT, + "--max-session-mem-used"); + } + mysql_mutex_unlock(&thd->LOCK_thd_kill); } } DBUG_ASSERT((longlong) thd->status_var.local_memory_used >= 0 || @@ -4117,8 +4111,9 @@ static int init_common_variables() SQLCOM_END + 10); #endif - if (get_options(&remaining_argc, &remaining_argv)) - exit(1); + int opt_err; + if ((opt_err= get_options(&remaining_argc, &remaining_argv))) + exit(opt_err); if (IS_SYSVAR_AUTOSIZE(&server_version_ptr)) set_server_version(server_version, sizeof(server_version)); @@ -4520,8 +4515,10 @@ static int init_thread_environment() mysql_mutex_init(key_LOCK_temp_pool, &LOCK_temp_pool, MY_MUTEX_INIT_FAST); #ifdef HAVE_OPENSSL +#ifdef HAVE_des mysql_mutex_init(key_LOCK_des_key_file, &LOCK_des_key_file, MY_MUTEX_INIT_FAST); +#endif /* HAVE_des */ #if defined(HAVE_OPENSSL10) && !defined(HAVE_WOLFSSL) openssl_stdlocks= (openssl_lock_t*) OPENSSL_malloc(CRYPTO_num_locks() * sizeof(openssl_lock_t)); @@ -4740,8 +4737,10 @@ static void init_ssl() { have_ssl= SHOW_OPTION_DISABLED; } +#ifdef HAVE_des if (des_key_file) load_des_key_file(des_key_file); +#endif /* HAVE_des */ #endif /* HAVE_OPENSSL */ #endif /* !EMBEDDED_LIBRARY */ } @@ -4982,10 +4981,13 @@ static int init_server_components() error_handler_hook= my_message_sql; proc_info_hook= set_thd_stage_info; + /* Set up hook to handle disk full */ + my_sleep_for_space= mariadb_sleep_for_space; + /* - Print source revision hash, as one of the first lines, if not the - first in error log, for troubleshooting and debugging purposes - */ + Print source revision hash, as one of the first lines, if not the + first in error log, for troubleshooting and debugging purposes + */ if (!opt_help) sql_print_information("Starting MariaDB %s source revision %s as process %lu", server_version, SOURCE_REVISION, (ulong) getpid()); @@ -5013,6 +5015,19 @@ static int init_server_components() xid_cache_init(); + /* + Do not open binlong when doing bootstrap. + This ensures that rpl_load_gtid_slave_state() will not fail with an error + as the mysql schema does not yet exists. + This also ensures that we don't get an empty binlog file if the user has + log-bin in his config files. + */ + if (opt_bootstrap) + { + opt_bin_log= opt_bin_log_used= binlog_format_used= 0; + opt_log_slave_updates= 0; + } + /* need to configure logging before initializing storage engines */ if (!opt_bin_log_used && !WSREP_ON) { @@ -5473,6 +5488,10 @@ static int init_server_components() } #endif +#ifndef EMBEDDED_LIBRARY + start_handle_manager(); +#endif + tc_log= get_tc_log_implementation(); if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file)) @@ -5484,9 +5503,6 @@ static int init_server_components() if (ha_recover(0)) unireg_abort(1); -#ifndef EMBEDDED_LIBRARY - start_handle_manager(); -#endif if (opt_bin_log) { int error; @@ -6587,12 +6603,12 @@ struct my_option my_long_options[]= &opt_debug_sync_timeout, 0, 0, GET_UINT, OPT_ARG, 0, 0, UINT_MAX, 0, 0, 0}, #endif /* defined(ENABLED_DEBUG_SYNC) */ -#ifdef HAVE_OPENSSL +#ifdef HAVE_des {"des-key-file", 0, "Load keys for des_encrypt() and des_encrypt from given file.", &des_key_file, &des_key_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#endif /* HAVE_OPENSSL */ +#endif /* HAVE_des */ #ifdef HAVE_STACKTRACE {"stack-trace", 0 , "Print a symbolic stack trace on failure", &opt_stack_trace, &opt_stack_trace, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, @@ -7942,7 +7958,9 @@ static int mysql_init_variables(void) libwrapName= NullS; #endif #ifdef HAVE_OPENSSL +#ifdef HAVE_des des_key_file = 0; +#endif /* HAVE_des */ #ifndef EMBEDDED_LIBRARY ssl_acceptor_fd= 0; #endif /* ! EMBEDDED_LIBRARY */ @@ -8239,7 +8257,7 @@ mysqld_get_one_option(const struct my_option *opt, const char *argument, case (int) OPT_SAFE: opt_specialflag|= SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC; SYSVAR_AUTOSIZE(delay_key_write_options, (uint) DELAY_KEY_WRITE_NONE); - SYSVAR_AUTOSIZE(myisam_recover_options, HA_RECOVER_DEFAULT); + myisam_recover_options= HA_RECOVER_DEFAULT; ha_open_options&= ~(HA_OPEN_DELAY_KEY_WRITE); #ifdef HAVE_QUERY_CACHE SYSVAR_AUTOSIZE(query_cache_size, 0); @@ -9158,7 +9176,9 @@ static PSI_file_info all_server_files[]= { &key_file_io_cache, "io_cache", 0}, { &key_file_casetest, "casetest", 0}, { &key_file_dbopt, "dbopt", 0}, +#ifdef HAVE_des { &key_file_des_key_file, "des_key_file", 0}, +#endif { &key_file_ERRMSG, "ERRMSG", 0}, { &key_select_to_file, "select_to_file", 0}, { &key_file_fileparser, "file_parser", 0}, @@ -9285,6 +9305,7 @@ PSI_stage_info stage_user_lock= { 0, "User lock", 0}; PSI_stage_info stage_user_sleep= { 0, "User sleep", 0}; PSI_stage_info stage_verifying_table= { 0, "Verifying table", 0}; PSI_stage_info stage_waiting_for_delay_list= { 0, "Waiting for delay_list", 0}; +PSI_stage_info stage_waiting_for_disk_space= {0, "Waiting for someone to free space", 0}; PSI_stage_info stage_waiting_for_gtid_to_be_written_to_binary_log= { 0, "Waiting for GTID to be written to binary log", 0}; PSI_stage_info stage_waiting_for_handler_insert= { 0, "Waiting for handler insert", 0}; PSI_stage_info stage_waiting_for_handler_lock= { 0, "Waiting for handler lock", 0}; |