diff options
Diffstat (limited to 'sql/sql_connect.cc')
-rw-r--r-- | sql/sql_connect.cc | 164 |
1 files changed, 141 insertions, 23 deletions
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 7821b96b9bb..c02db1b3947 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -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) -{ - 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)) +void do_handle_one_connection(CONNECT *connect) +{ + 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); +} |