summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/violite.h2
-rw-r--r--mysql-test/suite/perfschema/r/all_instances.result1
-rw-r--r--mysql-test/suite/perfschema/r/func_mutex.result44
-rw-r--r--mysql-test/suite/perfschema/t/func_mutex.test18
-rw-r--r--mysys/my_gethwaddr.c10
-rw-r--r--mysys/my_rnd.c15
-rw-r--r--sql/event_scheduler.cc26
-rw-r--r--sql/mysqld.cc216
-rw-r--r--sql/mysqld.h47
-rw-r--r--sql/sql_acl.cc37
-rw-r--r--sql/sql_class.cc41
-rw-r--r--sql/sql_class.h5
-rw-r--r--sql/sql_insert.cc8
-rw-r--r--sql/sql_parse.cc20
-rw-r--r--vio/vio.c8
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);
}