diff options
Diffstat (limited to 'sql/mysqld.cc')
-rw-r--r-- | sql/mysqld.cc | 365 |
1 files changed, 101 insertions, 264 deletions
diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5b14b9f7790..1e22c5621e6 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -347,7 +347,6 @@ static my_bool opt_short_log_format= 0, opt_silent_startup= 0; bool my_disable_leak_check= false; uint kill_cached_threads; -static uint wake_thread; ulong max_used_connections; volatile ulong cached_thread_count= 0; static char *mysqld_user, *mysqld_chroot; @@ -704,7 +703,7 @@ mysql_mutex_t LOCK_crypt, LOCK_global_system_variables, LOCK_user_conn, - LOCK_connection_count, LOCK_error_messages, LOCK_slave_background; + LOCK_error_messages, LOCK_slave_background; mysql_mutex_t LOCK_stats, LOCK_global_user_client_stats, LOCK_global_table_stats, LOCK_global_index_stats; @@ -862,7 +861,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list, key_BINLOG_LOCK_binlog_background_thread, key_LOCK_binlog_end_pos, key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi, - key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create, + key_LOCK_crypt, key_LOCK_delayed_create, key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log, key_LOCK_gdl, key_LOCK_global_system_variables, key_LOCK_manager, @@ -927,7 +926,6 @@ static PSI_mutex_info all_server_mutexes[]= { &key_delayed_insert_mutex, "Delayed_insert::mutex", 0}, { &key_hash_filo_lock, "hash_filo::lock", 0}, { &key_LOCK_active_mi, "LOCK_active_mi", PSI_FLAG_GLOBAL}, - { &key_LOCK_connection_count, "LOCK_connection_count", PSI_FLAG_GLOBAL}, { &key_LOCK_thread_id, "LOCK_thread_id", PSI_FLAG_GLOBAL}, { &key_LOCK_crypt, "LOCK_crypt", PSI_FLAG_GLOBAL}, { &key_LOCK_delayed_create, "LOCK_delayed_create", PSI_FLAG_GLOBAL}, @@ -1472,10 +1470,10 @@ struct st_VioSSLFd *ssl_acceptor_fd; #endif /* HAVE_OPENSSL */ /** - Number of currently active user connections. The variable is protected by - LOCK_connection_count. + Number of currently active user connections. */ -uint connection_count= 0, extra_connection_count= 0; +Atomic_counter<uint> connection_count; +static Atomic_counter<uint> extra_connection_count; my_bool opt_gtid_strict_mode= FALSE; @@ -2104,7 +2102,6 @@ static void clean_up_mutexes() mysql_mutex_destroy(&LOCK_delayed_create); mysql_mutex_destroy(&LOCK_crypt); mysql_mutex_destroy(&LOCK_user_conn); - mysql_mutex_destroy(&LOCK_connection_count); mysql_mutex_destroy(&LOCK_thread_id); mysql_mutex_destroy(&LOCK_stats); mysql_mutex_destroy(&LOCK_global_user_client_stats); @@ -2596,20 +2593,6 @@ extern "C" sig_handler end_mysqld_signal(int sig __attribute__((unused))) } #endif /* EMBEDDED_LIBRARY */ -/* - Decrease number of connections - - SYNOPSIS - dec_connection_count() -*/ - -void dec_connection_count(scheduler_functions *scheduler) -{ - mysql_mutex_lock(&LOCK_connection_count); - (*scheduler->connection_count)--; - mysql_mutex_unlock(&LOCK_connection_count); -} - /* Unlink thd from global list of available connections @@ -2635,7 +2618,7 @@ void unlink_thd(THD *thd) */ if (!thd->wsrep_applier) #endif /* WITH_WSREP */ - dec_connection_count(thd->scheduler); + --*thd->scheduler->connection_count; thd->free_connection(); @@ -2660,134 +2643,57 @@ void unlink_thd(THD *thd) */ -static bool cache_thread(THD *thd) +CONNECT *cache_thread(THD *thd) { struct timespec abstime; + CONNECT *connect; + bool flushed= false; DBUG_ENTER("cache_thread"); DBUG_ASSERT(thd); + set_timespec(abstime, THREAD_CACHE_TIMEOUT); + + /* + Delete the instrumentation for the job that just completed, + before parking this pthread in the cache (blocked on COND_thread_cache). + */ + PSI_CALL_delete_current_thread(); + +#ifndef DBUG_OFF + while (_db_is_pushed_()) + _db_pop_(); +#endif mysql_mutex_lock(&LOCK_thread_cache); - if (cached_thread_count < thread_cache_size && - ! abort_loop && !kill_cached_threads) + if ((connect= thread_cache.get())) + cached_thread_count++; + else if (cached_thread_count < thread_cache_size && !kill_cached_threads) { /* Don't kill the thread, just put it in cache for reuse */ DBUG_PRINT("info", ("Adding thread to cache")); cached_thread_count++; - - /* - Delete the instrumentation for the job that just completed, - before parking this pthread in the cache (blocked on COND_thread_cache). - */ - PSI_CALL_delete_current_thread(); - -#ifndef DBUG_OFF - while (_db_is_pushed_()) - _db_pop_(); -#endif - - set_timespec(abstime, THREAD_CACHE_TIMEOUT); - while (!abort_loop && ! wake_thread && ! kill_cached_threads) + for (;;) { int error= mysql_cond_timedwait(&COND_thread_cache, &LOCK_thread_cache, &abstime); - if (error == ETIMEDOUT || error == ETIME) + flushed= kill_cached_threads; + if ((connect= thread_cache.get())) + break; + else if (flushed || error == ETIMEDOUT || error == ETIME) { /* If timeout, end thread. - If a new thread is requested (wake_thread is set), we will handle + If a new thread is requested, we will handle the call, even if we got a timeout (as we are already awake and free) */ + cached_thread_count--; break; } } - cached_thread_count--; - if (kill_cached_threads) - mysql_cond_signal(&COND_flush_thread_cache); - if (wake_thread) - { - CONNECT *connect; - - wake_thread--; - connect= thread_cache.get(); - mysql_mutex_unlock(&LOCK_thread_cache); - - if (!(connect->create_thd(thd))) - { - /* Out of resources. Free thread to get more resources */ - connect->close_and_delete(); - DBUG_RETURN(0); - } - delete connect; - - /* - We have to call store_globals to update mysys_var->id and lock_info - with the new thread_id - */ - thd->store_globals(); - - /* - Create new instrumentation for the new THD job, - and attach it to this running pthread. - */ - PSI_CALL_set_thread(PSI_CALL_new_thread(key_thread_one_connection, - thd, thd->thread_id)); - - /* 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; - - server_threads.insert(thd); - DBUG_RETURN(1); - } } mysql_mutex_unlock(&LOCK_thread_cache); - DBUG_RETURN(0); -} - - -/* - End thread for the current connection - - SYNOPSIS - one_thread_per_connection_end() - thd Thread handler. This may be null if we run out of resources. - put_in_cache Store thread in cache, if there is room in it - Normally this is true in all cases except when we got - out of resources initializing the current thread - - NOTES - If thread is cached, we will wait until thread is scheduled to be - reused and then we will return. - If thread is not cached, we end the thread. - - RETURN - 0 Signal to handle_one_connection to reuse connection -*/ - -bool one_thread_per_connection_end(THD *thd, bool put_in_cache) -{ - DBUG_ENTER("one_thread_per_connection_end"); - - if (thd) - { - const bool wsrep_applier= IF_WSREP(thd->wsrep_applier, false); - - 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() -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) - ERR_remove_state(0); -#endif - my_thread_end(); - - pthread_exit(0); - return 0; // Avoid compiler warnings + if (flushed) + mysql_cond_signal(&COND_flush_thread_cache); + DBUG_RETURN(connect); } @@ -3086,7 +2992,7 @@ void init_signals(void) sigemptyset(&sa.sa_mask); sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL); - my_init_stacktrace(); + my_init_stacktrace(0); #if defined(__amiga__) sa.sa_handler=(void(*)())handle_fatal_signal; #else @@ -4525,8 +4431,6 @@ static int init_thread_environment() &LOCK_error_messages, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_uuid_short_generator, &LOCK_short_uuid_generator, MY_MUTEX_INIT_FAST); - mysql_mutex_init(key_LOCK_connection_count, - &LOCK_connection_count, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_thread_id, &LOCK_thread_id, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_stats, &LOCK_stats, MY_MUTEX_INIT_FAST); @@ -6197,8 +6101,7 @@ void inc_thread_created(void) void handle_connection_in_main_thread(CONNECT *connect) { - thread_cache_size= 0; // Safety - do_handle_one_connection(connect); + do_handle_one_connection(connect, false); } @@ -6208,37 +6111,32 @@ void handle_connection_in_main_thread(CONNECT *connect) void create_thread_to_handle_connection(CONNECT *connect) { - char error_message_buff[MYSQL_ERRMSG_SIZE]; - int error; DBUG_ENTER("create_thread_to_handle_connection"); - /* Check if we can get thread from the cache */ - if (cached_thread_count > wake_thread) + mysql_mutex_lock(&LOCK_thread_cache); + if (cached_thread_count) { - mysql_mutex_lock(&LOCK_thread_cache); - /* Recheck condition when we have the lock */ - if (cached_thread_count > wake_thread) - { - /* Get thread from cache */ - thread_cache.push_back(connect); - wake_thread++; - mysql_cond_signal(&COND_thread_cache); - mysql_mutex_unlock(&LOCK_thread_cache); - DBUG_PRINT("info",("Thread created")); - DBUG_VOID_RETURN; - } + /* Get thread from cache */ + thread_cache.push_back(connect); + cached_thread_count--; mysql_mutex_unlock(&LOCK_thread_cache); + mysql_cond_signal(&COND_thread_cache); + DBUG_PRINT("info",("Thread created")); + DBUG_VOID_RETURN; } + mysql_mutex_unlock(&LOCK_thread_cache); /* Create new thread to handle connection */ inc_thread_created(); DBUG_PRINT("info",(("creating thread %lu"), (ulong) connect->thread_id)); connect->prior_thr_create_utime= microsecond_interval_timer(); - if ((error= mysql_thread_create(key_thread_one_connection, - &connect->real_id, &connection_attrib, - handle_one_connection, (void*) connect))) + pthread_t tmp; + if (auto error= mysql_thread_create(key_thread_one_connection, + &tmp, &connection_attrib, + handle_one_connection, (void*) connect)) { + char error_message_buff[MYSQL_ERRMSG_SIZE]; /* purecov: begin inspected */ DBUG_PRINT("error", ("Can't create thread to handle request (error %d)", error)); @@ -6275,29 +6173,17 @@ void create_new_thread(CONNECT *connect) Don't allow too many connections. We roughly check here that we allow only (max_connections + 1) connections. */ - - mysql_mutex_lock(&LOCK_connection_count); - - if (*connect->scheduler->connection_count >= - *connect->scheduler->max_connections + 1|| abort_loop) + if ((*connect->scheduler->connection_count)++ >= + *connect->scheduler->max_connections + 1) { DBUG_PRINT("error",("Too many connections")); - - mysql_mutex_unlock(&LOCK_connection_count); - statistic_increment(denied_connections, &LOCK_status); - statistic_increment(connection_errors_max_connection, &LOCK_status); - connect->close_with_error(0, NullS, abort_loop ? ER_SERVER_SHUTDOWN : ER_CON_COUNT_ERROR); + connect->close_with_error(0, NullS, ER_CON_COUNT_ERROR); DBUG_VOID_RETURN; } - ++*connect->scheduler->connection_count; - - if (connection_count + extra_connection_count > max_used_connections) - max_used_connections= connection_count + extra_connection_count; - - mysql_mutex_unlock(&LOCK_connection_count); - - connect->thread_count_incremented= 1; + uint sum= connection_count + extra_connection_count; + if (sum > max_used_connections) + max_used_connections= sum; /* The initialization of thread_id is done in create_embedded_thd() for @@ -6318,13 +6204,6 @@ void create_new_thread(CONNECT *connect) void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock) { - CONNECT *connect; - bool is_unix_sock; - -#ifdef FD_CLOEXEC - (void) fcntl(mysql_socket_getfd(new_sock), F_SETFD, FD_CLOEXEC); -#endif - #ifdef HAVE_LIBWRAP { if (mysql_socket_getfd(sock) == mysql_socket_getfd(base_ip_sock) || @@ -6370,53 +6249,46 @@ void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock) DBUG_PRINT("info", ("Creating CONNECT for new connection")); - if ((connect= new CONNECT())) - { - is_unix_sock= (mysql_socket_getfd(sock) == - mysql_socket_getfd(unix_sock)); - - if (!(connect->vio= - mysql_socket_vio_new(new_sock, - is_unix_sock ? VIO_TYPE_SOCKET : - VIO_TYPE_TCPIP, - is_unix_sock ? VIO_LOCALHOST : 0))) - { - delete connect; - connect= 0; // Error handling below - } - } - - if (!connect) + if (auto connect= new CONNECT(new_sock, + mysql_socket_getfd(sock) == + mysql_socket_getfd(unix_sock) ? + VIO_TYPE_SOCKET : VIO_TYPE_TCPIP, + mysql_socket_getfd(sock) == + mysql_socket_getfd(extra_ip_sock) ? + extra_thread_scheduler : thread_scheduler)) + create_new_thread(connect); + else { /* Connect failure */ (void)mysql_socket_close(new_sock); statistic_increment(aborted_connects, &LOCK_status); statistic_increment(connection_errors_internal, &LOCK_status); - return; } +} - if (is_unix_sock) - connect->host= my_localhost; - - if (mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock)) +#ifndef _WIN32 +static void set_non_blocking_if_supported(MYSQL_SOCKET sock) +{ +#if !defined(NO_FCNTL_NONBLOCK) + if (!(test_flags & TEST_BLOCKING)) { - connect->extra_port= 1; - connect->scheduler= extra_thread_scheduler; + int flags= fcntl(mysql_socket_getfd(sock), F_GETFL, 0); +#if defined(O_NONBLOCK) + fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NONBLOCK); +#elif defined(O_NDELAY) + fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NDELAY); +#endif } - create_new_thread(connect); +#endif } -#ifndef _WIN32 + void handle_connections_sockets() { MYSQL_SOCKET sock= mysql_socket_invalid(); - MYSQL_SOCKET new_sock= mysql_socket_invalid(); uint error_count=0; struct sockaddr_storage cAddr; - int ip_flags __attribute__((unused))=0; - int socket_flags __attribute__((unused))= 0; - int extra_ip_flags __attribute__((unused))=0; - int flags=0,retval; + int retval; #ifdef HAVE_POLL int socket_count= 0; struct pollfd fds[3]; // for ip_sock, unix_sock and extra_ip_sock @@ -6438,16 +6310,16 @@ void handle_connections_sockets() if (mysql_socket_getfd(base_ip_sock) != INVALID_SOCKET) { setup_fds(base_ip_sock); - ip_flags = fcntl(mysql_socket_getfd(base_ip_sock), F_GETFL, 0); + set_non_blocking_if_supported(base_ip_sock); } if (mysql_socket_getfd(extra_ip_sock) != INVALID_SOCKET) { setup_fds(extra_ip_sock); - extra_ip_flags = fcntl(mysql_socket_getfd(extra_ip_sock), F_GETFL, 0); + set_non_blocking_if_supported(extra_ip_sock); } #ifdef HAVE_SYS_UN_H setup_fds(unix_sock); - socket_flags=fcntl(mysql_socket_getfd(unix_sock), F_GETFL, 0); + set_non_blocking_if_supported(unix_sock); #endif sd_notify(0, "READY=1\n" @@ -6489,79 +6361,44 @@ void handle_connections_sockets() if (fds[i].revents & POLLIN) { sock= pfs_fds[i]; - flags= fcntl(mysql_socket_getfd(sock), F_GETFL, 0); break; } } #else // HAVE_POLL if (FD_ISSET(mysql_socket_getfd(base_ip_sock),&readFDs)) - { sock= base_ip_sock; - flags= ip_flags; - } else if (FD_ISSET(mysql_socket_getfd(extra_ip_sock),&readFDs)) - { sock= extra_ip_sock; - flags= extra_ip_flags; - } else - { sock = unix_sock; - flags= socket_flags; - } #endif // HAVE_POLL -#if !defined(NO_FCNTL_NONBLOCK) - if (!(test_flags & TEST_BLOCKING)) - { -#if defined(O_NONBLOCK) - fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NONBLOCK); -#elif defined(O_NDELAY) - fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NDELAY); -#endif - } -#endif /* NO_FCNTL_NONBLOCK */ for (uint retry=0; retry < MAX_ACCEPT_RETRY; retry++) { size_socket length= sizeof(struct sockaddr_storage); + MYSQL_SOCKET new_sock; + new_sock= mysql_socket_accept(key_socket_client_connection, sock, (struct sockaddr *)(&cAddr), &length); - if (mysql_socket_getfd(new_sock) != INVALID_SOCKET || - (socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN)) - break; -#if !defined(NO_FCNTL_NONBLOCK) - if (!(test_flags & TEST_BLOCKING)) + if (mysql_socket_getfd(new_sock) != INVALID_SOCKET) + handle_accepted_socket(new_sock, sock); + else if (socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN) { - if (retry == MAX_ACCEPT_RETRY - 1) - { - // Try without O_NONBLOCK - fcntl(mysql_socket_getfd(sock), F_SETFL, flags); - } + /* + accept(2) failed on the listening port. + There is not much details to report about the client, + increment the server global status variable. + */ + statistic_increment(connection_errors_accept, &LOCK_status); + if ((error_count++ & 255) == 0) // This can happen often + sql_perror("Error in accept"); + if (socket_errno == SOCKET_ENFILE || socket_errno == SOCKET_EMFILE) + sleep(1); // Give other threads some time + break; } -#endif } - - if (mysql_socket_getfd(new_sock) == INVALID_SOCKET) - { - /* - accept(2) failed on the listening port, after many retries. - There is not much details to report about the client, - increment the server global status variable. - */ - statistic_increment(connection_errors_accept, &LOCK_status); - if ((error_count++ & 255) == 0) // This can happen often - sql_perror("Error in accept"); - if (socket_errno == SOCKET_ENFILE || socket_errno == SOCKET_EMFILE) - sleep(1); // Give other threads some time - continue; - } -#if !defined(NO_FCNTL_NONBLOCK) - if (!(test_flags & TEST_BLOCKING)) - fcntl(mysql_socket_getfd(sock), F_SETFL, flags); -#endif - handle_accepted_socket(new_sock, sock); } sd_notify(0, "STOPPING=1\n" "STATUS=Shutdown in progress\n"); @@ -7607,7 +7444,7 @@ static int debug_status_func(THD *thd, SHOW_VAR *var, char *buff, #endif #ifdef HAVE_POOL_OF_THREADS -int show_threadpool_idle_threads(THD *thd, SHOW_VAR *var, char *buff, +static int show_threadpool_idle_threads(THD *thd, SHOW_VAR *var, char *buff, enum enum_var_type scope) { var->type= SHOW_INT; @@ -8029,7 +7866,7 @@ static int mysql_init_variables(void) mqh_used= 0; cleanup_done= 0; test_flags= select_errors= dropping_tables= ha_open_options=0; - thread_count= kill_cached_threads= wake_thread= 0; + thread_count= kill_cached_threads= 0; slave_open_temp_tables= 0; cached_thread_count= 0; opt_endinfo= using_udf_functions= 0; |