diff options
-rw-r--r-- | include/violite.h | 2 | ||||
-rw-r--r-- | mysql-test/suite/perfschema/r/all_instances.result | 1 | ||||
-rw-r--r-- | mysql-test/suite/perfschema/r/func_mutex.result | 44 | ||||
-rw-r--r-- | mysql-test/suite/perfschema/t/func_mutex.test | 18 | ||||
-rw-r--r-- | mysys/my_gethwaddr.c | 10 | ||||
-rw-r--r-- | mysys/my_rnd.c | 15 | ||||
-rw-r--r-- | sql/event_scheduler.cc | 26 | ||||
-rw-r--r-- | sql/mysqld.cc | 216 | ||||
-rw-r--r-- | sql/mysqld.h | 47 | ||||
-rw-r--r-- | sql/sql_acl.cc | 37 | ||||
-rw-r--r-- | sql/sql_class.cc | 41 | ||||
-rw-r--r-- | sql/sql_class.h | 5 | ||||
-rw-r--r-- | sql/sql_insert.cc | 8 | ||||
-rw-r--r-- | sql/sql_parse.cc | 20 | ||||
-rw-r--r-- | vio/vio.c | 8 |
15 files changed, 253 insertions, 245 deletions
diff --git a/include/violite.h b/include/violite.h index 14c99e8d8fe..3a284a9e00d 100644 --- a/include/violite.h +++ b/include/violite.h @@ -216,7 +216,7 @@ struct st_vio struct sockaddr_storage remote; /* Remote internet address */ int addrLen; /* Length of remote address */ enum enum_vio_type type; /* Type of connection */ - char desc[30]; /* String description */ + const char *desc; /* String description */ char *read_buffer; /* buffer for vio_read_buff */ char *read_pos; /* start of unfetched data in the read buffer */ diff --git a/mysql-test/suite/perfschema/r/all_instances.result b/mysql-test/suite/perfschema/r/all_instances.result index d59f17847e2..616ff646c5c 100644 --- a/mysql-test/suite/perfschema/r/all_instances.result +++ b/mysql-test/suite/perfschema/r/all_instances.result @@ -64,6 +64,7 @@ wait/synch/mutex/sql/LOCK_server_started wait/synch/mutex/sql/LOCK_slave_list wait/synch/mutex/sql/LOCK_stats wait/synch/mutex/sql/LOCK_status +wait/synch/mutex/sql/LOCK_thread_cache wait/synch/mutex/sql/LOCK_thread_count wait/synch/mutex/sql/LOCK_user_conn wait/synch/mutex/sql/LOCK_user_locks diff --git a/mysql-test/suite/perfschema/r/func_mutex.result b/mysql-test/suite/perfschema/r/func_mutex.result index 2cb1d3da80d..0e948897f9d 100644 --- a/mysql-test/suite/perfschema/r/func_mutex.result +++ b/mysql-test/suite/perfschema/r/func_mutex.result @@ -70,52 +70,34 @@ Success TRUNCATE TABLE performance_schema.events_waits_history_long; TRUNCATE TABLE performance_schema.events_waits_history; TRUNCATE TABLE performance_schema.events_waits_current; -SELECT * FROM t1 WHERE id = 1; -id b -1 initial value +show variables like "%not_found%"; +Variable_name Value SET @before_count = (SELECT SUM(TIMER_WAIT) FROM performance_schema.events_waits_history_long -WHERE (EVENT_NAME = 'wait/synch/rwlock/sql/LOCK_grant')); -SELECT * FROM t1; -id b -1 initial value -2 initial value -3 initial value -4 initial value -5 initial value -6 initial value -7 initial value -8 initial value +WHERE (EVENT_NAME = 'wait/synch/rwlock/sql/LOCK_system_variables_hash')); +show variables like "%not_found%"; +Variable_name Value SET @after_count = (SELECT SUM(TIMER_WAIT) FROM performance_schema.events_waits_history_long -WHERE (EVENT_NAME = 'wait/synch/rwlock/sql/LOCK_grant')); +WHERE (EVENT_NAME = 'wait/synch/rwlock/sql/LOCK_system_variables_hash')); SELECT IF((@after_count - @before_count) > 0, 'Success', 'Failure') test_fm1_rw_timed; test_fm1_rw_timed Success UPDATE performance_schema.setup_instruments SET enabled = 'NO' -WHERE NAME = 'wait/synch/rwlock/sql/LOCK_grant'; +WHERE NAME = 'wait/synch/rwlock/sql/LOCK_system_variables_hash'; TRUNCATE TABLE performance_schema.events_waits_history_long; TRUNCATE TABLE performance_schema.events_waits_history; TRUNCATE TABLE performance_schema.events_waits_current; -SELECT * FROM t1 WHERE id = 1; -id b -1 initial value +show variables like "%not_found%"; +Variable_name Value SET @before_count = (SELECT SUM(TIMER_WAIT) FROM performance_schema.events_waits_history_long -WHERE (EVENT_NAME = 'wait/synch/rwlock/sql/LOCK_grant')); -SELECT * FROM t1; -id b -1 initial value -2 initial value -3 initial value -4 initial value -5 initial value -6 initial value -7 initial value -8 initial value +WHERE (EVENT_NAME = 'wait/synch/rwlock/sql/LOCK_system_variables_hash')); +show variables like "%not_found%"; +Variable_name Value SET @after_count = (SELECT SUM(TIMER_WAIT) FROM performance_schema.events_waits_history_long -WHERE (EVENT_NAME = 'wait/synch/rwlock/sql/LOCK_grant')); +WHERE (EVENT_NAME = 'LOCK_system_variables_hash')); SELECT IF((COALESCE(@after_count, 0) - COALESCE(@before_count, 0)) = 0, 'Success', 'Failure') test_fm2_rw_timed; test_fm2_rw_timed Success diff --git a/mysql-test/suite/perfschema/t/func_mutex.test b/mysql-test/suite/perfschema/t/func_mutex.test index a96b497ffec..42f8c8d59ff 100644 --- a/mysql-test/suite/perfschema/t/func_mutex.test +++ b/mysql-test/suite/perfschema/t/func_mutex.test @@ -87,38 +87,38 @@ TRUNCATE TABLE performance_schema.events_waits_history_long; TRUNCATE TABLE performance_schema.events_waits_history; TRUNCATE TABLE performance_schema.events_waits_current; -SELECT * FROM t1 WHERE id = 1; +show variables like "%not_found%"; SET @before_count = (SELECT SUM(TIMER_WAIT) FROM performance_schema.events_waits_history_long - WHERE (EVENT_NAME = 'wait/synch/rwlock/sql/LOCK_grant')); + WHERE (EVENT_NAME = 'wait/synch/rwlock/sql/LOCK_system_variables_hash')); -SELECT * FROM t1; +show variables like "%not_found%"; SET @after_count = (SELECT SUM(TIMER_WAIT) FROM performance_schema.events_waits_history_long - WHERE (EVENT_NAME = 'wait/synch/rwlock/sql/LOCK_grant')); + WHERE (EVENT_NAME = 'wait/synch/rwlock/sql/LOCK_system_variables_hash')); SELECT IF((@after_count - @before_count) > 0, 'Success', 'Failure') test_fm1_rw_timed; UPDATE performance_schema.setup_instruments SET enabled = 'NO' -WHERE NAME = 'wait/synch/rwlock/sql/LOCK_grant'; +WHERE NAME = 'wait/synch/rwlock/sql/LOCK_system_variables_hash'; TRUNCATE TABLE performance_schema.events_waits_history_long; TRUNCATE TABLE performance_schema.events_waits_history; TRUNCATE TABLE performance_schema.events_waits_current; -SELECT * FROM t1 WHERE id = 1; +show variables like "%not_found%"; SET @before_count = (SELECT SUM(TIMER_WAIT) FROM performance_schema.events_waits_history_long - WHERE (EVENT_NAME = 'wait/synch/rwlock/sql/LOCK_grant')); + WHERE (EVENT_NAME = 'wait/synch/rwlock/sql/LOCK_system_variables_hash')); -SELECT * FROM t1; +show variables like "%not_found%"; SET @after_count = (SELECT SUM(TIMER_WAIT) FROM performance_schema.events_waits_history_long - WHERE (EVENT_NAME = 'wait/synch/rwlock/sql/LOCK_grant')); + WHERE (EVENT_NAME = 'LOCK_system_variables_hash')); SELECT IF((COALESCE(@after_count, 0) - COALESCE(@before_count, 0)) = 0, 'Success', 'Failure') test_fm2_rw_timed; diff --git a/mysys/my_gethwaddr.c b/mysys/my_gethwaddr.c index 74dae29f235..aa63138b48c 100644 --- a/mysys/my_gethwaddr.c +++ b/mysys/my_gethwaddr.c @@ -87,13 +87,17 @@ my_bool my_gethwaddr(uchar *to) int fd, res= 1; struct ifreq ifr[32]; struct ifconf ifc; + DBUG_ENTER("my_gethwaddr"); ifc.ifc_req= ifr; ifc.ifc_len= sizeof(ifr); fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) + { + DBUG_PRINT("error", ("socket() call failed with %d", errno)); goto err; + } if (ioctl(fd, SIOCGIFCONF, (char*)&ifc) >= 0) { @@ -106,8 +110,8 @@ my_bool my_gethwaddr(uchar *to) ETHER_ADDR_LEN); #else /* - A bug in OpenSolaris used to prevent non-root from getting a mac address: - {no url. Oracle killed the old OpenSolaris bug database} + A bug in OpenSolaris used to prevent non-root from getting a mac + address: {no url. Oracle killed the old OpenSolaris bug database} Thus, we'll use an alternative method and extract the address from the arp table. @@ -124,7 +128,7 @@ my_bool my_gethwaddr(uchar *to) close(fd); err: - return res; + DBUG_RETURN(res); } #elif defined(_WIN32) diff --git a/mysys/my_rnd.c b/mysys/my_rnd.c index 178bcd9c539..d043c8529ad 100644 --- a/mysys/my_rnd.c +++ b/mysys/my_rnd.c @@ -45,11 +45,20 @@ void my_rnd_init(struct my_rnd_struct *rand_st, ulong seed1, ulong seed2) RETURN VALUE generated pseudo random number + + NOTE: + This is codes so that it can be called by two threads at the same time + with minimum impact. + (As the number is supposed to be random, it doesn't matter much if + rand->seed1 or rand->seed2 are updated with slightly wrong numbers or + if two threads gets the same number. */ double my_rnd(struct my_rnd_struct *rand_st) { - rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value; - rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value; - return (((double) rand_st->seed1)/rand_st->max_value_dbl); + unsigned long seed1; + seed1= (rand_st->seed1*3+rand_st->seed2) % rand_st->max_value; + rand_st->seed2=(seed1+rand_st->seed2+33) % rand_st->max_value; + rand_st->seed1= seed1; + return (((double) seed1)/rand_st->max_value_dbl); } diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 8c3e57778ab..4a4ae5a732f 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -132,11 +132,11 @@ post_init_event_thread(THD *thd) return TRUE; } + thread_safe_increment32(&thread_count, &thread_count_lock); mysql_mutex_lock(&LOCK_thread_count); threads.append(thd); - thread_count++; - inc_thread_running(); mysql_mutex_unlock(&LOCK_thread_count); + inc_thread_running(); return FALSE; } @@ -154,12 +154,8 @@ deinit_event_thread(THD *thd) { thd->proc_info= "Clearing"; DBUG_PRINT("exit", ("Event thread finishing")); - mysql_mutex_lock(&LOCK_thread_count); - thread_count--; - dec_thread_running(); - delete thd; - mysql_cond_broadcast(&COND_thread_count); - mysql_mutex_unlock(&LOCK_thread_count); + + delete_running_thd(thd); } @@ -436,12 +432,7 @@ Event_scheduler::start() ret= TRUE; new_thd->proc_info= "Clearing"; - mysql_mutex_lock(&LOCK_thread_count); - thread_count--; - dec_thread_running(); - delete new_thd; - mysql_cond_broadcast(&COND_thread_count); - mysql_mutex_unlock(&LOCK_thread_count); + delete_running_thd(new_thd); } end: UNLOCK_DATA(); @@ -570,12 +561,7 @@ error: if (new_thd) { new_thd->proc_info= "Clearing"; - mysql_mutex_lock(&LOCK_thread_count); - thread_count--; - dec_thread_running(); - delete new_thd; - mysql_cond_broadcast(&COND_thread_count); - mysql_mutex_unlock(&LOCK_thread_count); + delete_running_thd(new_thd); } delete event_name; DBUG_RETURN(TRUE); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c662b3279ef..fb954908ac9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -465,7 +465,7 @@ ulong delay_key_write_options; uint protocol_version; uint lower_case_table_names; ulong tc_heuristic_recover= 0; -uint volatile thread_count; +int32 thread_count; int32 thread_running; ulong thread_created; ulong back_log, connect_timeout, concurrency, server_id; @@ -489,6 +489,7 @@ ulong executed_events=0; query_id_t global_query_id; my_atomic_rwlock_t global_query_id_lock; my_atomic_rwlock_t thread_running_lock; +my_atomic_rwlock_t thread_count_lock; my_atomic_rwlock_t statistics_lock; ulong aborted_threads, aborted_connects; ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size; @@ -663,7 +664,7 @@ SHOW_COMP_OPTION have_openssl; pthread_key(MEM_ROOT**,THR_MALLOC); pthread_key(THD*, THR_THD); -mysql_mutex_t LOCK_thread_count; +mysql_mutex_t LOCK_thread_count, LOCK_thread_cache; mysql_mutex_t LOCK_status, LOCK_error_log, LOCK_short_uuid_generator, LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, @@ -761,7 +762,8 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list, key_relay_log_info_log_space_lock, key_relay_log_info_run_lock, key_relay_log_info_sleep_lock, key_structure_guard_mutex, key_TABLE_SHARE_LOCK_ha_data, - key_LOCK_error_messages, key_LOG_INFO_lock, key_LOCK_thread_count, + key_LOCK_error_messages, key_LOG_INFO_lock, + key_LOCK_thread_count, key_LOCK_thread_cache, key_PARTITION_LOCK_auto_inc; PSI_mutex_key key_RELAYLOG_LOCK_index; @@ -832,6 +834,7 @@ static PSI_mutex_info all_server_mutexes[]= { &key_LOCK_commit_ordered, "LOCK_commit_ordered", PSI_FLAG_GLOBAL}, { &key_LOG_INFO_lock, "LOG_INFO::lock", 0}, { &key_LOCK_thread_count, "LOCK_thread_count", PSI_FLAG_GLOBAL}, + { &key_LOCK_thread_cache, "LOCK_thread_cache", PSI_FLAG_GLOBAL}, { &key_PARTITION_LOCK_auto_inc, "HA_DATA_PARTITION::LOCK_auto_inc", 0} }; @@ -1472,7 +1475,7 @@ static void close_connections(void) end_slave(); /* Give threads time to die. */ - for (int i= 0; thread_count && i < 100; i++) + for (int i= 0; *(volatile int32*) &thread_count && i < 100; i++) my_sleep(20000); /* @@ -1886,6 +1889,7 @@ void clean_up(bool print_message) sys_var_end(); my_atomic_rwlock_destroy(&global_query_id_lock); my_atomic_rwlock_destroy(&thread_running_lock); + my_atomic_rwlock_destroy(&thread_count_lock); my_atomic_rwlock_destroy(&statistics_lock); mysql_mutex_lock(&LOCK_thread_count); DBUG_PRINT("quit", ("got thread count lock")); @@ -1929,6 +1933,7 @@ static void clean_up_mutexes() DBUG_ENTER("clean_up_mutexes"); mysql_rwlock_destroy(&LOCK_grant); mysql_mutex_destroy(&LOCK_thread_count); + mysql_mutex_destroy(&LOCK_thread_cache); mysql_mutex_destroy(&LOCK_status); mysql_mutex_destroy(&LOCK_delayed_insert); mysql_mutex_destroy(&LOCK_delayed_status); @@ -2456,6 +2461,28 @@ void dec_connection_count(THD *thd) /* + Delete THD and decrement thread counters, including thread_running +*/ + +void delete_running_thd(THD *thd) +{ + mysql_mutex_lock(&LOCK_thread_count); + thd->unlink(); + mysql_mutex_unlock(&LOCK_thread_count); + + delete thd; + dec_thread_running(); + thread_safe_decrement32(&thread_count, &thread_count_lock); + if (!thread_count) + { + mysql_mutex_lock(&LOCK_thread_count); + mysql_cond_broadcast(&COND_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); + } +} + + +/* Unlink thd from global list of available connections and free thd SYNOPSIS @@ -2479,7 +2506,6 @@ void unlink_thd(THD *thd) mysql_mutex_unlock(&LOCK_status); mysql_mutex_lock(&LOCK_thread_count); - thread_count--; thd->unlink(); /* Used by binlog_reset_master. It would be cleaner to use @@ -2487,13 +2513,11 @@ void unlink_thd(THD *thd) sync feature has been shut down at this point. */ DBUG_EXECUTE_IF("sleep_after_lock_thread_count_before_delete_thd", sleep(5);); - /* - We must delete thd inside the lock to ensure that we don't start cleanup - before THD is deleted - */ - delete thd; mysql_mutex_unlock(&LOCK_thread_count); + delete thd; + thread_safe_decrement32(&thread_count, &thread_count_lock); + DBUG_VOID_RETURN; } @@ -2505,7 +2529,7 @@ void unlink_thd(THD *thd) cache_thread() NOTES - LOCK_thread_count has to be locked + LOCK_thread_cache is used to protect the cache variables RETURN 0 Thread was not put in cache @@ -2516,7 +2540,9 @@ void unlink_thd(THD *thd) static bool cache_thread() { - mysql_mutex_assert_owner(&LOCK_thread_count); + DBUG_ENTER("cache_thread"); + + mysql_mutex_lock(&LOCK_thread_cache); if (cached_thread_count < thread_cache_size && ! abort_loop && !kill_cached_threads) { @@ -2534,7 +2560,7 @@ static bool cache_thread() #endif while (!abort_loop && ! wake_thread && ! kill_cached_threads) - mysql_cond_wait(&COND_thread_cache, &LOCK_thread_count); + mysql_cond_wait(&COND_thread_cache, &LOCK_thread_cache); cached_thread_count--; if (kill_cached_threads) mysql_cond_signal(&COND_flush_thread_cache); @@ -2543,6 +2569,8 @@ static bool cache_thread() THD *thd; wake_thread--; thd= thread_cache.get(); + mysql_mutex_unlock(&LOCK_thread_cache); + thd->thread_stack= (char*) &thd; // For store_globals (void) thd->store_globals(); @@ -2568,11 +2596,16 @@ static bool cache_thread() thd->mysys_var->abort= 0; thd->thr_create_utime= microsecond_interval_timer(); thd->start_utime= thd->thr_create_utime; + + /* Link thd into list of all active threads (THD's) */ + mysql_mutex_lock(&LOCK_thread_count); threads.append(thd); - return(1); + mysql_mutex_unlock(&LOCK_thread_count); + DBUG_RETURN(1); } } - return(0); + mysql_mutex_unlock(&LOCK_thread_cache); + DBUG_RETURN(0); } @@ -2603,17 +2636,23 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache) set_current_thd(0); if (put_in_cache) { - mysql_mutex_lock(&LOCK_thread_count); - put_in_cache= cache_thread(); - mysql_mutex_unlock(&LOCK_thread_count); - if (put_in_cache) + if (cache_thread()) DBUG_RETURN(0); // Thread is reused } - /* It's safe to broadcast outside a lock (COND... is not deleted here) */ - DBUG_PRINT("signal", ("Broadcasting COND_thread_count")); - mysql_cond_broadcast(&COND_thread_count); - + /* + It's safe to check for thread_count outside of the mutex + as we are only interested to see if it was counted to 0 by the + above unlink_thd() call. We should only signal COND_thread_count if + thread_count is likely to be 0. (false positives are ok) + */ + if (!thread_count) + { + mysql_mutex_lock(&LOCK_thread_count); + DBUG_PRINT("signal", ("Broadcasting COND_thread_count")); + mysql_cond_broadcast(&COND_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); + } DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); @@ -2624,15 +2663,17 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache) void flush_thread_cache() { - mysql_mutex_lock(&LOCK_thread_count); + DBUG_ENTER("flush_thread_cache"); + mysql_mutex_lock(&LOCK_thread_cache); kill_cached_threads++; while (cached_thread_count) { mysql_cond_broadcast(&COND_thread_cache); - mysql_cond_wait(&COND_flush_thread_cache, &LOCK_thread_count); + mysql_cond_wait(&COND_flush_thread_cache, &LOCK_thread_cache); } kill_cached_threads--; - mysql_mutex_unlock(&LOCK_thread_count); + mysql_mutex_unlock(&LOCK_thread_cache); + DBUG_VOID_RETURN; } @@ -3973,6 +4014,7 @@ static int init_thread_environment() { DBUG_ENTER("init_thread_environment"); mysql_mutex_init(key_LOCK_thread_count, &LOCK_thread_count, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_LOCK_thread_cache, &LOCK_thread_cache, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_status, &LOCK_status, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_delayed_insert, &LOCK_delayed_insert, MY_MUTEX_INIT_FAST); @@ -5363,7 +5405,7 @@ static void bootstrap(MYSQL_FILE *file) thd->max_client_packet_length= thd->net.max_packet; thd->security_ctx->master_access= ~(ulong)0; thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; - thread_count++; + thread_count++; // Safe as only one thread running in_bootstrap= TRUE; bootstrap_file=file; @@ -5444,54 +5486,69 @@ void handle_connection_in_main_thread(THD *thd) void create_thread_to_handle_connection(THD *thd) { + DBUG_ENTER("create_thread_to_handle_connection"); + mysql_mutex_assert_owner(&LOCK_thread_count); + + /* Check if we can get thread from the cache */ if (cached_thread_count > wake_thread) { - /* Get thread from cache */ - thread_cache.push_back(thd); - wake_thread++; - mysql_cond_signal(&COND_thread_cache); - } - else - { - char error_message_buff[MYSQL_ERRMSG_SIZE]; - /* Create new thread to handle connection */ - int error; - thread_created++; - threads.append(thd); - DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id)); - thd->prior_thr_create_utime= microsecond_interval_timer(); - if ((error= mysql_thread_create(key_thread_one_connection, - &thd->real_id, &connection_attrib, - handle_one_connection, - (void*) thd))) + mysql_mutex_lock(&LOCK_thread_cache); + /* Recheck condition when we have the lock */ + if (cached_thread_count > wake_thread) { - /* purecov: begin inspected */ - DBUG_PRINT("error", - ("Can't create thread to handle request (error %d)", - error)); - thread_count--; - thd->killed= KILL_CONNECTION; // Safety mysql_mutex_unlock(&LOCK_thread_count); + /* Get thread from cache */ + thread_cache.push_back(thd); + wake_thread++; + mysql_cond_signal(&COND_thread_cache); + mysql_mutex_unlock(&LOCK_thread_cache); + DBUG_PRINT("info",("Thread created")); + DBUG_VOID_RETURN; + } + mysql_mutex_unlock(&LOCK_thread_cache); + } - mysql_mutex_lock(&LOCK_connection_count); - (*thd->scheduler->connection_count)--; - mysql_mutex_unlock(&LOCK_connection_count); + char error_message_buff[MYSQL_ERRMSG_SIZE]; + /* Create new thread to handle connection */ + int error; + thread_created++; + threads.append(thd); + DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id)); + thd->prior_thr_create_utime= microsecond_interval_timer(); + if ((error= mysql_thread_create(key_thread_one_connection, + &thd->real_id, &connection_attrib, + handle_one_connection, + (void*) thd))) + { + /* purecov: begin inspected */ + DBUG_PRINT("error", + ("Can't create thread to handle request (error %d)", + error)); + thd->killed= KILL_CONNECTION; // Safety + mysql_mutex_unlock(&LOCK_thread_count); - statistic_increment(aborted_connects,&LOCK_status); - /* Can't use my_error() since store_globals has not been called. */ - 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); - close_connection(thd, ER_OUT_OF_RESOURCES); - mysql_mutex_lock(&LOCK_thread_count); - delete thd; - mysql_mutex_unlock(&LOCK_thread_count); - return; - /* purecov: end */ - } + mysql_mutex_lock(&LOCK_connection_count); + (*thd->scheduler->connection_count)--; + mysql_mutex_unlock(&LOCK_connection_count); + + statistic_increment(aborted_connects,&LOCK_status); + /* Can't use my_error() since store_globals has not been called. */ + 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); + close_connection(thd, ER_OUT_OF_RESOURCES); + + mysql_mutex_lock(&LOCK_thread_count); + thd->unlink(); + mysql_mutex_unlock(&LOCK_thread_count); + delete thd; + thread_safe_decrement32(&thread_count, &thread_count_lock); + return; + /* purecov: end */ } mysql_mutex_unlock(&LOCK_thread_count); DBUG_PRINT("info",("Thread created")); + DBUG_VOID_RETURN; } @@ -5538,10 +5595,10 @@ static void create_new_thread(THD *thd) mysql_mutex_unlock(&LOCK_connection_count); - /* Start a new thread to handle connection. */ + thread_safe_increment32(&thread_count, &thread_count_lock); + /* Start a new thread to handle connection. */ mysql_mutex_lock(&LOCK_thread_count); - /* The initialization of thread_id is done in create_embedded_thd() for the embedded library. @@ -5549,8 +5606,6 @@ static void create_new_thread(THD *thd) */ thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; - thread_count++; - MYSQL_CALLBACK(thd->scheduler, add_connection, (thd)); DBUG_VOID_RETURN; @@ -5758,20 +5813,6 @@ void handle_connections_sockets() } #endif /* HAVE_LIBWRAP */ - { - size_socket dummyLen; - struct sockaddr_storage dummy; - dummyLen = sizeof(dummy); - if ( getsockname(new_sock,(struct sockaddr *)&dummy, - (SOCKET_SIZE_TYPE *)&dummyLen) < 0 ) - { - sql_perror("Error on new connection socket"); - (void) mysql_socket_shutdown(new_sock, SHUT_RDWR); - (void) closesocket(new_sock); - continue; - } - } - /* ** Don't allow too many connections */ @@ -7402,6 +7443,7 @@ static int mysql_init_variables(void) global_query_id= thread_id= 1L; my_atomic_rwlock_init(&global_query_id_lock); my_atomic_rwlock_init(&thread_running_lock); + my_atomic_rwlock_init(&thread_count_lock); my_atomic_rwlock_init(&statistics_lock); strmov(server_version, MYSQL_SERVER_VERSION); threads.empty(); @@ -8461,12 +8503,8 @@ void refresh_status(THD *thd) /* Set max_used_connections to the number of currently open - connections. Lock LOCK_thread_count out of LOCK_status to avoid - deadlocks. Status reset becomes not atomic, but status data is - not exact anyway. + connections. This is not perfect, but status data is not exact anyway. */ - mysql_mutex_lock(&LOCK_thread_count); max_used_connections= thread_count-delayed_insert_threads; - mysql_mutex_unlock(&LOCK_thread_count); } diff --git a/sql/mysqld.h b/sql/mysqld.h index 6bde25f08fb..587673de37c 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -56,6 +56,7 @@ void kill_mysql(void); void close_connection(THD *thd, uint sql_errno= 0); void handle_connection_in_main_thread(THD *thd); void create_thread_to_handle_connection(THD *thd); +void delete_running_thd(THD *thd); void unlink_thd(THD *thd); bool one_thread_per_connection_end(THD *thd, bool put_in_cache); void flush_thread_cache(); @@ -89,7 +90,6 @@ extern bool opt_ignore_builtin_innodb; extern my_bool opt_character_set_client_handshake; extern bool volatile abort_loop; extern bool in_bootstrap; -extern uint volatile thread_count; extern uint connection_count; extern my_bool opt_safe_user_create; extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap; @@ -352,7 +352,8 @@ extern mysql_rwlock_t LOCK_system_variables_hash; extern mysql_cond_t COND_thread_count; extern mysql_cond_t COND_manager; extern int32 thread_running; -extern my_atomic_rwlock_t thread_running_lock; +extern int32 thread_count; +extern my_atomic_rwlock_t thread_running_lock, thread_count_lock; extern char *opt_ssl_ca, *opt_ssl_capath, *opt_ssl_cert, *opt_ssl_cipher, *opt_ssl_key; @@ -449,7 +450,7 @@ inline query_id_t next_query_id() my_atomic_rwlock_wrlock(&global_query_id_lock); id= my_atomic_add64(&global_query_id, 1); my_atomic_rwlock_wrunlock(&global_query_id_lock); - return (id+1); + return (id); } inline query_id_t get_query_id() @@ -479,42 +480,30 @@ inline void table_case_convert(char * name, uint length) name, length, name, length); } -inline ulong sql_rnd_with_mutex() +inline void thread_safe_increment32(int32 *value, my_atomic_rwlock_t *lock) { - mysql_mutex_lock(&LOCK_thread_count); - ulong tmp=(ulong) (my_rnd(&sql_rand) * 0xffffffff); /* make all bits random */ - mysql_mutex_unlock(&LOCK_thread_count); - return tmp; + my_atomic_rwlock_wrlock(lock); + (void) my_atomic_add32(value, 1); + my_atomic_rwlock_wrunlock(lock); } -inline int32 -inc_thread_running() +inline void thread_safe_decrement32(int32 *value, my_atomic_rwlock_t *lock) { - int32 num_thread_running; - my_atomic_rwlock_wrlock(&thread_running_lock); - num_thread_running= my_atomic_add32(&thread_running, 1); - my_atomic_rwlock_wrunlock(&thread_running_lock); - return (num_thread_running+1); + my_atomic_rwlock_wrlock(lock); + (void) my_atomic_add32(value, -1); + my_atomic_rwlock_wrunlock(lock); } -inline int32 -dec_thread_running() +inline void +inc_thread_running() { - int32 num_thread_running; - my_atomic_rwlock_wrlock(&thread_running_lock); - num_thread_running= my_atomic_add32(&thread_running, -1); - my_atomic_rwlock_wrunlock(&thread_running_lock); - return (num_thread_running-1); + thread_safe_increment32(&thread_running, &thread_running_lock); } -inline int32 -get_thread_running() +inline void +dec_thread_running() { - int32 num_thread_running; - my_atomic_rwlock_wrlock(&thread_running_lock); - num_thread_running= my_atomic_load32(&thread_running); - my_atomic_rwlock_wrunlock(&thread_running_lock); - return num_thread_running; + thread_safe_decrement32(&thread_running, &thread_running_lock); } void set_server_version(void); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 2f854251ce5..25b54abf983 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -4530,12 +4530,16 @@ end: @see check_access @see check_table_access - @note This functions assumes that either number of tables to be inspected + @note + This functions assumes that either number of tables to be inspected by it is limited explicitly (i.e. is is not UINT_MAX) or table list used and thd->lex->query_tables_own_last value correspond to each other (the latter should be either 0 or point to next_global member of one of elements of this table list). + We delay locking of LOCK_grant until we really need it as we assume that + most privileges be resolved with user or db level accesses. + @return Access status @retval FALSE Access granted; But column privileges might need to be checked. @@ -4552,6 +4556,8 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, Security_context *sctx= thd->security_ctx; uint i; ulong orig_want_access= want_access; + my_bool locked= 0; + GRANT_TABLE *grant_table; DBUG_ENTER("check_grant"); DBUG_ASSERT(number > 0); @@ -4575,11 +4581,9 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, */ tl->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL); } + number= i; - mysql_rwlock_rdlock(&LOCK_grant); - for (tl= tables; - tl && number-- && tl != first_not_own_table; - tl= tl->next_global) + for (tl= tables; number-- ; tl= tl->next_global) { sctx = test(tl->security_ctx) ? tl->security_ctx : thd->security_ctx; @@ -4632,13 +4636,18 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, } continue; } - GRANT_TABLE *grant_table= table_hash_search(sctx->host, sctx->ip, - tl->get_db_name(), - sctx->priv_user, - tl->get_table_name(), - FALSE); - if (!grant_table) + if (!locked) + { + locked= 1; + mysql_rwlock_rdlock(&LOCK_grant); + } + + if (!(grant_table= table_hash_search(sctx->host, sctx->ip, + tl->get_db_name(), + sctx->priv_user, + tl->get_table_name(), + FALSE))) { want_access &= ~tl->grant.privilege; goto err; // No grants @@ -4665,11 +4674,13 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, goto err; // impossible } } - mysql_rwlock_unlock(&LOCK_grant); + if (locked) + mysql_rwlock_unlock(&LOCK_grant); DBUG_RETURN(FALSE); err: - mysql_rwlock_unlock(&LOCK_grant); + if (locked) + mysql_rwlock_unlock(&LOCK_grant); if (!no_errors) // Not a silent skip of table { char command[128]; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 155c6365e76..9fd3827ab39 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -350,29 +350,6 @@ void thd_set_thread_stack(THD *thd, char *stack_start) } /** - Lock connection data for the set of connections this connection - belongs to - - @param thd THD object -*/ -void thd_lock_thread_count(THD *) -{ - mysql_mutex_lock(&LOCK_thread_count); -} - -/** - Lock connection data for the set of connections this connection - belongs to - - @param thd THD object -*/ -void thd_unlock_thread_count(THD *) -{ - mysql_cond_broadcast(&COND_thread_count); - mysql_mutex_unlock(&LOCK_thread_count); -} - -/** Close the socket used by this connection @param thd THD object @@ -947,7 +924,14 @@ THD::THD() protocol_binary.init(this); tablespace_op=FALSE; - tmp= sql_rnd_with_mutex(); + + /* + Initialize the random generator. We call my_rnd() without a lock as + it's not really critical if two threads modifies the structure at the + same time. We ensure that we have an unique number foreach thread + by adding the address of the stack. + */ + 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 */ @@ -4342,17 +4326,8 @@ void THD::set_query_and_id(char *query_arg, uint32 query_length_arg, { mysql_mutex_lock(&LOCK_thd_data); set_query_inner(query_arg, query_length_arg, cs); - query_id= new_query_id; mysql_mutex_unlock(&LOCK_thd_data); -} - -/** Assign a new value to thd->query_id. */ - -void THD::set_query_id(query_id_t new_query_id) -{ - mysql_mutex_lock(&LOCK_thd_data); query_id= new_query_id; - mysql_mutex_unlock(&LOCK_thd_data); } /** Assign a new value to thd->mysys_var. */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 87b9783c1ed..01558603f68 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3076,7 +3076,10 @@ public: { set_query(CSET_STRING()); } void set_query_and_id(char *query_arg, uint32 query_length_arg, CHARSET_INFO *cs, query_id_t new_query_id); - void set_query_id(query_id_t new_query_id); + void set_query_id(query_id_t new_query_id) + { + query_id= new_query_id; + } void set_open_tables(TABLE *open_tables_arg) { mysql_mutex_lock(&LOCK_thd_data); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 833e134bff9..efbf35fe575 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2038,9 +2038,9 @@ public: thd.unlink(); // Must be unlinked under lock my_free(thd.query()); thd.security_ctx->user= thd.security_ctx->host=0; - thread_count--; delayed_insert_threads--; mysql_mutex_unlock(&LOCK_thread_count); + thread_safe_decrement32(&thread_count, &thread_count_lock); mysql_cond_broadcast(&COND_thread_count); /* Tell main we are ready */ } @@ -2175,9 +2175,9 @@ bool delayed_get_table(THD *thd, MDL_request *grl_protection_request, { if (!(di= new Delayed_insert())) goto end_create; - mysql_mutex_lock(&LOCK_thread_count); - thread_count++; - mysql_mutex_unlock(&LOCK_thread_count); + + thread_safe_increment32(&thread_count, &thread_count_lock); + /* Annotating delayed inserts is not supported. */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0abb249d97b..bdf2bd17589 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -645,9 +645,10 @@ end: delete thd; #ifndef EMBEDDED_LIBRARY - mysql_mutex_lock(&LOCK_thread_count); - thread_count--; + thread_safe_decrement32(&thread_count, &thread_count_lock); in_bootstrap= FALSE; + + mysql_mutex_lock(&LOCK_thread_count); mysql_cond_broadcast(&COND_thread_count); mysql_mutex_unlock(&LOCK_thread_count); my_thread_end(); @@ -930,9 +931,16 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->query_plan_flags= QPLAN_INIT; thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ thd->set_time(); - thd->set_query_id(get_query_id()); if (!(server_command_flags[command] & CF_SKIP_QUERY_ID)) - next_query_id(); + thd->set_query_id(next_query_id()); + else + { + /* + ping, get statistics or similar stateless command. + No reason to increase query id here. + */ + thd->set_query_id(get_query_id()); + } inc_thread_running(); if (!(server_command_flags[command] & CF_SKIP_QUESTIONS)) @@ -5021,6 +5029,10 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, if ((db != NULL) && (db != any_db)) { + /* + Check if this is reserved database, like information schema or + performance schema + */ const ACL_internal_schema_access *access; access= get_cached_schema_access(grant_internal_info, db); if (access) diff --git a/vio/vio.c b/vio/vio.c index aed99e72d54..6e2ec3f674b 100644 --- a/vio/vio.c +++ b/vio/vio.c @@ -213,9 +213,7 @@ Vio *vio_new(my_socket sd, enum enum_vio_type type, uint flags) if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME)))) { vio_init(vio, type, sd, 0, flags); - sprintf(vio->desc, - (vio->type == VIO_TYPE_SOCKET ? "socket (%d)" : "TCP/IP (%d)"), - vio->sd); + vio->desc= (vio->type == VIO_TYPE_SOCKET ? "socket" : "TCP/IP"); #if !defined(__WIN__) #if !defined(NO_FCNTL_NONBLOCK) /* @@ -257,7 +255,7 @@ Vio *vio_new_win32pipe(HANDLE hPipe) if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME)))) { vio_init(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, VIO_LOCALHOST); - strmov(vio->desc, "named pipe"); + vio->desc= "named pipe"; } DBUG_RETURN(vio); } @@ -282,7 +280,7 @@ Vio *vio_new_win32shared_memory(HANDLE handle_file_map, HANDLE handle_map, vio->event_conn_closed= event_conn_closed; vio->shared_memory_remain= 0; vio->shared_memory_pos= handle_map; - strmov(vio->desc, "shared memory"); + vio->desc= "shared memory"; } DBUG_RETURN(vio); } |