diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 4d20dde3610..98d006f8649 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2542,11 +2542,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"); @@ -2752,7 +2748,11 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache) unlink_thd(thd); /* Mark that current_thd is not valid anymore */ my_pthread_setspecific_ptr(THR_THD, 0); +#ifdef WITH_WSREP + if (put_in_cache && !thd->wsrep_applier) +#else if (put_in_cache) +#endif /* WITH_WSREP */ { mysql_mutex_lock(&LOCK_thread_count); put_in_cache= cache_thread(); @@ -4836,7 +4836,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)); @@ -4859,7 +4859,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; @@ -4888,10 +4888,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); @@ -4911,6 +4912,7 @@ pthread_handler_t start_wsrep_THD(void *arg) // at server shutdown } +#if 0 if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) { mysql_mutex_lock(&LOCK_thread_count); @@ -4918,6 +4920,8 @@ pthread_handler_t start_wsrep_THD(void *arg) thread_count--; mysql_mutex_unlock(&LOCK_thread_count); } +#endif + my_thread_end(); return(NULL); } @@ -4997,23 +5001,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; @@ -5124,7 +5111,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 } @@ -5199,7 +5186,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. @@ -5219,7 +5206,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) { @@ -6221,11 +6208,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); delete thd; mysql_mutex_unlock(&LOCK_thread_count); @@ -6268,11 +6251,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; DBUG_VOID_RETURN; @@ -6658,11 +6637,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)) { -#ifdef WITH_WSREP - close_connection(thd, ER_OUT_OF_RESOURCES, 1); -#else close_connection(thd, ER_OUT_OF_RESOURCES); -#endif delete thd; continue; } @@ -6857,11 +6832,7 @@ pthread_handler_t handle_connections_shared_memory(void *arg) event_conn_closed)) || my_net_init(&thd->net, thd->net.vio)) { -#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 f392452f56e..99d01c76e0d 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -53,11 +53,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 void handle_connection_in_main_thread(THD *thd); void create_thread_to_handle_connection(THD *thd); void unlink_thd(THD *thd); diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index c350334b46c..07290af8f4f 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -993,11 +993,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 @@ -1239,11 +1235,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; @@ -1302,16 +1294,12 @@ void do_handle_one_connection(THD *thd_arg) } #endif end_thread: -#ifdef WITH_WSREP - close_connection(thd, 0, 1); -#else close_connection(thd); -#endif if (thd->userstat_running) update_global_user_stats(thd, create_user, time(NULL)); - if (MYSQL_CALLBACK_ELSE(thd->scheduler, end_thread, (thd, 1), 0)) + if (MYSQL_CALLBACK_ELSE(thread_scheduler, end_thread, (thd, 1), 0)) return; // Probably no-threads /* diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c091d526220..45581e6a9c3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -622,11 +622,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; diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc index 8eb5340dd58..be60d997265 100644 --- a/sql/wsrep_hton.cc +++ b/sql/wsrep_hton.cc @@ -77,8 +77,13 @@ void wsrep_register_hton(THD* thd, bool all) { trans_register_ha(thd, all, wsrep_hton); - /* follow innodb read/write settting */ - if (i->is_trx_read_write()) + /* follow innodb read/write settting + * but, as an exception: CTAS with empty result set will not be + * replicated unless we declare wsrep hton as read/write here + */ + if (i->is_trx_read_write() || + (thd->lex->sql_command == SQLCOM_CREATE_TABLE && + thd->wsrep_exec_mode == LOCAL_STATE)) { thd->ha_data[wsrep_hton->slot].ha_info[all].set_trx_read_write(); } diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 666952e6f52..9b204172f3e 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1337,6 +1337,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_var.cc b/sql/wsrep_var.cc index 81d436f6116..319c5fca979 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()) { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 152883a3e4c..0cf6f10c143 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3469,6 +3469,9 @@ ha_innobase::max_supported_key_length() const is 16 kB; but currently MySQL does not work with keys whose size is > MAX_KEY_LENGTH */ #ifdef WITH_WSREP + /* this may look like obsolete code, but this ifdef is here + just to make sure we will see bzr merge conflict, if Oracle + changes max key length */ return(3500); #else return(3500); @@ -4617,7 +4620,7 @@ wsrep_innobase_mysql_sort( tmp_length = charset->coll->strnxfrm(charset, str, str_length, tmp_str, str_length); - DBUG_ASSERT(tmp_length == str_length); + DBUG_ASSERT(tmp_length <= str_length); break; } @@ -7443,6 +7446,13 @@ ha_innobase::wsrep_append_keys( } else { ut_a(table->s->keys <= 256); uint i; + bool hasPK= false; + + for (i=0; is->keys && !hasPK; ++i) { + KEY* key_info = table->key_info + i; + if (key_info->flags & HA_NOSAME) hasPK = true; + } + for (i=0; is->keys; ++i) { uint len; char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; @@ -7463,7 +7473,7 @@ ha_innobase::wsrep_append_keys( table->s->table_name.str, key_info->name); } - if (key_info->flags & HA_NOSAME || + if (!hasPK || key_info->flags & HA_NOSAME || ((tab && dict_table_get_referenced_constraint(tab, idx)) || (!tab && referenced_by_foreign_key()))) { diff --git a/storage/innobase/lock/lock0lock.c b/storage/innobase/lock/lock0lock.c index c500bf44ffa..71b3097d012 100644 --- a/storage/innobase/lock/lock0lock.c +++ b/storage/innobase/lock/lock0lock.c @@ -909,6 +909,9 @@ UNIV_INLINE ibool lock_rec_has_to_wait( /*=================*/ +#ifdef WITH_WSREP + ibool for_locking, /*!< is caller locking or releasing */ +#endif /* WITH_WSREP */ const trx_t* trx, /*!< in: trx of new lock */ ulint type_mode,/*!< in: precise mode of the new lock to set: LOCK_S or LOCK_X, possibly @@ -983,6 +986,44 @@ lock_rec_has_to_wait( return(FALSE); } +#ifdef WITH_WSREP + /* if BF thread is locking and has conflict with another BF + thread, we need to look at trx ordering and lock types */ + if (for_locking && + wsrep_thd_is_BF(trx->mysql_thd, FALSE) && + wsrep_thd_is_BF(lock2->trx->mysql_thd, TRUE)) { + + if (wsrep_debug) { + fprintf(stderr, "\n BF-BF lock conflict \n"); + lock_rec_print(stderr, lock2); + } + + if (wsrep_trx_order_before(trx->mysql_thd, + lock2->trx->mysql_thd) && + (type_mode & LOCK_MODE_MASK) == LOCK_X && + (lock2->type_mode & LOCK_MODE_MASK) == LOCK_X) + { + /* exclusive lock conflicts are not accepted */ + fprintf(stderr, "BF-BF X lock conflict\n"); + lock_rec_print(stderr, lock2); + abort(); + } else { + /* if lock2->index->n_uniq <= + lock2->index->n_user_defined_cols + operation is on uniq index + */ + if (wsrep_debug) fprintf(stderr, + "BF conflict, modes: %lu %lu, " + "idx: %s-%s n_uniq %u n_user %u\n", + type_mode, lock2->type_mode, + lock2->index->name, + lock2->index->table_name, + lock2->index->n_uniq, + lock2->index->n_user_defined_cols); + return FALSE; + } + } +#endif /* WITH_WSREP */ return(TRUE); } @@ -1013,7 +1054,11 @@ lock_has_to_wait( /* If this lock request is for a supremum record then the second bit on the lock bitmap is set */ +#ifdef WITH_WSREP + return(lock_rec_has_to_wait(FALSE, lock1->trx, +#else return(lock_rec_has_to_wait(lock1->trx, +#endif /* WITH_WSREP */ lock1->type_mode, lock2, lock_rec_get_nth_bit( lock1, 1))); @@ -1592,7 +1637,11 @@ lock_rec_other_has_conflicting( if (UNIV_UNLIKELY(heap_no == PAGE_HEAP_NO_SUPREMUM)) { do { - if (lock_rec_has_to_wait(trx, mode, lock, +#ifdef WITH_WSREP + if (lock_rec_has_to_wait(TRUE, trx, mode, lock, +#else + if (lock_rec_has_to_wait(trx, mode, lock, +#endif /* WITH_WSREP */ TRUE)) { #ifdef WITH_WSREP wsrep_kill_victim(trx, lock); @@ -1605,7 +1654,11 @@ lock_rec_other_has_conflicting( } else { do { - if (lock_rec_has_to_wait(trx, mode, lock, +#ifdef WITH_WSREP + if (lock_rec_has_to_wait(TRUE, trx, mode, lock, +#else + if (lock_rec_has_to_wait(trx, mode, lock, +#endif /* WITH_WSREP */ FALSE)) { #ifdef WITH_WSREP wsrep_kill_victim(trx, lock);