summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorVladislav Vaintroub <wlad@mariadb.com>2018-02-01 09:01:15 +0000
committerVladislav Vaintroub <wlad@mariadb.com>2018-02-01 09:01:15 +0000
commit313247db9c0bb884d4fa000035da4a0fd22d567b (patch)
tree7362aaa5670fa87c06cc9418a5b640795920013b /sql
parentb56f9fbe2f6a83f2fd2964c56de9097877354783 (diff)
downloadmariadb-git-313247db9c0bb884d4fa000035da4a0fd22d567b.tar.gz
MDEV-15089 Ensure that connection ID is in 32bit range
Diffstat (limited to 'sql')
-rw-r--r--sql/mysqld.cc109
-rw-r--r--sql/mysqld.h10
2 files changed, 106 insertions, 13 deletions
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 24021f327b8..cbe50b14deb 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -559,7 +559,7 @@ ulong max_prepared_stmt_count;
statements.
*/
ulong prepared_stmt_count=0;
-my_thread_id global_thread_id= 1;
+my_thread_id global_thread_id= 0;
ulong current_pid;
ulong slow_launch_threads = 0;
uint sync_binlog_period= 0, sync_relaylog_period= 0,
@@ -766,6 +766,9 @@ mysql_mutex_t LOCK_stats, LOCK_global_user_client_stats,
/* This protects against changes in master_info_index */
mysql_mutex_t LOCK_active_mi;
+/* This protects connection id.*/
+mysql_mutex_t LOCK_thread_id;
+
/**
The below lock protects access to two global server variables:
max_prepared_stmt_count and prepared_stmt_count. These variables
@@ -933,6 +936,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_LOCK_thread_count, key_LOCK_thread_cache,
key_PARTITION_LOCK_auto_inc;
PSI_mutex_key key_RELAYLOG_LOCK_index;
+PSI_mutex_key key_LOCK_thread_id;
PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state,
key_LOCK_rpl_thread, key_LOCK_rpl_thread_pool, key_LOCK_parallel_entry;
@@ -970,6 +974,7 @@ static PSI_mutex_info all_server_mutexes[]=
{ &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},
{ &key_LOCK_delayed_insert, "LOCK_delayed_insert", PSI_FLAG_GLOBAL},
@@ -2048,8 +2053,8 @@ pthread_handler_t kill_server_thread(void *arg __attribute__((unused)))
extern "C" sig_handler print_signal_warning(int sig)
{
if (global_system_variables.log_warnings)
- sql_print_warning("Got signal %d from thread %ld", sig,
- (ulong) my_thread_id());
+ sql_print_warning("Got signal %d from thread %u", sig,
+ my_thread_id());
#ifdef SIGNAL_HANDLER_RESET_ON_DELIVERY
my_sigset(sig,print_signal_warning); /* int. thread system calls */
#endif
@@ -2335,6 +2340,7 @@ static void clean_up_mutexes()
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);
mysql_mutex_destroy(&LOCK_global_table_stats);
@@ -4690,6 +4696,8 @@ static int init_thread_environment()
&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);
mysql_mutex_init(key_LOCK_global_user_client_stats,
&LOCK_global_user_client_stats, MY_MUTEX_INIT_FAST);
@@ -8760,7 +8768,7 @@ static int mysql_init_variables(void)
denied_connections= 0;
executed_events= 0;
global_query_id= 1;
- global_thread_id= 1;
+ global_thread_id= 0;
strnmov(server_version, MYSQL_SERVER_VERSION, sizeof(server_version)-1);
threads.empty();
thread_cache.empty();
@@ -10420,3 +10428,96 @@ void init_server_psi_keys(void)
}
#endif /* HAVE_PSI_INTERFACE */
+
+
+/*
+ Connection ID allocation.
+
+ We need to maintain thread_ids in the 32bit range,
+ because this is how it is passed to the client in the protocol.
+
+ The idea is to maintain a id range, initially set to
+ (0,UINT32_MAX). Whenever new id is needed, we increment the
+ lower limit and return its new value.
+
+ On "overflow", if id can not be generated anymore(i.e lower == upper -1),
+ we recalculate the range boundaries.
+ To do that, we first collect thread ids that are in use, by traversing
+ THD list, and find largest region within (0,UINT32_MAX), that is still free.
+
+*/
+
+static my_thread_id thread_id_max= UINT_MAX32;
+
+#include <vector>
+#include <algorithm>
+
+/*
+ Find largest unused thread_id range.
+
+ i.e for every number N within the returned range,
+ there is no existing connection with thread_id equal to N.
+
+ The range is exclusive, lower bound is always >=0 and
+ upper bound <=MAX_UINT32.
+
+ @param[out] low - lower bound for the range
+ @param[out] high - upper bound for the range
+*/
+static void recalculate_thread_id_range(my_thread_id *low, my_thread_id *high)
+{
+ std::vector<my_thread_id> ids;
+
+ // Add sentinels
+ ids.push_back(0);
+ ids.push_back(UINT_MAX32);
+
+ mysql_mutex_lock(&LOCK_thread_count);
+
+ I_List_iterator<THD> it(threads);
+ THD *thd;
+ while ((thd=it++))
+ ids.push_back(thd->thread_id);
+
+ mysql_mutex_unlock(&LOCK_thread_count);
+
+ std::sort(ids.begin(), ids.end());
+ my_thread_id max_gap= 0;
+ for (size_t i= 0; i < ids.size() - 1; i++)
+ {
+ my_thread_id gap= ids[i+1] - ids[i];
+ if (gap > max_gap)
+ {
+ *low= ids[i];
+ *high= ids[i+1];
+ max_gap= gap;
+ }
+ }
+
+ if (max_gap < 2)
+ {
+ /* Can't find free id. This is not really possible,
+ we'd need 2^32 connections for this to happen.*/
+ sql_print_error("Cannot find free connection id.");
+ abort();
+ }
+}
+
+
+my_thread_id next_thread_id(void)
+{
+ my_thread_id retval;
+ DBUG_EXECUTE_IF("thread_id_overflow", global_thread_id= thread_id_max-2;);
+
+ mysql_mutex_lock(&LOCK_thread_id);
+
+ if (unlikely(global_thread_id == thread_id_max - 1))
+ {
+ recalculate_thread_id_range(&global_thread_id, &thread_id_max);
+ }
+
+ retval= ++global_thread_id;
+
+ mysql_mutex_unlock(&LOCK_thread_id);
+ return retval;
+}
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 310bc1dd342..d13fdd193ef 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -722,15 +722,7 @@ inline query_id_t get_query_id()
}
/* increment global_thread_id and return it. */
-inline __attribute__((warn_unused_result)) my_thread_id next_thread_id()
-{
- return my_atomic_add64_explicit((int64*) &global_thread_id, 1, MY_MEMORY_ORDER_RELAXED);
-}
-
-#if defined(MYSQL_DYNAMIC_PLUGIN) && defined(_WIN32)
-extern "C" my_thread_id next_thread_id_noinline();
-#define next_thread_id() next_thread_id_noinline()
-#endif
+extern __attribute__((warn_unused_result)) my_thread_id next_thread_id(void);
/*
TODO: Replace this with an inline function.