summaryrefslogtreecommitdiff
path: root/sql/mysqld.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/mysqld.cc')
-rw-r--r--sql/mysqld.cc119
1 files changed, 98 insertions, 21 deletions
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index bf1780ed082..fa9387ac51a 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -466,6 +466,7 @@ uint protocol_version;
uint lower_case_table_names;
ulong tc_heuristic_recover= 0;
Atomic_counter<uint32_t> thread_count;
+bool shutdown_wait_for_slaves;
int32 slave_open_temp_tables;
ulong thread_created;
ulong back_log, connect_timeout, concurrency, server_id;
@@ -1519,19 +1520,9 @@ static void end_ssl();
** Code to end mysqld
****************************************************************************/
-static my_bool kill_all_threads(THD *thd, void *)
+/* common callee of two shutdown phases */
+static void kill_thread(THD *thd)
{
- DBUG_PRINT("quit", ("Informing thread %ld that it's time to die",
- (ulong) thd->thread_id));
- /* We skip slave threads on this first loop through. */
- if (thd->slave_thread)
- return 0;
-
- if (DBUG_EVALUATE_IF("only_kill_system_threads", !thd->system_thread, 0))
- return 0;
-
- thd->set_killed(KILL_SERVER_HARD);
- MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (thd));
if (WSREP(thd)) mysql_mutex_lock(&thd->LOCK_thd_data);
mysql_mutex_lock(&thd->LOCK_thd_kill);
if (thd->mysys_var)
@@ -1557,16 +1548,73 @@ static my_bool kill_all_threads(THD *thd, void *)
}
mysql_mutex_unlock(&thd->LOCK_thd_kill);
if (WSREP(thd)) mysql_mutex_unlock(&thd->LOCK_thd_data);
+}
+
+
+/**
+ First shutdown everything but slave threads and binlog dump connections
+*/
+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())
+ return 0;
+
+ if (DBUG_EVALUATE_IF("only_kill_system_threads", !thd->system_thread, 0))
+ return 0;
+
+ thd->set_killed(KILL_SERVER_HARD);
+ MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (thd));
+ kill_thread(thd);
return 0;
}
-static my_bool warn_threads_still_active(THD *thd, void *)
+/**
+ Last shutdown binlog dump connections
+*/
+static my_bool kill_thread_phase_2(THD *thd, void *)
+{
+ if (shutdown_wait_for_slaves)
+ {
+ thd->set_killed(KILL_SERVER);
+ }
+ else
+ {
+ thd->set_killed(KILL_SERVER_HARD);
+ MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (thd));
+ }
+ kill_thread(thd);
+ return 0;
+}
+
+
+/* associated with the kill thread phase 1 */
+static my_bool warn_threads_active_after_phase_1(THD *thd, void *)
+{
+ if (!thd->is_binlog_dump_thread())
+ sql_print_warning("%s: Thread %llu (user : '%s') did not exit\n", my_progname,
+ (ulonglong) thd->thread_id,
+ (thd->main_security_ctx.user ?
+ thd->main_security_ctx.user : ""));
+ return 0;
+}
+
+
+/* associated with the kill thread phase 2 */
+static my_bool warn_threads_active_after_phase_2(THD *thd, void *)
{
- sql_print_warning("%s: Thread %llu (user : '%s') did not exit\n", my_progname,
- (ulonglong) thd->thread_id,
- (thd->main_security_ctx.user ?
- thd->main_security_ctx.user : ""));
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+ // dump thread may not have yet (or already) current_linfo set
+ sql_print_warning("Dump thread %llu last sent to server %lu "
+ "binlog file:pos %s:%llu",
+ thd->thread_id, thd->variables.server_id,
+ thd->current_linfo ?
+ my_basename(thd->current_linfo->log_file_name) : "NULL",
+ thd->current_linfo ? thd->current_linfo->pos : 0);
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+
return 0;
}
@@ -1650,6 +1698,21 @@ void kill_mysql(THD *thd)
{
my_free(user);
}
+
+ DBUG_EXECUTE_IF("mysql_admin_shutdown_wait_for_slaves",
+ thd->lex->is_shutdown_wait_for_slaves= true;);
+ DBUG_EXECUTE_IF("simulate_delay_at_shutdown",
+ {
+ DBUG_ASSERT(binlog_dump_thread_count == 3);
+ const char act[]=
+ "now "
+ "SIGNAL greetings_from_kill_mysql";
+ DBUG_ASSERT(!debug_sync_set_action(thd,
+ STRING_WITH_LEN(act)));
+ };);
+
+ if (thd->lex->is_shutdown_wait_for_slaves)
+ shutdown_wait_for_slaves= true;
break_connect_loop();
}
@@ -1693,7 +1756,7 @@ 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.
*/
- server_threads.iterate(kill_all_threads);
+ server_threads.iterate(kill_thread_phase_1);
Events::deinit();
slave_prepare_for_shutdown();
@@ -1716,11 +1779,11 @@ static void close_connections(void)
*/
DBUG_PRINT("info", ("thread_count: %u", uint32_t(thread_count)));
- for (int i= 0; thread_count && i < 1000; i++)
+ for (int i= 0; (thread_count - binlog_dump_thread_count) && i < 1000; i++)
my_sleep(20000);
if (global_system_variables.log_warnings)
- server_threads.iterate(warn_threads_still_active);
+ server_threads.iterate(warn_threads_active_after_phase_1);
#ifdef WITH_WSREP
if (wsrep_inited == 1)
@@ -1732,9 +1795,23 @@ static void close_connections(void)
DBUG_PRINT("quit", ("Waiting for threads to die (count=%u)",
uint32_t(thread_count)));
- while (thread_count)
+ while (thread_count - binlog_dump_thread_count)
my_sleep(1000);
+ /* Kill phase 2 */
+ server_threads.iterate(kill_thread_phase_2);
+ for (uint64 i= 0; thread_count; i++)
+ {
+ /*
+ This time the warnings are emitted within the loop to provide a
+ dynamic view on the shutdown status through the errorlog.
+ */
+ if (global_system_variables.log_warnings > 2 && i % 60000 == 0)
+ server_threads.iterate(warn_threads_active_after_phase_2);
+ my_sleep(1000);
+ }
+ /* End of kill phase 2 */
+
DBUG_PRINT("quit",("close_connections thread"));
DBUG_VOID_RETURN;
}