diff --git a/include/thr_lock.h b/include/thr_lock.h index 4551a3160ff..f05db666da9 100644 --- a/include/thr_lock.h +++ b/include/thr_lock.h @@ -22,7 +22,7 @@ extern "C" { #endif #ifdef WITH_WSREP #include - typedef int (* wsrep_thd_is_brute_force_fun)(void *); + typedef my_bool (* wsrep_thd_is_brute_force_fun)(void *, my_bool); typedef int (* wsrep_abort_thd_fun)(void *, void *, my_bool); typedef int (* wsrep_on_fun)(void *); void wsrep_thr_lock_init( diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 4f7c727594b..59c08240bca 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -690,7 +690,7 @@ wsrep_break_lock( { if (wsrep_on(data->owner->mysql_thd) && wsrep_thd_is_brute_force && - wsrep_thd_is_brute_force(data->owner->mysql_thd)) + wsrep_thd_is_brute_force(data->owner->mysql_thd, TRUE)) { THR_LOCK_DATA *holder; @@ -715,7 +715,7 @@ wsrep_break_lock( holder; holder=holder->next) { - if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd)) + if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd, TRUE)) { wsrep_abort_thd(data->owner->mysql_thd, holder->owner->mysql_thd, FALSE); @@ -731,7 +731,7 @@ wsrep_break_lock( holder; holder=holder->next) { - if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd)) + if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd, TRUE)) { wsrep_abort_thd(data->owner->mysql_thd, holder->owner->mysql_thd, FALSE); diff --git a/sql/log.cc b/sql/log.cc index c0b3f36ee78..a46c85e503b 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -567,8 +567,11 @@ void thd_binlog_trx_reset(THD * thd) { binlog_cache_mngr *const cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); - if (cache_mngr) cache_mngr->reset(false, true); - } + if (cache_mngr) + { + cache_mngr->reset_cache(&cache_mngr->stmt_cache); + cache_mngr->reset_cache(&cache_mngr->trx_cache); + } thd->clear_binlog_table_maps(); } diff --git a/sql/mdl.cc b/sql/mdl.cc index 2f00388a14b..399863d4d73 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -1482,7 +1482,7 @@ void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket) DBUG_ASSERT(ticket->get_lock()); #ifdef WITH_WSREP if ((this == &(ticket->get_lock()->m_waiting)) && - wsrep_thd_is_brute_force((void *)(ticket->get_ctx()->wsrep_get_thd()))) + wsrep_thd_is_BF((void *)(ticket->get_ctx()->get_thd()), false)) { Ticket_iterator itw(ticket->get_lock()->m_waiting); Ticket_iterator itg(ticket->get_lock()->m_granted); @@ -1493,7 +1493,7 @@ void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket) while ((waiting= itw++) && !added) { - if (!wsrep_thd_is_brute_force((void *)(waiting->get_ctx()->wsrep_get_thd()))) + if (!wsrep_thd_is_BF((void *)(waiting->get_ctx()->get_thd()), true)) { WSREP_DEBUG("MDL add_ticket inserted before: %lu %s", wsrep_thd_thread_id(waiting->get_ctx()->wsrep_get_thd()), @@ -1894,7 +1894,7 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, ticket->is_incompatible_when_granted(type_arg)) #ifdef WITH_WSREP { - if (wsrep_thd_is_brute_force((void *)(requestor_ctx->wsrep_get_thd())) && + if (wsrep_thd_is_BF((void *)(requestor_ctx->get_thd()), false) && key.mdl_namespace() == MDL_key::GLOBAL) { WSREP_DEBUG("global lock granted for BF: %lu %s", @@ -1935,7 +1935,7 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, #ifdef WITH_WSREP else { - if (wsrep_thd_is_brute_force((void *)(requestor_ctx->wsrep_get_thd())) && + if (wsrep_thd_is_BF((void *)(requestor_ctx->get_thd()), false) && key.mdl_namespace() == MDL_key::GLOBAL) { WSREP_DEBUG("global lock granted for BF (waiting queue): %lu %s", diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e486630f390..39ec8c760bf 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2735,11 +2735,7 @@ static void network_init(void) @note For the connection that is doing shutdown, this is called twice */ -#ifdef WITH_WSREP -void close_connection(THD *thd, uint sql_errno, bool lock) -#else void close_connection(THD *thd, uint sql_errno) -#endif { DBUG_ENTER("close_connection"); @@ -2972,7 +2968,11 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache) unlink_thd(thd); /* Mark that current_thd is not valid anymore */ set_current_thd(0); +#ifdef WITH_WSREP + if (put_in_cache && cache_thread() && !thd->wsrep_applier) +#else if (put_in_cache && cache_thread()) +#endif /* WITH_WSREP */ DBUG_RETURN(0); // Thread is reused /* @@ -5248,7 +5248,7 @@ pthread_handler_t start_wsrep_THD(void *arg) thd->thr_create_utime= microsecond_interval_timer(); if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0)) { - close_connection(thd, ER_OUT_OF_RESOURCES, 1); + close_connection(thd, ER_OUT_OF_RESOURCES); statistic_increment(aborted_connects,&LOCK_status); MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); @@ -5271,7 +5271,7 @@ pthread_handler_t start_wsrep_THD(void *arg) thd->thread_stack= (char*) &thd; if (thd->store_globals()) { - close_connection(thd, ER_OUT_OF_RESOURCES, 1); + close_connection(thd, ER_OUT_OF_RESOURCES); statistic_increment(aborted_connects,&LOCK_status); MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); delete thd; @@ -5300,10 +5300,11 @@ pthread_handler_t start_wsrep_THD(void *arg) processor(thd); - close_connection(thd, 0, 1); + close_connection(thd, 0); mysql_mutex_lock(&LOCK_thread_count); wsrep_running_threads--; + WSREP_DEBUG("wsrep running threads now: %lu", wsrep_running_threads); mysql_cond_signal(&COND_thread_count); mysql_mutex_unlock(&LOCK_thread_count); @@ -5323,6 +5324,7 @@ pthread_handler_t start_wsrep_THD(void *arg) // at server shutdown } + my_thread_end(); if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) { mysql_mutex_lock(&LOCK_thread_count); @@ -5409,23 +5411,6 @@ static bool have_client_connections() return false; } -/* - returns the number of wsrep appliers running. - However, the caller (thd parameter) is not taken in account - */ -static int have_wsrep_appliers(THD *thd) -{ - int ret= 0; - THD *tmp; - - I_List_iterator it(threads); - while ((tmp=it++)) - { - ret+= (tmp != thd && tmp->wsrep_applier); - } - return ret; -} - static void wsrep_close_thread(THD *thd) { thd->killed= KILL_CONNECTION; @@ -5536,7 +5521,7 @@ void wsrep_close_client_connections(my_bool wait_to_end) !is_replaying_connection(tmp)) { WSREP_INFO("killing local connection: %ld",tmp->thread_id); - close_connection(tmp,0,0); + close_connection(tmp,0); } #endif } @@ -5611,7 +5596,7 @@ void wsrep_wait_appliers_close(THD *thd) { /* Wait for wsrep appliers to gracefully exit */ mysql_mutex_lock(&LOCK_thread_count); - while (have_wsrep_appliers(thd) > 1) + while (wsrep_running_threads > 1) // 1 is for rollbacker thread which needs to be killed explicitly. // This gotta be fixed in a more elegant manner if we gonna have arbitrary // number of non-applier wsrep threads. @@ -5631,7 +5616,7 @@ void wsrep_wait_appliers_close(THD *thd) wsrep_close_threads (thd); /* and wait for them to die */ mysql_mutex_lock(&LOCK_thread_count); - while (have_wsrep_appliers(thd) > 0) + while (wsrep_running_threads > 0) { if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) { @@ -6630,11 +6615,7 @@ void create_thread_to_handle_connection(THD *thd) my_snprintf(error_message_buff, sizeof(error_message_buff), ER_THD(thd, ER_CANT_CREATE_THREAD), error); net_send_error(thd, ER_CANT_CREATE_THREAD, error_message_buff, NULL); -#ifdef WITH_WSREP - close_connection(thd, ER_OUT_OF_RESOURCES ,0); -#else close_connection(thd, ER_OUT_OF_RESOURCES); -#endif /* WITH_WSREP */ mysql_mutex_lock(&LOCK_thread_count); thd->unlink(); @@ -6680,11 +6661,7 @@ static void create_new_thread(THD *thd) mysql_mutex_unlock(&LOCK_connection_count); DBUG_PRINT("error",("Too many connections")); -#ifdef WITH_WSREP - close_connection(thd, ER_CON_COUNT_ERROR, 1); -#else close_connection(thd, ER_CON_COUNT_ERROR); -#endif /* WITH_WSREP */ statistic_increment(denied_connections, &LOCK_status); delete thd; statistic_increment(connection_errors_max_connection, &LOCK_status); @@ -7095,11 +7072,7 @@ pthread_handler_t handle_connections_namedpipes(void *arg) if (!(thd->net.vio= vio_new_win32pipe(hConnectedPipe)) || my_net_init(&thd->net, thd->net.vio, MYF(MY_THREAD_SPECIFIC))) { -#ifdef WITH_WSREP - close_connection(thd, ER_OUT_OF_RESOURCES, 1); -#else close_connection(thd, ER_OUT_OF_RESOURCES); -#endif delete thd; set_current_thd(0); continue; @@ -7297,11 +7270,7 @@ pthread_handler_t handle_connections_shared_memory(void *arg) event_conn_closed)) || my_net_init(&thd->net, thd->net.vio, MYF(MY_THREAD_SPECIFIC))) { -#ifdef WITH_WSREP - close_connection(thd, ER_OUT_OF_RESOURCES, 1); -#else close_connection(thd, ER_OUT_OF_RESOURCES); -#endif errmsg= 0; goto errorconn; } diff --git a/sql/mysqld.h b/sql/mysqld.h index 3cd810f7040..86823d8fc54 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -55,11 +55,7 @@ typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */ some places */ /* Function prototypes */ void kill_mysql(void); -#ifdef WITH_WSREP -void close_connection(THD *thd, uint sql_errno= 0, bool lock=1); -#else void close_connection(THD *thd, uint sql_errno= 0); -#endif /* WITH_WSREP */ void handle_connection_in_main_thread(THD *thd); void create_thread_to_handle_connection(THD *thd); void delete_running_thd(THD *thd); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5c70c4501f0..04dc73d1b10 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8830,7 +8830,7 @@ bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use, #ifdef WITH_WSREP { signalled|= mysql_lock_abort_for_thread(thd, thd_table); - if (thd && WSREP(thd) && wsrep_thd_is_brute_force((void *)thd)) + if (thd && WSREP(thd) && wsrep_thd_is_BF((void *)thd, true)) { WSREP_DEBUG("remove_table_from_cache: %llu", (unsigned long long) thd->real_id); diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 03d9a804372..843a3a812dc 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1102,11 +1102,7 @@ bool setup_connection_thread_globals(THD *thd) { if (thd->store_globals()) { -#ifdef WITH_WSREP - close_connection(thd, ER_OUT_OF_RESOURCES, 1); -#else close_connection(thd, ER_OUT_OF_RESOURCES); -#endif statistic_increment(aborted_connects,&LOCK_status); MYSQL_CALLBACK(thd->scheduler, end_thread, (thd, 0)); return 1; // Error @@ -1351,11 +1347,7 @@ void do_handle_one_connection(THD *thd_arg) if (MYSQL_CALLBACK_ELSE(thd->scheduler, init_new_connection_thread, (), 0)) { -#ifdef WITH_WSREP - close_connection(thd, ER_OUT_OF_RESOURCES, 1); -#else close_connection(thd, ER_OUT_OF_RESOURCES); -#endif statistic_increment(aborted_connects,&LOCK_status); MYSQL_CALLBACK(thd->scheduler, end_thread, (thd, 0)); return; @@ -1413,13 +1405,9 @@ void do_handle_one_connection(THD *thd_arg) thd->wsrep_query_state= QUERY_EXITING; mysql_mutex_unlock(&thd->LOCK_wsrep_thd); } -#endif -end_thread: -#ifdef WITH_WSREP - close_connection(thd, 0, 1); -#else - close_connection(thd); #endif +end_thread: + close_connection(thd); if (thd->userstat_running) update_global_user_stats(thd, create_user, time(NULL)); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e3fa61d11e8..681741fed1e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -808,11 +808,7 @@ void do_handle_bootstrap(THD *thd) if (my_thread_init() || thd->store_globals()) { #ifndef EMBEDDED_LIBRARY -#ifdef WITH_WSREP - close_connection(thd, ER_OUT_OF_RESOURCES, 1); -#else close_connection(thd, ER_OUT_OF_RESOURCES); -#endif /* WITH_WSREP */ #endif thd->fatal_error(); goto end; @@ -7884,7 +7880,7 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ #ifdef WITH_WSREP if (((thd->security_ctx->master_access & SUPER_ACL) || thd->security_ctx->user_matches(tmp->security_ctx)) && - !wsrep_thd_is_brute_force((void *)tmp)) + !wsrep_thd_is_BF((void *)tmp, true)) #else if ((thd->security_ctx->master_access & SUPER_ACL) || thd->security_ctx->user_matches(tmp->security_ctx)) diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index c6ee9532919..38b34a061d4 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -663,7 +663,7 @@ void wsrep_init_startup (bool first) { if (wsrep_init()) unireg_abort(1); - wsrep_thr_lock_init(wsrep_thd_is_brute_force, wsrep_abort_thd, + wsrep_thr_lock_init(wsrep_thd_is_BF, wsrep_abort_thd, wsrep_debug, wsrep_convert_LOCK_to_trx, wsrep_on); /* Skip replication start if no cluster address */ @@ -1370,6 +1370,13 @@ int wsrep_to_isolation_begin(THD *thd, char *db_, char *table_, DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE); DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno == WSREP_SEQNO_UNDEFINED); + if (thd->global_read_lock.can_acquire_protection()) + { + WSREP_DEBUG("Aborting TOI: Global Read-Lock (FTWRL) in place: %s %lu", + thd->query(), thd->thread_id); + return -1; + } + if (wsrep_debug && thd->mdl_context.has_locks()) { WSREP_DEBUG("thread holds MDL locks at TI begin: %s %lu", diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index 2e1e86f2f30..e68120ee779 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -473,27 +473,51 @@ void wsrep_create_rollbacker() } extern "C" -int wsrep_thd_is_brute_force(void *thd_ptr) -{ - /* - Brute force: - Appliers and replaying are running in REPL_RECV mode. TOI statements - in TOTAL_ORDER mode. Locally committing transaction that has got - past wsrep->pre_commit() without error is running in LOCAL_COMMIT mode. - - Everything else is running in LOCAL_STATE and should not be considered - brute force. - */ - if (thd_ptr) { - switch (((THD *)thd_ptr)->wsrep_exec_mode) { - case LOCAL_STATE: return 0; - case REPL_RECV: return 1; - case TOTAL_ORDER: return 2; - case LOCAL_COMMIT: return 3; - } - DBUG_ASSERT(0); +my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync) +{ + my_bool status = FALSE; + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + status = ((thd->wsrep_exec_mode == REPL_RECV) || + (thd->wsrep_exec_mode == TOTAL_ORDER)); + if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd); } - return 0; + return status; +} + +extern "C" +my_bool wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync) +{ + bool status = FALSE; + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + status = ((thd->wsrep_exec_mode == REPL_RECV) || + (thd->wsrep_exec_mode == TOTAL_ORDER) || + (thd->wsrep_exec_mode == LOCAL_COMMIT)); + if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + return status; +} + +extern "C" +my_bool wsrep_thd_is_local(void *thd_ptr, my_bool sync) +{ + bool status = FALSE; + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + status = (thd->wsrep_exec_mode == LOCAL_STATE); + if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } + return status; } extern "C" diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h index bded13b5684..74e3bff120c 100644 --- a/sql/wsrep_thd.h +++ b/sql/wsrep_thd.h @@ -24,7 +24,9 @@ void wsrep_replay_transaction(THD *thd); void wsrep_create_appliers(long threads); void wsrep_create_rollbacker(); -extern "C" int wsrep_thd_is_brute_force(void *thd_ptr); +extern "C" my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +extern "C" my_bool wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync); +extern "C" my_bool wsrep_thd_is_local(void *thd_ptr, my_bool sync); extern "C" int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal); extern "C" int wsrep_thd_in_locking_session(void *thd_ptr); diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index 02e2584e86d..d187c7b9e35 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -331,7 +331,16 @@ bool wsrep_cluster_address_update (sys_var *self, THD* thd, enum_var_type type) bool wsrep_on_saved= thd->variables.wsrep_on; thd->variables.wsrep_on= false; + /* stop replication is heavy operation, and includes closing all client + connections. Closing clients may need to get LOCK_global_system_variables + at least in MariaDB. + + Note: releasing LOCK_global_system_variables may cause race condition, if + there can be several concurrent clients changing wsrep_provider + */ + mysql_mutex_unlock(&LOCK_global_system_variables); wsrep_stop_replication(thd); + mysql_mutex_lock(&LOCK_global_system_variables); if (wsrep_start_replication()) {