- b! H7 f9 V$ n$ \) g& N2 r$ C& s& |, D# C1 s Q T. Q
int mysqld_main(int argc, char **argv): n. R9 D+ x! a. f8 R8 N6 H* S% V
{ % d5 l. D6 L* D& Y //创建服务监听线程 $ ]" [( S/ w- _+ a) o6 @9 @ handle_connections_sockets(); 2 P3 M- \/ B6 L6 ?} & l8 t" N% F4 B7 N( Q: ^7 j! S: [1 Y% {. ~) m. E+ w
void handle_connections_sockets()7 i, @0 {/ B$ d c2 }& G
{ 5 g0 `3 L" N3 q; Y //监听连接& [% l0 Z2 z1 y# Q2 } P& V' }
new_sock= mysql_socket_accept(key_socket_client_connection, sock,- ~+ H/ x# k4 `2 ~ d- @. K
(struct sockaddr *)(&cAddr), &length);1 [. {5 Y4 }+ L# j% o
7 p3 S& M$ A) `+ N P* l if (mysql_socket_getfd(sock) == mysql_socket_getfd(unix_sock)); w- e" Y, @" X5 {5 I: P- V
thd->security_ctx->set_host((char*) my_localhost);2 |# ^+ u; W) f( O1 H! c9 I5 L; p& H
& r4 T( \- r! ]5 M+ K$ L9 n J //创建连接 * F6 `% d' n" Y r! J6 [# | create_new_thread(thd); 7 [0 l% R; y- `5 v# M7 s} a' ]1 P* u0 C3 k- ~5 x
. C V" t5 O* R( }
//创建新线程处理处理用户连接5 m& k5 a I; _# ~
static void create_new_thread(THD *thd){ + j. E1 N; o2 Z6 m1 m" N8 k# v4 `& w6 |4 G
thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; " D' F1 I9 H _3 W6 d1 {' K* Y0 R, T' h0 Y ^3 b, j# c# s$ _6 q
//线程进了线程调度器 # w8 }+ P3 l" Q# j* B0 m y MYSQL_CALLBACK(thread_scheduler, add_connection, (thd)); 2 i6 G8 c% {* a; s* i$ Q% f; ^% a8 }
}+ S$ M4 ^( L& T' h4 A
% ~; h4 A0 U% [ F( ^4 l. _
; ^& t# T2 D# B+ I( n
至此mysql就开启了一个线程对 3306 端口进行监控,等待客户端请求触发 add_connection 回调。 0 W) M, ^3 m& t$ } V: D# K # O, b8 W. Z* U S" E9 r$ B; {: a- @1 E$ w
2. 理解mysql是如何处理sql请求 % n1 y! V2 C2 e( |- `2 [这里我以Insert操作为例稍微解剖下处理流程: 7 d- e b% Q3 a, B0 }9 p/ r5 [8 J7 N4 L9 O$ \
当用户有请求sql过来之后,就会触发 thread_scheduler的回调函数add_connection。 . F; x" z) f" E5 Y1 r2 ?! { 4 B3 o8 Q" l$ H* u; _ 2 @) T* Z& ]9 H! F3 Y _7 V, c2 Astatic scheduler_functions one_thread_per_connection_scheduler_functions= % J: E% G# W* @) u6 i$ m1 }{ 8 B* {& y, f k, v9 T; l 0, // max_threads, u: y$ `$ }. f) N% r9 F3 @ x5 R
NULL, // init ; g! j3 D6 I% C1 c' F* H1 W! W3 m r init_new_connection_handler_thread, // init_new_connection_thread3 {' [+ y( s, B% `: ]6 ]
create_thread_to_handle_connection, // add_connection 8 {/ T; `* o2 U0 M4 J! R2 c NULL, // thd_wait_begin . M: r$ F% q) u NULL, // thd_wait_end* u0 D* M b O: s
NULL, // post_kill_notification" S* p O) z" N( [
one_thread_per_connection_end, // end_thread , ~4 ]* w9 g+ D- q NULL, // end) l0 ]$ U. z2 Z4 `" J
}; 5 q6 w; C/ O4 F4 K8 s4 w! F; z8 l; b$ Y
) l' z# E( E* t9 c w) @从 scheduler_functions 中可以看到,add_connection 对应了 create_thread_to_handle_connection,也就是请求来了会触发这个函数,从名字也可以看出,用一个线程处理一个用户连接。 3 ]7 t4 T3 z6 o " Y; X. }+ G7 C. c% ^<1> 客户端请求被 create_thread_to_handle_connection 接管及调用栈追踪! I0 _3 j" ^1 H. q# u. m
. i! J. W: L4 }. k* Q9 \! T4 ?. Dvoid create_thread_to_handle_connection(THD *thd)- u' U1 c8 S$ \, S ~& ^/ d9 _
{2 x& B ^- u* H! }
if ((error= mysql_thread_create(key_thread_one_connection, &thd->real_id, &connection_attrib," A0 {$ Z) y8 W' e6 `0 M
handle_one_connection,(void*) thd))){}- B/ B4 ]% M5 _
} * ^1 Y% q5 A4 k2 I& n! H& [; E//触发回调函数 handle_one_connection; ~2 o" ?1 L. ^" \- M* y
pthread_handler_t handle_one_connection(void *arg) $ }9 V' P% y" b- O) h5 v{" s3 k* ]( K2 y' F! |3 z- Y5 G8 {$ P
do_handle_one_connection(thd); # F% J0 c! G4 j: m' R}& [3 u$ r2 Y* s- w9 ~
//继续处理+ D( u% z0 v" h' u
void do_handle_one_connection(THD *thd_arg){' a. b9 O ?6 c
while (thd_is_connection_alive(thd)) 4 _. M ^* W) G+ j9 v$ C {4 H! }+ r; i' N5 l
mysql_audit_release(thd);7 f2 R2 n* d' r. [
if (do_command(thd)) break; //这里的 do_command 继续处理5 V# m4 R% X% _) ]$ ~
}/ V" O/ Z* i2 U( e- J
}- C d2 E- i) w' H: u0 A
//继续分发1 F$ I" O! B! u3 R# O
bool do_command(THD *thd) ; {( G" M8 r, t+ g. F' p{ . K- S. }, P7 l( l# [2 A return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1));* q4 W& P6 f+ z! K- W7 R o
} 5 Q4 E, F p, P3 E, @bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length) , k$ S" n+ H6 g" q. ]4 A{ 2 L1 p: I) _4 V7 X' c* ~ switch (command) { + U" S2 h- s& W- e4 W case COM_INIT_DB: .... break; 9 ?6 k" R6 E+ E7 } ... u( Q# J0 U& M, [. k
case COM_QUERY: //查询语句: insert xxxx$ p' B3 Z3 |1 i) J) R! L6 j6 W
mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); //sql解析' o' U" e- z) ^/ A' ]1 E. X
break; 8 F" {, q# Y: L4 G* H }7 ^ v, s3 _: w# c, B
}; t, H7 o! _; s; h
//sql解析模块7 O( ~/ Q$ C. c& ?3 w
void mysql_parse(THD *thd, char *rawbuf, uint length, Parser_state *parser_state) ) u; i4 _3 l4 n5 p# I{6 O& L% \" c: M# U+ U$ L
error= mysql_execute_command(thd);& s% F' r. R( U1 `
} 8 o, r; C( `% J0 ~* ^ 9 C! B4 e1 n; {, G1 G- X! C8 E ; f: r; b" s1 D<2> 到这里它的Parse,Optimizer,Cache都追完了,接下来看sql的CURD类型,继续追。。。* f6 J# B- {3 K! H* e1 D
( X. A- V2 K6 _4 B$ \8 ]' k" J
//继续执行 : j: A5 ^$ N+ N# u; Sint mysql_execute_command(THD *thd) : b% d' |7 A9 e{ / D* C8 H$ h9 R R& \" Z switch (lex->sql_command) " U# U: u. s V6 L* m; t {2 |8 _2 P7 l( ^' s
case SQLCOM_SELECT: res= execute_sqlcom_select(thd, all_tables); break;$ n% j) [ S/ M5 H: W4 V
8 `0 [: e! @( N
//这个 insert 就是我要追的5 ~4 m9 u; U; u& ^
case SQLCOM_INSERT: res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values, ; M& w6 I/ V F. e lex->update_list, lex->value_list, 9 j3 {1 N& F# ^- }0 o& C: d lex->duplicates, lex->ignore);$ B! l0 Z4 f/ [ g: k# T
}2 T8 ]( W: z, \* q
}, \2 F1 P9 R* ~7 o
//insert插入操作处理 , l) e2 Y1 y. f* j- obool mysql_insert(THD *thd,TABLE_LIST *table_list,List<Item> &fields, List<List_item> &values_list, 1 }; a7 [& n9 t" c) z, |7 T$ {" M List<Item> &update_fields, List<Item> &update_values, $ f& g, z) X# b% { h
enum_duplicates duplic, bool ignore)5 o1 u1 N9 o& w0 z9 T6 @
{ " C0 S' a3 m6 w- _ H s7 Y: _7 | while ((values= its++)): A( N; ]4 O/ n& _7 k/ P: T% w
{ ) J; z/ R& u+ T error= write_record(thd, table, &info, &update); : p% P5 _( e r( ]% V" {' c$ F }' J& C* ]: N. X2 @
} " [3 I/ M, A \4 _//写入记录8 S8 y: i( [. h* `- h: [
int write_record(THD *thd, TABLE *table, COPY_INFO *info, COPY_INFO *update), h- D6 g* ]% r6 Y4 z5 c
{" n2 T$ Z, m! q4 c) P: g6 K: j, o1 V
if (duplicate_handling == DUP_REPLACE || duplicate_handling == DUP_UPDATE) ) }2 u' V5 O' {' S( H0 w. X {: P9 e. V; A: n5 Y% D) I
// ha_write_row 重点是这个函数 2 {: {9 v( G+ h" }9 l while ((error=table->file->ha_write_row(table->record[0]))) ( U# v/ J( g$ G' z9 x7 E3 W1 } { / \! s/ @+ S: v3 E) T ....2 Q! o6 j7 q( l. O3 e
} * Q* z' R8 F/ e$ c } 5 h( R( l$ L0 T} % K: [: H1 t& x* v# F . b6 Z$ w! I- m, e( ~# p6 W0 ~* T4 ^7 U6 ]$ g
# k/ u% [6 l* \7 V6 Q7 i可以看到,调用链还是挺深的,追到 ha_write_row 方法基本上算是追到头了,再往下的话就是 MySql Server 给 Storage Engine提供的接口实现了,不信的话继续看呗。。。 ; w; D& @& E' o# u/ T 3 r p7 j3 v! |. R<3> 继续挖 ha_write_row 9 {( [) D7 ~# b) j) D9 ?/ l4 T. }6 O S% @; ?
int handler::ha_write_row(uchar *buf)! C0 o1 L2 n! I9 d/ y& N- H
{ 5 U6 t j$ M/ j, m1 \5 C0 X MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0,{ error= write_row(buf); })$ e9 V% z @; E1 l6 X: p4 n
}7 @5 X6 ~0 ]) A( \
% O5 i4 [" f! ~0 d2 P B4 T. g7 S. L
//这是一个虚方法 , O2 H1 c2 ^ ]" g3 q: Fvirtual int write_row(uchar *buf __attribute__((unused))) 8 E5 l& B3 T" D) p) _+ P* {{; g' U$ [8 a+ b/ P& M* P
return HA_ERR_WRONG_COMMAND; ' C# l0 W" E8 I O+ b3 D. S* N" x! w} 3 d* {1 ?# d7 L' @ 4 H* S( {* L: D# e- ~4 E0 o ]: v8 C0 S
看到没有,write_row是个虚方法,也就是给底层方法实现的,在这里就是给各大Storage Engines的哈。😁😁😁! u) N/ y9 H- U- A
* U7 }1 e' o0 d1 l2 y) {3. 调用链图& p0 J8 `; X; H$ }
这么多方法,看起来有点懵懵的吧,我来画一张图,帮助大家理解下这个调用堆栈。3 |' l7 e$ j0 W1 X" s( f 3 X7 M- \( L+ a ' ^8 n: L- x, p% i5 z ( f/ T' G( E x6 ~% p三:总结% F. Z3 P2 s. y) R- v j0 z) M. D
大家一定要熟读架构图,有了架构图从源码中找信息就方便多了,总之学习mysql成就感还是满满的。5 F6 ?* H, Z5 K3 @0 w. H
————————————————) O; Q: \! ~/ E8 [
版权声明:本文为CSDN博主「一线码农」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。) l9 s5 R, k B+ v% E
原文链接:https://blog.csdn.net/huangxinchen520/article/details/1064874154 i$ t: y: x* r2 a$ _