diff options
34 files changed, 220 insertions, 130 deletions
diff --git a/include/my_pthread.h b/include/my_pthread.h index de1f0af070a..3459180b9b2 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -691,7 +691,7 @@ struct st_my_thread_var mysql_mutex_t * volatile current_mutex; mysql_cond_t * volatile current_cond; pthread_t pthread_self; - my_thread_id id; + my_thread_id id, dbug_id; int volatile abort; my_bool init; struct st_my_thread_var *next,**prev; diff --git a/include/thr_lock.h b/include/thr_lock.h index bc916b8ec9c..fb69d8a693e 100644 --- a/include/thr_lock.h +++ b/include/thr_lock.h @@ -139,9 +139,10 @@ typedef struct st_thr_lock { extern LIST *thr_lock_thread_list; extern mysql_mutex_t THR_LOCK_lock; +struct st_my_thread_var; my_bool init_thr_lock(void); /* Must be called once/thread */ -void thr_lock_info_init(THR_LOCK_INFO *info); +void thr_lock_info_init(THR_LOCK_INFO *info, struct st_my_thread_var *tmp); void thr_lock_init(THR_LOCK *lock); void thr_lock_delete(THR_LOCK *lock); void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index bcb45aefbfb..7855a5f2a73 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -667,8 +667,7 @@ void init_embedded_mysql(MYSQL *mysql, int client_flag) */ void *create_embedded_thd(int client_flag) { - THD * thd= new THD; - thd->thread_id= thd->variables.pseudo_thread_id= next_thread_id(); + THD * thd= new THD(next_thread_id()); thd->thread_stack= (char*) &thd; if (thd->store_globals()) diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index 1e4b85583b1..60a46997901 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -294,7 +294,7 @@ my_bool my_thread_init(void) STACK_DIRECTION * (long)my_thread_stack_size; mysql_mutex_lock(&THR_LOCK_threads); - tmp->id= ++thread_id; + tmp->id= tmp->dbug_id= ++thread_id; ++THR_thread_count; mysql_mutex_unlock(&THR_LOCK_threads); tmp->init= 1; @@ -400,7 +400,7 @@ my_thread_id my_thread_dbug_id() my_thread_init(). */ struct st_my_thread_var *tmp= my_thread_var; - return tmp ? tmp->id : 0; + return tmp ? tmp->dbug_id : 0; } #ifdef DBUG_OFF diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index da653b12314..e8c4ed9c614 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -465,9 +465,10 @@ void thr_lock_delete(THR_LOCK *lock) } -void thr_lock_info_init(THR_LOCK_INFO *info) +void thr_lock_info_init(THR_LOCK_INFO *info, struct st_my_thread_var *tmp) { - struct st_my_thread_var *tmp= my_thread_var; + if (tmp) + tmp= my_thread_var; info->thread= tmp->pthread_self; info->thread_id= tmp->id; } @@ -1816,7 +1817,7 @@ static void *test_thread(void *arg) printf("Thread %s (%d) started\n",my_thread_name(),param); fflush(stdout); - thr_lock_info_init(&lock_info); + thr_lock_info_init(&lock_info, 0); for (i=0; i < lock_counts[param] ; i++) thr_lock_data_init(locks+tests[param][i].lock_nr,data+i,NULL); for (j=1 ; j < 10 ; j++) /* try locking 10 times */ diff --git a/plugin/feedback/sender_thread.cc b/plugin/feedback/sender_thread.cc index f7b9f440fcd..1b90d2cb340 100644 --- a/plugin/feedback/sender_thread.cc +++ b/plugin/feedback/sender_thread.cc @@ -89,7 +89,7 @@ static int prepare_for_fill(TABLE_LIST *tables) (every increment of global thread_id counts as a new connection in SHOW STATUS and we want to avoid skewing the statistics) */ - thd->thread_id= thd->variables.pseudo_thread_id= thd_thread_id; + thd->variables.pseudo_thread_id= thd->thread_id; mysql_mutex_lock(&LOCK_thread_count); thread_count++; threads.append(thd); @@ -205,10 +205,10 @@ static void send_report(const char *when) /* otherwise, prepare the THD and TABLE_LIST, create and fill the temporary table with data just like - SELECT * FROM IFROEMATION_SCHEMA.feedback is doing, + SELECT * FROM INFORMATION_SCHEMA.feedback is doing, read and concatenate table data into a String. */ - if (!(thd= new THD())) + if (!(thd= new THD(thd_thread_id))) return; if (prepare_for_fill(&tables)) diff --git a/plugin/handler_socket/handlersocket/database.cpp b/plugin/handler_socket/handlersocket/database.cpp index 94eedbf6d04..28ce6c78876 100644 --- a/plugin/handler_socket/handlersocket/database.cpp +++ b/plugin/handler_socket/handlersocket/database.cpp @@ -278,7 +278,7 @@ dbcontext::init_thread(const void *stack_bottom, volatile int& shutdown_flag) DBG_THR(fprintf(stderr, "HNDSOCK init thread\n")); { my_thread_init(); - thd = new THD; + thd = new THD(0); thd->thread_stack = (char *)stack_bottom; DBG_THR(fprintf(stderr, "thread_stack = %p sizeof(THD)=%zu sizeof(mtx)=%zu " diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 6a8bdabb948..ea0163e3f78 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -189,7 +189,6 @@ pre_init_event_thread(THD* thd) thd->net.read_timeout= slave_net_timeout; thd->variables.option_bits|= OPTION_AUTO_IS_NULL; thd->client_capabilities|= CLIENT_MULTI_RESULTS; - thd->thread_id= thd->variables.pseudo_thread_id= next_thread_id(); /* Guarantees that we will see the thread in SHOW PROCESSLIST though its @@ -396,7 +395,7 @@ Event_scheduler::start(int *err_no) if (state > INITIALIZED) goto end; - if (!(new_thd= new THD)) + if (!(new_thd= new THD(next_thread_id()))) { sql_print_error("Event Scheduler: Cannot initialize the scheduler thread"); ret= true; @@ -542,7 +541,7 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name) int res= 0; DBUG_ENTER("Event_scheduler::execute_top"); - if (!(new_thd= new THD())) + if (!(new_thd= new THD(next_thread_id()))) goto error; pre_init_event_thread(new_thd); diff --git a/sql/events.cc b/sql/events.cc index 5ef4d6f55a5..2daf99abffc 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -854,7 +854,7 @@ Events::init(THD *thd, bool opt_noacl_or_bootstrap) if (!thd) { - if (!(thd= new THD())) + if (!(thd= new THD(0))) { res= TRUE; goto end; diff --git a/sql/log.cc b/sql/log.cc index 07fd352d93b..aed30e2bb39 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -9510,10 +9510,9 @@ binlog_background_thread(void *arg __attribute__((unused))) my_thread_init(); DBUG_ENTER("binlog_background_thread"); - thd= new THD; + thd= new THD(next_thread_id()); thd->system_thread= SYSTEM_THREAD_BINLOG_BACKGROUND; thd->thread_stack= (char*) &thd; /* Set approximate stack start */ - thd->thread_id= next_thread_id(); thd->store_globals(); thd->security_ctx->skip_grants(); thd->set_command(COM_DAEMON); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index cfac17ad9ed..835074d6e5f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2949,7 +2949,7 @@ void signal_thd_deleted() /* - Unlink thd from global list of available connections and free thd + Unlink thd from global list of available connections SYNOPSIS unlink_thd() @@ -2971,7 +2971,7 @@ void unlink_thd(THD *thd) thd->add_status_to_global(); unlink_not_visible_thd(thd); - delete thd; + thd->free_connection(); dec_thread_count(); DBUG_VOID_RETURN; @@ -2983,6 +2983,7 @@ void unlink_thd(THD *thd) SYNOPSIS cache_thread() + thd Thread handler NOTES LOCK_thread_cache is used to protect the cache variables @@ -2994,10 +2995,11 @@ void unlink_thd(THD *thd) */ -static bool cache_thread() +static bool cache_thread(THD *thd) { struct timespec abstime; DBUG_ENTER("cache_thread"); + DBUG_ASSERT(thd); mysql_mutex_lock(&LOCK_thread_cache); if (cached_thread_count < thread_cache_size && @@ -3041,13 +3043,12 @@ static bool cache_thread() if (wake_thread) { CONNECT *connect; - THD *thd; wake_thread--; connect= thread_cache.get(); mysql_mutex_unlock(&LOCK_thread_cache); - if (!(thd= connect->create_thd())) + if (!(connect->create_thd(thd))) { /* Out of resources. Free thread to get more resources */ connect->close_and_delete(); @@ -3055,8 +3056,11 @@ static bool cache_thread() } delete connect; - thd->thread_stack= (char*) &thd; // For store_globals - (void) thd->store_globals(); + /* + We have to call store_globals to update mysys_var->id and lock_info + with the new thread_id + */ + thd->store_globals(); #ifdef HAVE_PSI_THREAD_INTERFACE /* @@ -3068,11 +3072,7 @@ static bool cache_thread() PSI_THREAD_CALL(set_thread)(psi); #endif - /* - THD::mysys_var::abort is associated with physical thread rather - than with THD object. So we need to reset this flag before using - this thread for handling of new THD object/connection. - */ + /* reset abort flag for the thread */ thd->mysys_var->abort= 0; thd->thr_create_utime= microsecond_interval_timer(); thd->start_utime= thd->thr_create_utime; @@ -3108,13 +3108,16 @@ static bool cache_thread() bool one_thread_per_connection_end(THD *thd, bool put_in_cache) { DBUG_ENTER("one_thread_per_connection_end"); - const bool wsrep_applier= IF_WSREP(thd->wsrep_applier, false); if (thd) - unlink_thd(thd); + { + const bool wsrep_applier= IF_WSREP(thd->wsrep_applier, false); - if (!wsrep_applier && put_in_cache && cache_thread()) - DBUG_RETURN(0); // Thread is reused + unlink_thd(thd); + if (!wsrep_applier && put_in_cache && cache_thread(thd)) + DBUG_RETURN(0); // Thread is reused + delete thd; + } DBUG_PRINT("info", ("killing thread")); DBUG_LEAVE; // Must match DBUG_ENTER() @@ -4076,9 +4079,9 @@ void init_com_statement_info() extern "C" my_thread_id mariadb_dbug_id() { THD *thd; - if ((thd= current_thd)) + if ((thd= current_thd) && thd->thread_dbug_id) { - return thd->thread_id; + return thd->thread_dbug_id; } return my_thread_dbug_id(); } @@ -6318,7 +6321,7 @@ static void bootstrap(MYSQL_FILE *file) { DBUG_ENTER("bootstrap"); - THD *thd= new THD; + THD *thd= new THD(next_thread_id()); #ifdef WITH_WSREP thd->variables.wsrep_on= 0; #endif @@ -6326,7 +6329,6 @@ static void bootstrap(MYSQL_FILE *file) my_net_init(&thd->net,(st_vio*) 0, (void*) 0, MYF(0)); thd->max_client_packet_length= thd->net.max_packet; thd->security_ctx->master_access= ~(ulong)0; - thd->thread_id= thd->variables.pseudo_thread_id= next_thread_id(); thread_count++; // Safe as only one thread running in_bootstrap= TRUE; diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index df036d0e23f..18c83608cd3 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -967,9 +967,8 @@ handle_rpl_parallel_thread(void *arg) struct rpl_parallel_thread *rpt= (struct rpl_parallel_thread *)arg; my_thread_init(); - thd = new THD; + thd = new THD(next_thread_id()); thd->thread_stack = (char*)&thd; - thd->thread_id= thd->variables.pseudo_thread_id= next_thread_id(); add_to_active_threads(thd); set_current_thd(thd); pthread_detach_this_thread(); diff --git a/sql/scheduler.cc b/sql/scheduler.cc index 2a0138d06a8..de472ae2504 100644 --- a/sql/scheduler.cc +++ b/sql/scheduler.cc @@ -36,7 +36,10 @@ static bool no_threads_end(THD *thd, bool put_in_cache) { if (thd) + { unlink_thd(thd); + delete thd; + } return 1; // Abort handle_one_connection } diff --git a/sql/slave.cc b/sql/slave.cc index 30a0018f490..3fd4b2a19c3 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -292,9 +292,8 @@ handle_slave_init(void *arg __attribute__((unused))) THD *thd; my_thread_init(); - thd= new THD; + thd= new THD(next_thread_id()); thd->thread_stack= (char*) &thd; /* Set approximate stack start */ - thd->thread_id= next_thread_id(); thd->system_thread = SYSTEM_THREAD_SLAVE_INIT; thread_safe_increment32(&service_thread_count); thd->store_globals(); @@ -3071,7 +3070,6 @@ static int init_slave_thread(THD* thd, Master_info *mi, thd->variables.log_slow_filter= global_system_variables.log_slow_filter; set_slave_thread_options(thd); thd->client_capabilities = CLIENT_LOCAL_FILES; - thd->thread_id= thd->variables.pseudo_thread_id= next_thread_id(); if (thd_type == SLAVE_THD_SQL) THD_STAGE_INFO(thd, stage_waiting_for_the_next_event_in_relay_log); @@ -3940,7 +3938,7 @@ pthread_handler_t handle_slave_io(void *arg) mysql= NULL ; retry_count= 0; - thd= new THD; // note that contructor of THD uses DBUG_ ! + thd= new THD(next_thread_id()); // note that contructor of THD uses DBUG_ ! mysql_mutex_lock(&mi->run_lock); /* Inform waiting threads that slave has started */ @@ -4512,7 +4510,7 @@ pthread_handler_t handle_slave_sql(void *arg) #endif serial_rgi= new rpl_group_info(rli); - thd = new THD; // note that contructor of THD uses DBUG_ ! + thd = new THD(next_thread_id()); // note that contructor of THD uses DBUG_ ! thd->thread_stack = (char*)&thd; // remember where our stack is thd->system_thread_info.rpl_sql_info= &sql_info; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 241f19c75a3..c0a865c39f6 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1133,7 +1133,7 @@ bool acl_init(bool dont_read_acl_tables) /* To be able to run this from boot, we allocate a temporary THD */ - if (!(thd=new THD)) + if (!(thd=new THD(0))) DBUG_RETURN(1); /* purecov: inspected */ thd->thread_stack= (char*) &thd; thd->store_globals(); @@ -6570,7 +6570,7 @@ bool grant_init() bool return_val; DBUG_ENTER("grant_init"); - if (!(thd= new THD)) + if (!(thd= new THD(0))) DBUG_RETURN(1); /* purecov: deadcode */ thd->thread_stack= (char*) &thd; thd->store_globals(); diff --git a/sql/sql_audit.cc b/sql/sql_audit.cc index e2132efc528..118b843e1a4 100644 --- a/sql/sql_audit.cc +++ b/sql/sql_audit.cc @@ -460,5 +460,12 @@ void mysql_audit_release(THD *thd) { } +void mysql_audit_init_thd(THD *thd) +{ +} + +void mysql_audit_free_thd(THD *thd) +{ +} #endif /* EMBEDDED_LIBRARY */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 08a9647cf56..c5510d95b64 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -9038,7 +9038,7 @@ my_bool mysql_rm_tmp_tables(void) THD *thd; DBUG_ENTER("mysql_rm_tmp_tables"); - if (!(thd= new THD)) + if (!(thd= new THD(0))) DBUG_RETURN(1); thd->thread_stack= (char*) &thd; thd->store_globals(); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 4be28457859..c8347d0f585 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -337,17 +337,6 @@ void thd_set_killed(THD *thd) } /** - Clear errors from the previous THD - - @param thd THD object -*/ -void thd_clear_errors(THD *thd) -{ - my_errno= 0; - thd->mysys_var->abort= 0; -} - -/** Set thread stack in THD object @param thd Thread object @@ -456,7 +445,7 @@ my_socket thd_get_fd(THD *thd) { return mysql_socket_getfd(thd->net.vio->mysql_socket); } -#endif +#endif /* ONLY_FOR_MYSQL_CLOSED_SOURCE_SCHEDULED */ /** Get current THD object from thread local data @@ -469,6 +458,18 @@ THD *thd_get_current_thd() } /** + Clear errors from the previous THD + + @param thd THD object +*/ +void thd_clear_errors(THD *thd) +{ + my_errno= 0; + thd->mysys_var->abort= 0; +} + + +/** Get thread attributes for connection threads @retval Reference to thread attribute for connection threads @@ -845,7 +846,7 @@ extern "C" void thd_kill_timeout(THD* thd) } -THD::THD(bool is_wsrep_applier) +THD::THD(my_thread_id id, bool is_wsrep_applier) :Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION, /* statement id */ 0), rli_fake(0), rgi_fake(0), rgi_slave(NULL), @@ -854,17 +855,13 @@ THD::THD(bool is_wsrep_applier) binlog_unsafe_warning_flags(0), binlog_table_maps(0), table_map_for_update(0), - arg_of_last_insert_id_function(FALSE), - first_successful_insert_id_in_prev_stmt(0), - first_successful_insert_id_in_prev_stmt_for_binlog(0), - first_successful_insert_id_in_cur_stmt(0), - stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE), m_examined_row_count(0), accessed_rows_and_keys(0), m_digest(NULL), m_statement_psi(NULL), m_idle_psi(NULL), - thread_id(0), + thread_id(id), + thread_dbug_id(id), os_thread_id(0), global_disable_checkpoint(0), failed_com_change_user(0), @@ -910,6 +907,7 @@ THD::THD(bool is_wsrep_applier) set_current_thd(this); status_var.local_memory_used= sizeof(THD); status_var.global_memory_used= 0; + variables.pseudo_thread_id= thread_id; main_da.init(); /* @@ -973,14 +971,12 @@ THD::THD(bool is_wsrep_applier) #ifndef DBUG_OFF dbug_sentry=THD_SENTRY_MAGIC; #endif -#ifndef EMBEDDED_LIBRARY mysql_audit_init_thd(this); -#endif net.vio=0; net.buff= 0; client_capabilities= 0; // minimalistic client system_thread= NON_SYSTEM_THREAD; - cleanup_done= abort_on_warning= 0; + cleanup_done= free_connection_done= abort_on_warning= 0; peer_port= 0; // For SHOW PROCESSLIST transaction.m_pending_rows_event= 0; transaction.on= 1; @@ -1003,7 +999,6 @@ THD::THD(bool is_wsrep_applier) /* Variables with default values */ proc_info="login"; where= THD::DEFAULT_WHERE; - variables.server_id = global_system_variables.server_id; slave_net = 0; m_command=COM_CONNECT; *scramble= '\0'; @@ -1064,7 +1059,6 @@ THD::THD(bool is_wsrep_applier) tmp= (ulong) (my_rnd(&sql_rand) * 0xffffffff); my_rnd_init(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id); substitute_null_with_insert_id = FALSE; - thr_lock_info_init(&lock_info); /* safety: will be reset after start */ lock_info.mysql_thd= (void *)this; m_token_array= NULL; @@ -1425,10 +1419,16 @@ void THD::init(void) reset_binlog_local_stmt_filter(); set_status_var_init(); bzero((char *) &org_status_var, sizeof(org_status_var)); + status_in_global= 0; start_bytes_received= 0; last_commit_gtid.seq_no= 0; last_stmt= NULL; - status_in_global= 0; + /* Reset status of last insert id */ + arg_of_last_insert_id_function= FALSE; + stmt_depends_on_first_successful_insert_id_in_prev_stmt= FALSE; + first_successful_insert_id_in_prev_stmt= 0; + first_successful_insert_id_in_prev_stmt_for_binlog= 0; + first_successful_insert_id_in_cur_stmt= 0; #ifdef WITH_WSREP wsrep_exec_mode= wsrep_applier ? REPL_RECV : LOCAL_STATE; wsrep_conflict_state= NO_CONFLICT; @@ -1547,12 +1547,14 @@ void THD::init_for_queries() void THD::change_user(void) { - add_status_to_global(); + if (!status_in_global) // Reset in init() + add_status_to_global(); - cleanup(); - reset_killed(); + if (!cleanup_done) + cleanup(); cleanup_done= 0; - status_in_global= 0; + reset_killed(); + thd_clear_errors(this); init(); stmt_map.reset(); my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0, @@ -1616,6 +1618,8 @@ void THD::cleanup(void) my_hash_free(&user_vars); sp_cache_clear(&sp_proc_cache); sp_cache_clear(&sp_func_cache); + auto_inc_intervals_forced.empty(); + auto_inc_intervals_in_cur_stmt_for_binlog.empty(); mysql_ull_cleanup(this); /* All metadata locks must have been released by now. */ @@ -1627,6 +1631,63 @@ void THD::cleanup(void) } +/* + Free all connection related resources associated with a THD. + This is used when we put a thread into the thread cache. + After this call should either call ~THD or reset_for_reuse() depending on + circumstances. +*/ + +void THD::free_connection() +{ + DBUG_ASSERT(free_connection_done == 0); + my_free(db); + db= NULL; +#ifndef EMBEDDED_LIBRARY + if (net.vio) + vio_delete(net.vio); + net.vio= 0; + net_end(&net); +#endif + ha_close_connection(this); + plugin_thdvar_cleanup(this); + mysql_audit_free_thd(this); + main_security_ctx.destroy(); + /* close all prepared statements, to save memory */ + stmt_map.reset(); + free_connection_done= 1; + profiling.restart(); // Reset profiling +} + +/* + Reset thd for reuse by another connection + This is only used for user connections, so the following variables doesn't + have to be reset: + - Replication (slave) variables. + - Variables not reset between each statements. See reset_for_next_command. +*/ + +void THD::reset_for_reuse() +{ + mysql_audit_init_thd(this); + change_user(); // Calls cleanup() & init() + get_stmt_da()->reset_diagnostics_area(); + main_security_ctx.init(); + failed_com_change_user= 0; + is_fatal_error= 0; + client_capabilities= 0; + peer_port= 0; + query_name_consts= 0; // Safety + abort_on_warning= 0; + free_connection_done= 0; + m_command= COM_CONNECT; + profiling.reset(); +#ifdef SIGNAL_WITH_VIO_CLOSE + active_vio = 0; +#endif +} + + THD::~THD() { THD *orig_thd= current_thd; @@ -1653,26 +1714,15 @@ THD::~THD() mysql_mutex_lock(&LOCK_wsrep_thd); mysql_mutex_unlock(&LOCK_wsrep_thd); mysql_mutex_destroy(&LOCK_wsrep_thd); - if (wsrep_rgi) delete wsrep_rgi; -#endif - /* Close connection */ -#ifndef EMBEDDED_LIBRARY - if (net.vio) - vio_delete(net.vio); - net_end(&net); + delete wsrep_rgi; #endif - stmt_map.reset(); /* close all prepared statements */ + if (!free_connection_done) + free_connection(); if (!cleanup_done) cleanup(); mdl_context.destroy(); - ha_close_connection(this); - mysql_audit_release(this); - plugin_thdvar_cleanup(this); - main_security_ctx.destroy(); - my_free(db); - db= NULL; free_root(&transaction.mem_root,MYF(0)); mysql_cond_destroy(&COND_wakeup_ready); mysql_mutex_destroy(&LOCK_wakeup_ready); @@ -1692,7 +1742,6 @@ THD::~THD() rli_fake= NULL; } - mysql_audit_free_thd(this); if (rgi_slave) rgi_slave->cleanup_after_session(); my_free(semisync_info); @@ -2089,7 +2138,16 @@ bool THD::store_globals() Let mysqld define the thread id (not mysys) This allows us to move THD to different threads if needed. */ - mysys_var->id= thread_id; + mysys_var->id= thread_id; + + /* thread_dbug_id should not change for a THD */ + if (!thread_dbug_id) + thread_dbug_id= mysys_var->dbug_id; + else + { + /* This only changes if we are using pool-of-threads */ + mysys_var->dbug_id= thread_dbug_id; + } #ifdef __NR_gettid os_thread_id= (uint32)syscall(__NR_gettid); #else @@ -2106,7 +2164,7 @@ bool THD::store_globals() We have to call thr_lock_info_init() again here as THD may have been created in another thread */ - thr_lock_info_init(&lock_info); + thr_lock_info_init(&lock_info, mysys_var); return 0; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 4819e91ae81..d1e479ae422 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2652,7 +2652,7 @@ public: ulong query_plan_flags; ulong query_plan_fsort_passes; pthread_t real_id; /* For debugging */ - my_thread_id thread_id; + my_thread_id thread_id, thread_dbug_id; uint32 os_thread_id; uint tmp_table, global_disable_checkpoint; uint server_status,open_options; @@ -2764,7 +2764,7 @@ public: /* for IS NULL => = last_insert_id() fix in remove_eq_conds() */ bool substitute_null_with_insert_id; bool in_lock_tables; - bool bootstrap, cleanup_done; + bool bootstrap, cleanup_done, free_connection_done; /** is set if some thread specific value(s) used in a statement. */ bool thread_specific_used; @@ -2906,7 +2906,7 @@ public: /* Debug Sync facility. See debug_sync.cc. */ struct st_debug_sync_control *debug_sync_control; #endif /* defined(ENABLED_DEBUG_SYNC) */ - THD(bool is_wsrep_applier= false); + THD(my_thread_id id, bool is_wsrep_applier= false); ~THD(); @@ -2926,6 +2926,8 @@ public: void change_user(void); void cleanup(void); void cleanup_after_query(); + void free_connection(); + void reset_for_reuse(); bool store_globals(); void reset_globals(); #ifdef SIGNAL_WITH_VIO_CLOSE diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 66564bd5e94..f210762db50 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1299,7 +1299,7 @@ void do_handle_one_connection(CONNECT *connect) ulonglong thr_create_utime= microsecond_interval_timer(); THD *thd; if (connect->scheduler->init_new_connection_thread() || - !(thd= connect->create_thd())) + !(thd= connect->create_thd(NULL))) { scheduler_functions *scheduler= connect->scheduler; connect->close_with_error(0, 0, ER_OUT_OF_RESOURCES); @@ -1426,7 +1426,7 @@ void CONNECT::close_and_delete() void CONNECT::close_with_error(uint sql_errno, const char *message, uint close_error) { - THD *thd= create_thd(); + THD *thd= create_thd(NULL); if (thd) { if (sql_errno) @@ -1460,17 +1460,28 @@ CONNECT::~CONNECT() vio_delete(vio); } -/* Create a THD based on a CONNECT object */ -THD *CONNECT::create_thd() +/* Reuse or create a THD based on a CONNECT object */ + +THD *CONNECT::create_thd(THD *thd) { - my_bool res; - THD *thd; + bool res, thd_reused= thd != 0; DBUG_ENTER("create_thd"); DBUG_EXECUTE_IF("simulate_failed_connection_2", DBUG_RETURN(0); ); - if (!(thd= new THD)) + if (thd) + { + /* reuse old thd */ + thd->reset_for_reuse(); + /* + reset tread_id's, but not thread_dbug_id's as the later isn't allowed + to change as there is already structures in thd marked with the old + value. + */ + thd->thread_id= thd->variables.pseudo_thread_id= thread_id; + } + else if (!(thd= new THD(thread_id))) DBUG_RETURN(0); set_current_thd(thd); @@ -1479,7 +1490,8 @@ THD *CONNECT::create_thd() if (res) { - delete thd; + if (!thd_reused) + delete thd; set_current_thd(0); DBUG_RETURN(0); } @@ -1489,7 +1501,6 @@ THD *CONNECT::create_thd() thd->security_ctx->host= host; thd->extra_port= extra_port; thd->scheduler= scheduler; - thd->thread_id= thd->variables.pseudo_thread_id= thread_id; thd->real_id= real_id; DBUG_RETURN(thd); } diff --git a/sql/sql_connect.h b/sql/sql_connect.h index 22a12e845c7..9cd31814ad7 100644 --- a/sql/sql_connect.h +++ b/sql/sql_connect.h @@ -52,7 +52,7 @@ public: void close_and_delete(); void close_with_error(uint sql_errno, const char *message, uint close_error); - THD *create_thd(); + THD *create_thd(THD *thd); }; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 65af14b62f6..d9923c31468 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2015, Oracle and/or its affiliates. - Copyright (c) 2010, 2015, MariaDB + Copyright (c) 2010, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2041,7 +2041,8 @@ public: MDL_request grl_protection; Delayed_insert(SELECT_LEX *current_select) - :locks_in_memory(0), table(0),tables_in_use(0),stacked_inserts(0), + :locks_in_memory(0), thd(next_thread_id()), + table(0),tables_in_use(0), stacked_inserts(0), status(0), retry(0), handler_thread_initialized(FALSE), group_count(0) { DBUG_ENTER("Delayed_insert constructor"); @@ -2819,7 +2820,6 @@ pthread_handler_t handle_delayed_insert(void *arg) pthread_detach_this_thread(); /* Add thread to THD list so that's it's visible in 'show processlist' */ - thd->thread_id= thd->variables.pseudo_thread_id= next_thread_id(); thd->set_current_time(); add_to_active_threads(thd); if (abort_loop) diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index f540c268923..848358e517a 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1769,7 +1769,7 @@ static void plugin_load(MEM_ROOT *tmp_root) TABLE *table; READ_RECORD read_record_info; int error; - THD *new_thd= new THD; + THD *new_thd= new THD(0); bool result; DBUG_ENTER("plugin_load"); diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index a169823e25e..f3b62991c5c 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -329,13 +329,27 @@ PROFILING::PROFILING() PROFILING::~PROFILING() { + restart(); +} + +/* + Restart profiling from scratch +*/ + +void PROFILING::restart() +{ while (! history.is_empty()) delete history.pop(); if (current != NULL) delete current; + /* Ensure that profiling object can be reused */ + profile_id_counter= 1; + current= NULL; + last= NULL; } + /** Throw away the current profile, because it's useless or unwanted or corrupted. @@ -675,6 +689,6 @@ int PROFILING::fill_statistics_info(THD *thd_arg, TABLE_LIST *tables, Item *cond void PROFILING::reset() { - enabled= thd->variables.option_bits & OPTION_PROFILING; + enabled= (thd->variables.option_bits & OPTION_PROFILING) != 0; } #endif /* ENABLED_PROFILING */ diff --git a/sql/sql_profile.h b/sql/sql_profile.h index 1d770ca1147..38682f3ddec 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -324,6 +324,7 @@ public: /* ... from INFORMATION_SCHEMA.PROFILING ... */ int fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond); void reset(); + void restart(); }; # endif /* ENABLED_PROFILING */ diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index 089f60a2dd8..25d4d93d75f 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -72,7 +72,7 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options, If reload_acl_and_cache() is called from SIGHUP handler we have to allocate temporary THD for execution of acl_reload()/grant_reload(). */ - if (!thd && (thd= (tmp_thd= new THD))) + if (!thd && (thd= (tmp_thd= new THD(0)))) { thd->thread_stack= (char*) &tmp_thd; thd->store_globals(); diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 196c138c04d..836b0563e23 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -162,7 +162,7 @@ bool servers_init(bool dont_read_servers_table) /* To be able to run this from boot, we allocate a temporary THD */ - if (!(thd=new THD)) + if (!(thd=new THD(0))) DBUG_RETURN(TRUE); thd->thread_stack= (char*) &thd; thd->store_globals(); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 758757ea7dd..91e0369d7a3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1642,7 +1642,7 @@ void execute_ddl_log_recovery() /* To be able to run this from boot, we allocate a temporary THD */ - if (!(thd=new THD)) + if (!(thd=new THD(0))) DBUG_VOID_RETURN; thd->thread_stack= (char*) &thd; thd->store_globals(); diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 502bc88c489..db2ef93204c 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -154,7 +154,7 @@ void udf_init() mysql_rwlock_init(key_rwlock_THR_LOCK_udf, &THR_LOCK_udf); init_sql_alloc(&mem, UDF_ALLOC_BLOCK_SIZE, 0, MYF(0)); - THD *new_thd = new THD; + THD *new_thd = new THD(0); if (!new_thd || my_hash_init(&udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0)) { diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc index 2cfa3473222..520a16c467e 100644 --- a/sql/threadpool_common.cc +++ b/sql/threadpool_common.cc @@ -122,7 +122,7 @@ THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data) pthread_setspecific(THR_KEY_mysys, 0); my_thread_init(); st_my_thread_var* mysys_var= (st_my_thread_var *)pthread_getspecific(THR_KEY_mysys); - if (!mysys_var ||!(thd= connect->create_thd())) + if (!mysys_var ||!(thd= connect->create_thd(NULL))) { /* Out of memory? */ connect->close_and_delete(); @@ -200,6 +200,7 @@ void threadpool_remove_connection(THD *thd) end_connection(thd); close_connection(thd, 0); unlink_thd(thd); + delete thd; mysql_cond_broadcast(&COND_thread_count); /* diff --git a/sql/tztime.cc b/sql/tztime.cc index ce0272d996d..a9db91668bb 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1620,7 +1620,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap) /* To be able to run this from boot, we allocate a temporary THD */ - if (!(thd= new THD)) + if (!(thd= new THD(0))) DBUG_RETURN(1); thd->thread_stack= (char*) &thd; thd->store_globals(); diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc index 56f1018deac..e7d60652355 100644 --- a/sql/wsrep_utils.cc +++ b/sql/wsrep_utils.cc @@ -414,7 +414,7 @@ process::wait () return err_; } -thd::thd (my_bool won) : init(), ptr(new THD) +thd::thd (my_bool won) : init(), ptr(new THD(0)) { if (ptr) { diff --git a/storage/spider/spd_conn.cc b/storage/spider/spd_conn.cc index 681a3fb144c..551284e58b3 100644 --- a/storage/spider/spd_conn.cc +++ b/storage/spider/spd_conn.cc @@ -2259,7 +2259,7 @@ void *spider_bg_conn_action( my_thread_init(); DBUG_ENTER("spider_bg_conn_action"); /* init start */ - if (!(thd = new THD())) + if (!(thd = new THD(next_thread_id()))) { pthread_mutex_lock(&conn->bg_conn_sync_mutex); pthread_cond_signal(&conn->bg_conn_sync_cond); @@ -2267,7 +2267,6 @@ void *spider_bg_conn_action( my_thread_end(); DBUG_RETURN(NULL); } - thd->thread_id = next_thread_id(); #ifdef HAVE_PSI_INTERFACE mysql_thread_set_psi_id(thd->thread_id); #endif @@ -2766,7 +2765,7 @@ void *spider_bg_sts_action( } #endif pthread_mutex_lock(&share->sts_mutex); - if (!(thd = new THD())) + if (!(thd = new THD(next_thread_id()))) { share->bg_sts_thd_wait = FALSE; share->bg_sts_kill = FALSE; @@ -2778,7 +2777,6 @@ void *spider_bg_sts_action( #endif DBUG_RETURN(NULL); } - thd->thread_id = next_thread_id(); #ifdef HAVE_PSI_INTERFACE mysql_thread_set_psi_id(thd->thread_id); #endif @@ -3146,7 +3144,7 @@ void *spider_bg_crd_action( } #endif pthread_mutex_lock(&share->crd_mutex); - if (!(thd = new THD())) + if (!(thd = new THD(next_thread_id()))) { share->bg_crd_thd_wait = FALSE; share->bg_crd_kill = FALSE; @@ -3158,7 +3156,6 @@ void *spider_bg_crd_action( #endif DBUG_RETURN(NULL); } - thd->thread_id = next_thread_id(); #ifdef HAVE_PSI_INTERFACE mysql_thread_set_psi_id(thd->thread_id); #endif @@ -3636,7 +3633,7 @@ void *spider_bg_mon_action( DBUG_ENTER("spider_bg_mon_action"); /* init start */ pthread_mutex_lock(&share->bg_mon_mutexes[link_idx]); - if (!(thd = new THD())) + if (!(thd = new THD(next_thread_id()))) { share->bg_mon_kill = FALSE; share->bg_mon_init = FALSE; @@ -3645,7 +3642,6 @@ void *spider_bg_mon_action( my_thread_end(); DBUG_RETURN(NULL); } - thd->thread_id = next_thread_id(); #ifdef HAVE_PSI_INTERFACE mysql_thread_set_psi_id(thd->thread_id); #endif diff --git a/storage/spider/spd_trx.cc b/storage/spider/spd_trx.cc index b376265c1e7..81ded109d54 100644 --- a/storage/spider/spd_trx.cc +++ b/storage/spider/spd_trx.cc @@ -4055,7 +4055,7 @@ THD *spider_create_tmp_thd() { THD *thd; DBUG_ENTER("spider_create_tmp_thd"); - if (!(thd = new THD)) + if (!(thd = new THD(0))) DBUG_RETURN(NULL); #if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100000 thd->killed = NOT_KILLED; @@ -4066,7 +4066,6 @@ THD *spider_create_tmp_thd() thd->locked_tables = FALSE; #endif thd->proc_info = ""; - thd->thread_id = thd->variables.pseudo_thread_id = 0; thd->thread_stack = (char*) &thd; if (thd->store_globals()) DBUG_RETURN(NULL); |