Article directory
MySQL Core Class - THD - Life Cycle
THD is the core class of MySQL server layer. There is no one. Basically, all information is bound to the THD instance. After each client link comes in, the system instantiates a THD object, which then accompanies the link for life.
Initialization process
After mysqld is started, the main thread is responsible for listening to the database external service port and accepting external link requests in the loop.
The code is as follows
connection_event_loop
void connection_event_loop() { Connection_handler_manager *mgr= Connection_handler_manager::get_instance(); while (!abort_loop) { Channel_info *channel_info= m_listener->listen_for_connection_event(); if (channel_info != NULL) mgr->process_new_connection(channel_info); } }
It can also be seen that under short link stress test, this will become a bottleneck of MySQL. What we see in this article is the optimized code of 5.7. In previous versions, when initializing links, more work is left to main thread to complete, and the performance is poor.
listen_for_connection_event
Channel_info* Mysqld_socket_listener::listen_for_connection_event() { #ifdef HAVE_POLL int retval= poll(&m_poll_info.m_fds[0], m_socket_map.size(), -1); #else m_select_info.m_read_fds= m_select_info.m_client_fds; int retval= select((int) m_select_info.m_max_used_connection, &m_select_info.m_read_fds, 0, 0, 0); #endif
In the operating system supporting poll, poll is used, otherwise, select mechanism is used. There are a lot of polls on the network compared with the optimization points of select mechanism.
Then enter Mgr - > process_new_connection (channel_info)
Connection_handler_manager::process_new_connection(Channel_info* channel_info) { if (abort_loop || !check_and_incr_conn_count()) { channel_info->send_error_and_close_channel(ER_CON_COUNT_ERROR, 0, true); delete channel_info; return; } if (m_connection_handler->add_connection(channel_info)) { inc_aborted_connects(); delete channel_info; } }
MySQL supports many ways of linking, including the enterprise version of the connection pool, which is reflected here. M_connection_handler - > add_connection (channel_info)
Per_thread_connection_handler is commonly used online.
bool Per_thread_connection_handler::add_connection(Channel_info* channel_info) { int error= 0; my_thread_handle id; DBUG_ENTER("Per_thread_connection_handler::add_connection"); // Simulate thread creation for test case before we check thread cache DBUG_EXECUTE_IF("fail_thread_create", error= 1; goto handle_error;); if (!check_idle_thread_and_enqueue_connection(channel_info)) DBUG_RETURN(false); /* There are no idle threads avaliable to take up the new connection. Create a new thread to handle the connection */ channel_info->set_prior_thr_create_utime(); error= mysql_thread_create(key_thread_one_connection, &id, &connection_attrib, handle_connection, (void*) channel_info);
The mysql_thread_create function creates a new thread
Then start focusing on threading functions
pfs_spawn_thread is the entry function for initializing threads. Here's how he generates THD objects
pfs_spawn_thread calls handle_connection, mainly responsible for the following parts
- Initialize thread
- Initialize THD to be used with this thread
- Authenticate user
- Execute all queries sent on the connection
- Take connection down
- End thread / Handle next connection using thread from thread cache
Initialize thd
THD *thd= init_new_thd(channel_info);
When I write this, I suddenly think of a question: Where does the global variable max_connections work? Let's start with another short article on this issue. Let's skip it first.
Other initialization operations involve thread reuse mechanisms.
#ifdef HAVE_PSI_THREAD_INTERFACE if (pthread_reused) { /* Reusing existing pthread: Create new instrumentation for the new THD job, and attach it to this running pthread. */ PSI_thread *psi= PSI_THREAD_CALL(new_thread) (key_thread_one_connection, thd, thd->thread_id()); PSI_THREAD_CALL(set_thread_os_id)(psi); PSI_THREAD_CALL(set_thread)(psi); } #endif #ifdef HAVE_PSI_THREAD_INTERFACE /* Find the instrumented thread */ PSI_thread *psi= PSI_THREAD_CALL(get_thread)(); /* Save it within THD, so it can be inspected */ thd->set_psi(psi); #endif /* HAVE_PSI_THREAD_INTERFACE */ mysql_thread_set_psi_id(thd->thread_id()); mysql_thread_set_psi_THD(thd); mysql_socket_set_thread_owner( thd->get_protocol_classic()->get_vio()->mysql_socket);
Join the thread queue
thd_manager->add_thd(thd);
Authentication of privileges can also be seen from this, even if the user password is wrong, MySQL will also allocate threads. Does this occupy thread resources?
thd_prepare_connection(thd)
If none of the above is a problem, you begin to receive and process client commands in a loop
while (thd_connection_alive(thd)) { if (do_command(thd)) break; }
THD destruction
If the link is timed out, or the client close s the link actively, the thd object will be destroyed. There are probably the following steps.
- end_connection(thd);
In the end_connection operation, a user's link is released, which is useful in the function of restricting the user's link.
- close_connection(thd, 0, false, false);
Real Close Links and Pre-Close Processing
- thd->release_resources();
Release Thread Resources
- thd_manager->remove_thd(thd);
Remove from the thread queue
Further down is thread reuse
- channel_info= Per_thread_connection_handler::block_until_new_connection();
Whether this thread is cached is related to thread_cache_size, the global variable in MySQL. If the number of currently cached threads is less than this value, the thread will enter the cached state, wait for the new client to arrive, and then wake up. Otherwise, it will exit the thread.
Welcome to MySQL Kernel Communication qq q Group 860945825