9 ~0 T5 P8 l2 h# z5 ? thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;% Q7 c5 a4 ]. s
# ^4 x7 e. N! q; V0 J# d' w/ a
//线程进了线程调度器, l j' F ~: g3 K* e0 G' g
MYSQL_CALLBACK(thread_scheduler, add_connection, (thd)); . C6 V2 S1 w1 G& w9 j6 o
} . W, ]' ` @! ?* q" ~ ' V/ a, `+ G1 [( y5 T5 Y, P6 _% |, k" v1 [) Y4 }1 s! w
至此mysql就开启了一个线程对 3306 端口进行监控,等待客户端请求触发 add_connection 回调。! y3 C- l) W( F+ F; ? E
7 `) Y/ S0 Z5 D- |
2 q# S$ l. z3 U* Y3 Y' u7 f% T8 W9 P
2. 理解mysql是如何处理sql请求3 _: c- c3 ^: d6 R/ i. }: p6 ~
这里我以Insert操作为例稍微解剖下处理流程: ! r& U4 {1 t7 P: f, [, O: [* w7 i' F / l+ d! s r; S1 e/ {7 M当用户有请求sql过来之后,就会触发 thread_scheduler的回调函数add_connection。9 @- r2 }; Z& R% t% z3 U
/ s2 R1 Q1 C# [1 b9 S, D
$ W) S* O' M8 K! w: p0 @
static scheduler_functions one_thread_per_connection_scheduler_functions= ; a/ G& v) l% a5 f# }8 F- {{ / \' p2 v$ k0 f C 0, // max_threads % b: g) m( I1 l) p9 v2 l1 G NULL, // init " |! X% A; Y* L( d3 i init_new_connection_handler_thread, // init_new_connection_thread U/ p+ l8 {! t) ?
create_thread_to_handle_connection, // add_connection! ^; O/ a. [' a$ X! \
NULL, // thd_wait_begin" S4 Y! v+ O1 @2 |7 m1 v
NULL, // thd_wait_end ]$ U& d4 z. e. q
NULL, // post_kill_notification # I$ l* S4 A* e6 ^0 Q one_thread_per_connection_end, // end_thread ( B8 I2 P/ \: P& D* U NULL, // end " S+ v# \; Z5 k9 E/ j5 A}; + J5 S, u3 \! w% ~: Q+ S$ q* D, `- X
) g$ v/ M9 G# B( r/ T
从 scheduler_functions 中可以看到,add_connection 对应了 create_thread_to_handle_connection,也就是请求来了会触发这个函数,从名字也可以看出,用一个线程处理一个用户连接。 : K5 {* j0 l0 @, T: l8 {' \ a- u. K1 |( L/ B
<1> 客户端请求被 create_thread_to_handle_connection 接管及调用栈追踪. }- g9 }. y' l' B/ f) j: U5 J
5 z& v5 G2 m2 g/ g; g$ Nvoid create_thread_to_handle_connection(THD *thd) ) e/ D5 A, S, I+ h: o9 X{' T% y2 R$ @$ _& W8 ^- j6 H
if ((error= mysql_thread_create(key_thread_one_connection, &thd->real_id, &connection_attrib, ! `. G7 w9 g4 o6 G9 q handle_one_connection,(void*) thd))){}+ `( j% m7 P$ r8 i$ f5 _
}. q3 M( d' ?& [0 M" P- x r
//触发回调函数 handle_one_connection/ W* ^4 n C/ N' s% O
pthread_handler_t handle_one_connection(void *arg)7 j( b8 `% ]! r `
{, T7 k* \0 k2 [* @
do_handle_one_connection(thd); 5 Q+ U9 i, g: g8 x}% ?: ?; g# p& a. f! ^, k
//继续处理6 ]- q3 x$ H( i' T8 ^
void do_handle_one_connection(THD *thd_arg){* i; ~4 g3 A$ K( W/ p
while (thd_is_connection_alive(thd))6 h+ }) U7 C- m2 |: {+ e' @0 |
{0 R m# r" m% B* |4 y, A
mysql_audit_release(thd);7 [) y9 e/ O U( B0 F, b
if (do_command(thd)) break; //这里的 do_command 继续处理 . i; W0 ` F6 Z }7 B8 Y7 @' t& C/ v5 F5 ~ ?
} . m' {& X" s; ]//继续分发; T9 ~3 g& M% M! T
bool do_command(THD *thd)% J8 s8 w7 Z0 a! z6 t
{2 k+ j8 n" z b- r
return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1)); " ?8 k6 [3 h) t} " A5 E% }' w7 k# Qbool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length) % A2 J' L! M, |+ k W- W+ ?{: {) [6 g7 S( Q; e
switch (command) {: c& o) z. p7 j: @+ l `! k& U
case COM_INIT_DB: .... break; : `2 i- g* o1 z" J ...5 P$ z) j# `3 L" \; m# s
case COM_QUERY: //查询语句: insert xxxx' }. q" J& G5 Y# F! Q1 t" A
mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); //sql解析 " R( T- S5 B; G) t break;) X& u. m* z3 ^! M1 z
} 8 H0 h1 A5 ?) {- e+ y9 u! t; l}+ y3 } ~3 j$ S. b7 Z
//sql解析模块 3 w8 p$ {& S; g# k3 z) b* lvoid mysql_parse(THD *thd, char *rawbuf, uint length, Parser_state *parser_state) . K# J* o1 P. o$ Y! W" V/ Q7 {2 i+ U{ % ^* {4 A# P: |# w X e error= mysql_execute_command(thd); 3 U( g0 P4 ]; p} 7 u3 L, _5 Z. J" r# l4 _ & b+ I1 ~" {: ^. X7 Q5 n1 ^" V# h0 ^+ Z1 G* V) x- V" |
<2> 到这里它的Parse,Optimizer,Cache都追完了,接下来看sql的CURD类型,继续追。。。5 z/ K B3 t; d [ M
3 G8 O$ c) l2 ^2 k5 [
//继续执行 / A) K4 d) u3 A g/ x9 Oint mysql_execute_command(THD *thd) . a5 V1 u2 l* ~/ i+ J{ 6 ?6 p& \: |' r c: U switch (lex->sql_command) : U; Z) X) R8 ^0 e { - M' E, Z& O9 e, ^* j4 l case SQLCOM_SELECT: res= execute_sqlcom_select(thd, all_tables); break;/ o4 D. r8 ?" L$ v+ f
% d- ~, X* M `3 J$ X' ?" b
//这个 insert 就是我要追的 + u% D4 @" f3 }4 o case SQLCOM_INSERT: res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values, 8 W% V+ _9 z) \3 P lex->update_list, lex->value_list,% C! r Q! T& d' d
lex->duplicates, lex->ignore);6 M8 y8 t& s$ E! Z5 z9 Z! ^) Q
} E. r, U$ F5 m8 `4 m/ h} 5 P7 s# }2 \0 V* S0 M//insert插入操作处理 1 G% O% z7 ?/ j' a/ T+ \2 Nbool mysql_insert(THD *thd,TABLE_LIST *table_list,List<Item> &fields, List<List_item> &values_list,2 }0 @9 l7 j9 ~( J! a; h
List<Item> &update_fields, List<Item> &update_values, + ^2 }% U' J4 F* x. @5 G enum_duplicates duplic, bool ignore) 0 B8 u) R8 f$ C7 |6 J" z: o' P{* ?+ B5 U( a/ J1 T
while ((values= its++))! Y8 ^ K5 U- _! P9 G! ?+ U K
{7 g6 \: V6 q4 R$ z+ k
error= write_record(thd, table, &info, &update); $ f( [( W, ^9 B. X' U } * J! F) Y9 ~4 g) J# h}' ?9 P% i7 R/ @( b1 D5 u9 i- l& G2 |
//写入记录 0 [& X" T( S E/ F. W) ^int write_record(THD *thd, TABLE *table, COPY_INFO *info, COPY_INFO *update) % H- K- ]! z5 O3 C" B{( R/ n- M V6 p8 h1 z6 G
if (duplicate_handling == DUP_REPLACE || duplicate_handling == DUP_UPDATE) 6 R3 I4 \; Z3 C { 1 H* [: T% l9 U8 r' v# A // ha_write_row 重点是这个函数 ; v6 ]2 u3 L/ v' P7 X- } while ((error=table->file->ha_write_row(table->record[0])))9 S# R# U+ n5 e! i$ h, l" l
{ 1 G* h$ S8 [$ J9 n8 W1 [" r ....3 o& L6 h7 I0 d- U/ p5 b' Y7 E H
} ; T- |) h$ J& {& y }8 t# a0 x: w( Q6 _ j( Q" |2 k, q
}7 A* [2 J5 o/ \3 r3 m' v5 I& C
2 {* [6 D: |: K: B
/ F8 d. O3 M% J3 b+ Q1 e. a$ @2 }
. M8 i& i. C5 Z, U3 M6 e可以看到,调用链还是挺深的,追到 ha_write_row 方法基本上算是追到头了,再往下的话就是 MySql Server 给 Storage Engine提供的接口实现了,不信的话继续看呗。。。5 _1 m6 p7 M, ^7 e. \- R! a* c
1 x; J( l4 p- l7 d& [6 s* N<3> 继续挖 ha_write_row 1 I, g5 [, n' d * i& W' H1 _) w& F Zint handler::ha_write_row(uchar *buf)" @9 B6 v7 X/ ]3 T- ]; V. `
{ . [% N! Z1 p. Y* E0 d MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0,{ error= write_row(buf); }) 2 @9 ~3 J. N5 K( ^} 4 x$ }! Z/ D6 I0 T+ e: K2 M- s6 @ a W& L
//这是一个虚方法) Y2 i' o) a. \$ T6 g* T7 ~3 v
virtual int write_row(uchar *buf __attribute__((unused))) " Q+ F2 @# J& W' |9 \$ E{! W, Y; ^6 N% j: W- H
return HA_ERR_WRONG_COMMAND;- Z2 o' B8 q% N( K- N
} # Y/ {: X# Z n. T6 L, k6 d) q" R' b# N$ I
% O* D# M: W& e% C- n' q& _+ z6 Q看到没有,write_row是个虚方法,也就是给底层方法实现的,在这里就是给各大Storage Engines的哈。😁😁😁 ; G) y* j; t. U# p; Y1 t 9 ?' r7 `- O. U/ _3. 调用链图. T5 G0 x+ t E8 c
这么多方法,看起来有点懵懵的吧,我来画一张图,帮助大家理解下这个调用堆栈。) L' K5 i; \, T 1 D, i3 j8 }) M$ k( q9 F
]! {0 c/ \4 N5 ]3 W9 s8 j' f; {+ ?
: F8 G" d4 m4 |6 _+ W+ w
三:总结 * P* C$ @! m X8 A大家一定要熟读架构图,有了架构图从源码中找信息就方便多了,总之学习mysql成就感还是满满的。: X2 F# L$ p6 ~. C5 L# G
———————————————— & x. T- x4 Y3 I2 T3 n版权声明:本文为CSDN博主「一线码农」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。% @, c1 m) J) S) _+ s2 o7 [
原文链接:https://blog.csdn.net/huangxinchen520/article/details/106487415 9 `# S6 j( z0 M