A little free today (mood?) ) to sort out the network part of MySQL code. The overall network part of the code is very simple, MySQL almost did not do too much encapsulation, very direct call system functions, at a glance.
Overall, MySQL uses a model that connects one thread to another, using nonblocking mode for the socket that the client connects to. The Linux version, and even OSX, uses the poll function to listen for client requests. The processing of the intermediate details does not have too many complicated operations, and the MySQL piece is not particularly optimized.
Let's start with some key functions of MySQL startup network.
When MySQL starts, the first entry is the Mysql_main function, which is equivalent to the main function. In this main, there are some column initialization tasks, including initializing environment variables, shutdown threads, and finally entering an infinite loop to process client connection requests, of course, the wireless loop can be closed operation or abnormal interrupt, thus exiting Mysqld. Main first calls Network_init () to initialize the network socket, and at last, calls Handle_connection_sockets () into the Loop processing client to request the connection. The pseudo-code that is simply written is as follows:
int Sql_main () { // Initialize socket handle_connection_sockets ();// loop processing connection request return0;}
The following is the pseudo-code for Network_init (), ignoring some platforms, error-handling code, and writing out the main logic:
voidNetwork_init () {//address information, AI is a linked list, and a is the address information of BIND structAddrinfo *ai, *A; //Set_port is the listener port that determines MySQL, and by default it takes the port of the compiled configuration ,//If the compilation configuration is not set, then use 3306//environment variable Mysql_tcp_port will overwrite the above configurationSet_port (); //call getaddrinfo to get address information through the hostname, note that the Hint.ai_flags setting here is ai_passive to get only address information that can bind. The default host name is "0.0.0.0"Hint.ai_flags=ai_passive; Getaddrinfo (host name, hint,&AI); //call Create_socket to create a ip_sock based on the address information, this ip_sock is used by the Accept connection request. Ip_sock is a global variable. Ip_sock=Create_socket (AI, a); //the set address can be reused so that mysqld can quickly re-bind from the stop without waiting for the time wait statesetsockopt (Ip_sock, REUSEADDR,1); //turn off use only IPv6setsockopt (Ip_sock, Ipv6only,0); //The following MySQL uses a For loop to try bind multiple times, which is also to ensure the success rate of BIND, each attempt fails, then sleep for a while. //sleep x seconds for every try//x:1, 3, 7 , A, a, a, ... for(retry =1;; retry++) {ret=bind (Ip_sock, a); //bind successfully went on if(0==ret) { Break; } //failure, if not because the address is still in use error, go out to continue, so mysqld will start failure if(Socket_eaddrinuse! =errno) { Break; } //too many attempts failed, mysqld start failed//This can be used when MySQL starts with parameter--port-open-timeout= #设置启动最多等待时间 if(Wait_time >max_wait_time) { Break; } wait_time+ = Retry * Retry/3+1; Sleep (wait_time); } Listen (Ip_sock, back_log);
//The following, read out Mysql.sock This file, the native sock parameters loaded in, so that MySQL actually has two sockets to come out of the client connection request, one is the above, one is the following this main to the local use, its code is more simple#ifdef Unix_sock Unix_sock=socket (); Strmov (Unixaddr.sun_path, Mysqld_unix_port); //load the local addresssetsockopt (Unix_sock, REUSEADDR,1); Bind (Unix_sock); Listen (Unix_sock, back_log);#endif //#ifdef Unix_sock}
In the above code, Set_port () and Create_socket () are simple, simply call getenv to get the environment variable to set the port, and Create_socket () calls the socket to generate the socket socket. So it's not listed.
Next will enter the handle function, the handle function is mainly to deal with the connection request, the main implementation method is the arrival of poll listening request, and then the accept out New_sock, the new_sock to a new thread, then the task is this child thread:
voidhandle_connection_sockets () {intSocket_count =0; //Yes, just two, a ip_sock, a unix_sock, the former is used to accept the remote client, the latter is used to accept the machinePOLLFD fds[2]; FDS[SOCKET_COUNT].FD=Ip_sock; Fds[socket_count].events=Pollin; intIp_flags = Fcntl (Ip_sock, F_GETFL,0); Socket_count++; FDS[SOCKET_COUNT].FD=Unix_sock; Fds[socket_count].events=Pollin; intSocket_flags=fcntl (Unix_sock, F_GETFL,0); Socket_count++; intSock =0, flags =0, New_sock =0; //This is the main loop of the mysqld main thread. while(!Abort_loop) { //Poll monitoring intRet_val = Poll (FDS, Socket_count,-1); for(inti =0; i < Socket_count; ++i) { if(Fds[i].revents &Pollin) {Sock=FDS[I].FD; Flags= Fcntl (sock, F_GETFL,0); Break; } } //non-blocking socketsfcntl (sock, F_SETFL, flags|O_nonblock); //Accept, here accept10 times, until successful, 10 times are unsuccessful, then this connection request failed//Max_accept_retry = Ten for(intRetry =0; retry = = Max_accept_retry; ++retry) {New_sock=Accept (sock); if(no error) { Break; } Sleep (1); } if(New_sock = =invalid_socket) { Continue; } //obtaining address information on the endSockaddr_storage Dummy; if(GetSockName (New_sock, &dummy) <0) {Shotdown (New_sock, SHUT_RDWR); Close (New_sock); Continue; } //The following creates the ThD object, the THD is the MySQL thread object, puts a lot of information, has not studied//... }}
I'm going to study here today.
MySQL Network section Code