7 w. [5 v! s) e c thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; . |* I f. r D* P3 k' T; u! k - e0 _ e4 n; T) _& G //线程进了线程调度器 0 m8 c* {/ Q$ ^8 |- D MYSQL_CALLBACK(thread_scheduler, add_connection, (thd)); ; Z4 S ?. H% ]; ~
}2 ~, ?; q5 j4 t8 @4 N
6 w( a; P. i( Z* |3 G 0 G& b" k" B8 B4 `5 O至此mysql就开启了一个线程对 3306 端口进行监控,等待客户端请求触发 add_connection 回调。 : P! B4 J& j% ?1 [% N! w; y- `; d- N! I" c X+ J7 P- a
4 A/ {9 l7 A7 z4 ~' t% F
2. 理解mysql是如何处理sql请求 4 q, J' B0 q0 o3 P这里我以Insert操作为例稍微解剖下处理流程:8 P% N. Y$ H8 ]/ w' {2 p0 y
% s0 Z" k) u2 ?& p4 g% t# y当用户有请求sql过来之后,就会触发 thread_scheduler的回调函数add_connection。 ; s Q8 Y t) A) e, c( O) l ; \# o$ `6 }, n& ]2 i9 N- p$ D6 N. y, }' ~5 k9 a
static scheduler_functions one_thread_per_connection_scheduler_functions= 4 w; w2 ], [0 ]% E{ " U& ` S5 h; [1 m8 Z 0, // max_threads5 Q3 [& m; y& A/ _. s) s
NULL, // init2 B7 r9 @/ R5 T* P; W. \) a
init_new_connection_handler_thread, // init_new_connection_thread" L: D& }- Z* u) z1 X+ z) C$ i
create_thread_to_handle_connection, // add_connection* s- Y7 y1 q( A$ |& t9 {
NULL, // thd_wait_begin 9 C6 [' c: c/ `. ^2 C NULL, // thd_wait_end! }4 v: F3 c- Q& b
NULL, // post_kill_notification 1 a9 k3 W3 I# w one_thread_per_connection_end, // end_thread7 q2 d( Y2 [. R& o, ^" z
NULL, // end 0 k& _: E' F) S};; w0 D( `2 E9 `. f8 x0 ?" H1 U' x
1 G V8 n! j) o4 L j: v; u; F; a
6 o X! F# h+ I* W从 scheduler_functions 中可以看到,add_connection 对应了 create_thread_to_handle_connection,也就是请求来了会触发这个函数,从名字也可以看出,用一个线程处理一个用户连接。( |" s ~8 J" M' n, Z; y
7 r& w4 j. u" Y
<1> 客户端请求被 create_thread_to_handle_connection 接管及调用栈追踪 . h" G% N8 r5 O5 p- g1 K9 R2 x/ d$ C9 `/ O/ Y
void create_thread_to_handle_connection(THD *thd) 2 g0 H/ B. s4 _) f8 g" z/ T8 C{# U r4 B5 @# N! A. `) S4 s
if ((error= mysql_thread_create(key_thread_one_connection, &thd->real_id, &connection_attrib, 7 u9 m1 C6 g8 q7 \3 k handle_one_connection,(void*) thd))){} 7 }4 X. t; ]. W' U} , t$ K2 h- J6 O$ T- n5 U9 u h* ?) `2 ]//触发回调函数 handle_one_connection 9 r7 [0 v, H( A$ l* Qpthread_handler_t handle_one_connection(void *arg) " x9 ]1 i( @6 p' R{( K* S4 k# y9 F2 E6 R* H9 X' ?) Z
do_handle_one_connection(thd);1 Y0 o! t6 `! N# M
}* V# I- C" y9 H* ^5 `
//继续处理 9 v9 k K f n& qvoid do_handle_one_connection(THD *thd_arg){8 B" n! Q: u2 _) }% B/ B5 q' F- p7 V
while (thd_is_connection_alive(thd))4 Y5 Z% M, y: Y, K
{! |/ ~4 [* F3 \& n8 H
mysql_audit_release(thd);% h W" |" k& n) ]1 Z
if (do_command(thd)) break; //这里的 do_command 继续处理 & y3 o1 `7 ^ _2 ^ } / {5 I4 o( X6 u" Y6 K* l& ?} 4 H& k) X; B% X& J) r; Q//继续分发: Z" f7 Z+ M- L
bool do_command(THD *thd) 7 G) H1 I! e) y{' Y( a8 C, e& G0 R
return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1)); 8 F& K1 H* f9 T* S} ' Z. k% A5 z7 `% e( ~/ }bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length)! \" v }& [# A7 q6 X
{ ( S* c2 C' c7 T% t switch (command) {" ~3 r7 ~' e( T8 j5 z
case COM_INIT_DB: .... break;2 J* l: S$ X, u8 @1 f1 T7 ]# t
...) S( g( X+ U$ V8 [7 [$ A3 h+ u
case COM_QUERY: //查询语句: insert xxxx : A. X# M; k% n+ @3 K mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); //sql解析# t( H8 X- V9 q
break;4 M& _( |) k2 f$ v* r8 K8 U
}' @; q' X5 C+ d- R3 E J5 R, c
} 7 y' X6 z% k P//sql解析模块 6 w* J ~9 J2 G% n7 b) W# m+ c" ~3 Svoid mysql_parse(THD *thd, char *rawbuf, uint length, Parser_state *parser_state)" @. X8 I4 q* ?& P o- M
{7 W( N- S3 Q# B5 _6 n% U" x
error= mysql_execute_command(thd);4 B& y M- \9 c( W$ w% g
}' ]) E+ c/ W C( ?$ G: n( {5 i
, a% t5 L( L |5 d) F8 _0 @( i8 p
# [: Y" c3 k! |( `0 z* c* \
<2> 到这里它的Parse,Optimizer,Cache都追完了,接下来看sql的CURD类型,继续追。。。 - `- J; v3 @+ E! a% n2 P6 l 2 F" L' w2 J( M) B$ S5 z" l//继续执行 % [' B# y4 O: ~, iint mysql_execute_command(THD *thd) / o$ F5 |# i& ?( x7 Z/ S0 L+ B{ 3 l5 p# A+ |( Q' P% ^, D switch (lex->sql_command) # D0 r' V, \ I. i2 x! W
{ & L" Q/ b2 \# B# Q" k case SQLCOM_SELECT: res= execute_sqlcom_select(thd, all_tables); break;+ [) Q% o9 N' [5 B: `. x
, ~% _0 i6 b) a1 l- S //这个 insert 就是我要追的 " V/ g; u2 s2 e! ?8 ~* L case SQLCOM_INSERT: res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values, ( [1 h. v8 R) I, W lex->update_list, lex->value_list,. o' Z. b1 t, v5 B! q) {0 Q" C
lex->duplicates, lex->ignore); ) b. r& b4 i7 X+ k( u) [2 O8 Q2 p } ^7 ?9 ?1 R( x3 q9 q
} - N2 }" w) @. _6 @4 ~//insert插入操作处理# o0 f) k3 [' i9 [+ @: E6 T
bool mysql_insert(THD *thd,TABLE_LIST *table_list,List<Item> &fields, List<List_item> &values_list, " A) ~! ~7 y e) P List<Item> &update_fields, List<Item> &update_values, 2 E9 S& _. F+ W+ ]+ G+ I6 J enum_duplicates duplic, bool ignore) 8 R4 J" J- R5 W/ G+ o{8 y; p/ N1 a) B1 \% R) C5 S
while ((values= its++)) 7 k- L1 y2 q* w! X {* m- ~- I7 q# u. p
error= write_record(thd, table, &info, &update); 8 J, i7 f$ {6 P( ^1 f w$ e } . j) _/ b$ L- v# w) J) K}9 E3 x0 H& L6 y9 ]+ R5 Q
//写入记录. U- T& m. w" w7 [# ]/ E
int write_record(THD *thd, TABLE *table, COPY_INFO *info, COPY_INFO *update) % y3 W, f" r3 W0 _( |# M{ 8 C( v3 T8 c. M$ F3 p1 z if (duplicate_handling == DUP_REPLACE || duplicate_handling == DUP_UPDATE)" S+ H, X( A9 r/ S5 W6 \' ]
{ 8 ]. I- t% w% P& ~ // ha_write_row 重点是这个函数 7 }2 m9 J7 {# b while ((error=table->file->ha_write_row(table->record[0]))) . _( q# s! f0 G3 U" Q: G9 c { 3 c8 T( h% s. g* T0 E$ Q ....( Y q; P& x0 Z4 r) [9 Q! {
} 3 e" H$ T+ V" e/ |. C. K; E } # V! C$ U/ Z& N7 s, T, M* f4 ~; V} 5 w# t$ a$ D: z; R, e2 a, O 1 ^) D3 |; S4 @/ n i0 p# g. E* O4 Y( S& R. X; j4 g3 F
0 m% U2 S) T& Q0 n! |+ c
可以看到,调用链还是挺深的,追到 ha_write_row 方法基本上算是追到头了,再往下的话就是 MySql Server 给 Storage Engine提供的接口实现了,不信的话继续看呗。。。 , q# M9 \3 K& B2 B g; O$ k; ?/ S: Z3 S 7 f" F7 q8 |1 l s<3> 继续挖 ha_write_row . _" j- t- L8 S, z0 `# R8 \! d8 R" {5 S+ U# }3 c8 K S9 t
int handler::ha_write_row(uchar *buf)" z0 T1 i. V% c) Y
{ 6 J" f2 Q' i# b' }$ N% z- n- y MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0,{ error= write_row(buf); })+ B! c* h% b: E4 w6 Z: M3 c
}( s; E8 I4 R/ a' ~ E+ \
. N& Z* _# a9 x) v! W2 O4 W/ Q
//这是一个虚方法 $ s" H% y$ f) e. `5 jvirtual int write_row(uchar *buf __attribute__((unused))) 7 C- ]# F" k4 a5 H( r" T{ 8 a& V0 ]7 I: W+ m m$ c& X9 x7 N return HA_ERR_WRONG_COMMAND;- I7 j2 [* Y, j$ w) {& f
}, b4 L% n% G' C* Y) L
6 j2 \) d" H& S6 J4 b9 Y' k0 m& S$ F9 X0 ]
看到没有,write_row是个虚方法,也就是给底层方法实现的,在这里就是给各大Storage Engines的哈。😁😁😁7 k% k0 T0 r& ^! _- w% a0 ~5 K, S
2 R$ [" |0 R) L0 e
3. 调用链图. j: K5 F5 F7 f5 d4 b7 h
这么多方法,看起来有点懵懵的吧,我来画一张图,帮助大家理解下这个调用堆栈。0 G4 G' f9 ^( f$ t& X3 u- y; H ; a( J& Q9 u. `; y( o 4 u, f; J# J$ g( q% _ 2 r) a( f5 P9 S2 y3 z三:总结; X, p; b8 d5 T9 m
大家一定要熟读架构图,有了架构图从源码中找信息就方便多了,总之学习mysql成就感还是满满的。) o# y+ @' Y. v8 t6 h
———————————————— 1 M8 Z# l: C; `- `版权声明:本文为CSDN博主「一线码农」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。! v1 }6 _$ I& v
原文链接:https://blog.csdn.net/huangxinchen520/article/details/106487415 3 [- d/ E3 b) M+ x2 R: J