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:
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user