1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-27 18:02:13 +03:00

MDEV-6150 Speed up connection speed by moving creation of THD to new thread

Creating a CONNECT object on client connect and pass this to the working thread which creates the THD.
Split LOCK_thread_count to different mutexes
Added LOCK_thread_start to syncronize threads
Moved most usage of LOCK_thread_count to dedicated functions
Use next_thread_id() instead of thread_id++

Other things:
- Thread id now starts from 1 instead of 2
- Added cast for thread_id as thread id is now of type my_thread_id
- Made THD->host const (To ensure it's not changed)
- Removed some DBUG_PRINT() about entering/exiting mutex as these was already logged by mutex code
- Fixed that aborted_connects and connection_errors_internal are counted in all cases
- Don't take locks for current_linfo when we set it (not needed as it was 0 before)
This commit is contained in:
Monty
2016-02-01 12:45:39 +02:00
parent 076aa182c2
commit 3d4a7390c1
50 changed files with 878 additions and 551 deletions

View File

@ -827,14 +827,17 @@ bool thd_init_client_charset(THD *thd, uint cs_number)
Initialize connection threads
*/
#ifndef EMBEDDED_LIBRARY
bool init_new_connection_handler_thread()
{
pthread_detach_this_thread();
if (my_thread_init())
{
statistic_increment(aborted_connects,&LOCK_status);
statistic_increment(connection_errors_internal, &LOCK_status);
return 1;
}
DBUG_EXECUTE_IF("simulate_failed_connection_1", return(1); );
return 0;
}
@ -850,7 +853,6 @@ bool init_new_connection_handler_thread()
1 error
*/
#ifndef EMBEDDED_LIBRARY
static int check_connection(THD *thd)
{
uint connect_errors= 0;
@ -951,6 +953,7 @@ static int check_connection(THD *thd)
this is treated as a global server OOM error.
TODO: remove the need for my_strdup.
*/
statistic_increment(aborted_connects,&LOCK_status);
statistic_increment(connection_errors_internal, &LOCK_status);
return 1; /* The error is set by my_strdup(). */
}
@ -968,7 +971,7 @@ static int check_connection(THD *thd)
if (thd->main_security_ctx.host)
{
if (thd->main_security_ctx.host != my_localhost)
thd->main_security_ctx.host[MY_MIN(strlen(thd->main_security_ctx.host),
((char*) thd->main_security_ctx.host)[MY_MIN(strlen(thd->main_security_ctx.host),
HOSTNAME_LENGTH)]= 0;
thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
}
@ -1016,6 +1019,7 @@ static int check_connection(THD *thd)
Hence, there is no reason to account on OOM conditions per client IP,
we count failures in the global server status instead.
*/
statistic_increment(aborted_connects,&LOCK_status);
statistic_increment(connection_errors_internal, &LOCK_status);
return 1; /* The error is set by alloc(). */
}
@ -1054,7 +1058,8 @@ bool setup_connection_thread_globals(THD *thd)
{
close_connection(thd, ER_OUT_OF_RESOURCES);
statistic_increment(aborted_connects,&LOCK_status);
MYSQL_CALLBACK(thd->scheduler, end_thread, (thd, 0));
statistic_increment(connection_errors_internal, &LOCK_status);
thd->scheduler->end_thread(thd, 0);
return 1; // Error
}
return 0;
@ -1082,7 +1087,7 @@ bool login_connection(THD *thd)
int error= 0;
DBUG_ENTER("login_connection");
DBUG_PRINT("info", ("login_connection called by thread %lu",
thd->thread_id));
(ulong) thd->thread_id));
/* Use "connect_timeout" value during connection phase */
my_net_set_read_timeout(net, connect_timeout);
@ -1254,11 +1259,11 @@ void prepare_new_connection_state(THD* thd)
pthread_handler_t handle_one_connection(void *arg)
{
THD *thd= (THD*) arg;
CONNECT *connect= (CONNECT*) arg;
mysql_thread_set_psi_id(thd->thread_id);
mysql_thread_set_psi_id(connect->thread_id);
do_handle_one_connection(thd);
do_handle_one_connection(connect);
return 0;
}
@ -1290,19 +1295,17 @@ bool thd_is_connection_alive(THD *thd)
return FALSE;
}
void do_handle_one_connection(THD *thd_arg)
void do_handle_one_connection(CONNECT *connect)
{
THD *thd= thd_arg;
thd->thr_create_utime= microsecond_interval_timer();
/* We need to set this because of time_out_user_resource_limits */
thd->start_utime= thd->thr_create_utime;
if (MYSQL_CALLBACK_ELSE(thd->scheduler, init_new_connection_thread, (), 0))
ulonglong thr_create_utime= microsecond_interval_timer();
THD *thd;
if (connect->scheduler->init_new_connection_thread() ||
!(thd= connect->create_thd()))
{
close_connection(thd, ER_OUT_OF_RESOURCES);
statistic_increment(aborted_connects,&LOCK_status);
MYSQL_CALLBACK(thd->scheduler, end_thread, (thd, 0));
scheduler_functions *scheduler= connect->scheduler;
connect->close_with_error(0, 0, ER_OUT_OF_RESOURCES);
scheduler->end_thread(0, 0);
return;
}
@ -1311,14 +1314,22 @@ void do_handle_one_connection(THD *thd_arg)
increment slow_launch_threads counter if it took more than
slow_launch_time seconds to create the thread.
*/
if (thd->prior_thr_create_utime)
if (connect->prior_thr_create_utime)
{
ulong launch_time= (ulong) (thd->thr_create_utime -
thd->prior_thr_create_utime);
ulong launch_time= (ulong) (thr_create_utime -
connect->prior_thr_create_utime);
if (launch_time >= slow_launch_time*1000000L)
statistic_increment(slow_launch_threads, &LOCK_status);
thd->prior_thr_create_utime= 0;
}
delete connect;
/* Make THD visible in show processlist */
add_to_active_threads(thd);
thd->thr_create_utime= thr_create_utime;
/* We need to set this because of time_out_user_resource_limits */
thd->start_utime= thr_create_utime;
/*
handle_one_connection() is normally the only way a thread would
@ -1365,7 +1376,7 @@ end_thread:
if (thd->userstat_running)
update_global_user_stats(thd, create_user, time(NULL));
if (MYSQL_CALLBACK_ELSE(thd->scheduler, end_thread, (thd, 1), 0))
if (thd->scheduler->end_thread(thd, 1))
return; // Probably no-threads
/*
@ -1377,3 +1388,110 @@ end_thread:
}
}
#endif /* EMBEDDED_LIBRARY */
/* Handling of CONNECT objects */
/*
Close connection without error and delete the connect object
This and close_with_error are only called if we didn't manage to
create a new thd object.
*/
void CONNECT::close_and_delete()
{
DBUG_ENTER("close_and_delete");
if (vio)
vio_close(vio);
if (thread_count_incremented)
{
/*
Normally this is handled by THD::unlink. As we haven't yet created
a THD and put it in the thread list, we have to manage counting here.
*/
dec_thread_count();
dec_connection_count(scheduler);
}
statistic_increment(connection_errors_internal, &LOCK_status);
statistic_increment(aborted_connects,&LOCK_status);
delete this;
DBUG_VOID_RETURN;
}
/*
Close a connection with a possible error to the end user
Alse deletes the connection object, like close_and_delete()
*/
void CONNECT::close_with_error(uint sql_errno,
const char *message, uint close_error)
{
THD *thd= create_thd();
if (thd)
{
if (sql_errno)
net_send_error(thd, sql_errno, message, NULL);
close_connection(thd, close_error);
delete thd;
set_current_thd(0);
if (thread_count_incremented)
{
dec_thread_count();
dec_connection_count(scheduler);
}
delete this;
statistic_increment(connection_errors_internal, &LOCK_status);
statistic_increment(aborted_connects,&LOCK_status);
}
else
{
/*
Out of memory; We can't generate an error, just close the connection
close_and_delete() will increment statistics.
*/
close_and_delete();
}
}
CONNECT::~CONNECT()
{
if (vio)
vio_delete(vio);
}
/* Create a THD based on a CONNECT object */
THD *CONNECT::create_thd()
{
my_bool res;
THD *thd;
DBUG_ENTER("create_thd");
DBUG_EXECUTE_IF("simulate_failed_connection_2", DBUG_RETURN(0); );
if (!(thd= new THD))
DBUG_RETURN(0);
set_current_thd(thd);
res= my_net_init(&thd->net, vio, thd, MYF(MY_THREAD_SPECIFIC));
vio= 0; // Vio now handled by thd
if (res)
{
delete thd;
set_current_thd(0);
DBUG_RETURN(0);
}
init_net_server_extension(thd);
thd->security_ctx->host= host;
thd->extra_port= extra_port;
thd->scheduler= scheduler;
thd->thread_id= thd->variables.pseudo_thread_id= thread_id;
thd->real_id= real_id;
DBUG_RETURN(thd);
}