#/sql/Main.cc line 22
//main 函数
int main(int argc, char **argv)
{
return mysqld_main(argc, argv);
}
#/sql/mysqld.cc line 4808
int mysqld_main(int argc, char **argv)
{
/* Start as standalone server */
Service.my_argc=argc;
Service.my_argv=argv;
mysql_service(NULL);
}
#/sql/mysqld.cc line 4709
int mysql_service(void *p)
{
if (my_thread_init())
return 1;
if (use_opt_args)
win_main(opt_argc, opt_argv);
else
win_main(Service.my_argc, Service.my_argv);
my_thread_end();
return 0;
}
#/sql/mysqld.cc line 4278
int mysqld_main(int argc, char **argv)
{
my_init()// init my_sys library & pthreads
load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv)
sys_var_init();
/* Initialize audit interface globals. Audit plugins are inited later. */
mysql_audit_initialize();
/*
Perform basic logger initialization logger. Should be called after
MY_INIT, as it initializes mutexes. Log tables are inited later.
*/
logger.init_base();
init_common_variables()
init_server_components()
init_ssl();
network_init();
start_signal_handler(); // Creates pidfile
init_slave()
initialize_information_schema_acl();
execute_ddl_log_recovery();
create_shutdown_thread();
start_handle_manager();
handle_connections_sockets();//启动监听连接请求
mysqld_exit(0);
}
#/sql/mysqld.cc line 5146
//监听新的连接请求
void handle_connections_sockets()
{
//从代码可见,对epoll和fcntl都提供了支持
#ifdef HAVE_POLL
fds[socket_count].fd= ip_sock;
fds[socket_count].events= POLLIN;
socket_count++;
#else
FD_SET(ip_sock,&clientFDs);
#endif
#ifdef HAVE_FCNTL
ip_flags = fcntl(ip_sock, F_GETFL, 0);
#endif
while (!abort_loop)
{
//在这里创建了THD类,这个类伴随着一个连接线程的一生。
thd= new THD;
//.........
my_net_init(&thd->net,vio_tmp));
//...............
create_new_thread(thd);//针对每个连接请求,创建新的线程
}
}
#/sql/mysqld.cc line 5077
//这个函数的逻辑比较清晰,首先判断是否达到最大连接数,没有的话则创建新线程
static void create_new_thread(THD *thd)
{
/*
Don't allow too many connections. We roughly check here that we allow
only (max_connections + 1) connections.
*/
if (connection_count >= max_connections + 1 || abort_loop)
{
close_connection(thd, ER_CON_COUNT_ERROR);
}
++connection_count;
if (connection_count > max_used_connections)
max_used_connections= connection_count;
/*
The initialization of thread_id is done in create_embedded_thd() for
the embedded library.
TODO: refactor this to avoid code duplication there
*/
/* MYSQL_CALLBACK是一个宏,thread_scheduleer是一个结构体,add_connection是一个函数指针,这个宏调用最后实际执行
thread_scheduler->add_connection(thd);
而在thread_scheduler的初始化过程当中,add_connection指针指向了create_thread_to_handle_connection函数(我的猜测,因为没找到初始化那段代码)
*/
MYSQL_CALLBACK(thread_scheduler, add_connection, (thd));
}
#/sql/mysqld.cc line 5011
void create_thread_to_handle_connection(THD *thd)
{
if (cached_thread_count > wake_thread)
{
/* Get thread from cache */
thread_cache.append(thd);//重用线程池当中的线程
wake_thread++;
mysql_cond_signal(&COND_thread_cache);
}
else{
//创建新的线程,传入的回调函数指针是handle_one_connection,从这个函数开始一个独立的线程。
mysql_thread_create(key_thread_one_connection,&thd->real_id, &connection_attrib,handle_one_connection,(void*) thd)
}
}
#/sql/sql_connect.cc line 700
//这个函数只是do_handle_one_connection的一个包装器
pthread_handler_t handle_one_connection(void *arg)
{
//........
do_handle_one_connection(thd);
//........
}
#/sql/sql_connect.cc line 736
void do_handle_one_connection(THD *thd_arg)
{
//初始化新连接
MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0)
//循环读取用户发送的命令并执行
while (thd_is_connection_alive(thd))
{
do_command(thd)
}
}
#/sql/sql_parse.cc line 668
/**
Read one command from connection and execute it (query or simple command).
This function is called in loop from thread function.
For profiling to work, it must never be called recursively.
*/
bool do_command(THD *thd)
{
NET *net= &thd->net;
//设置读取超时
my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
//读取命令
my_net_read(net)
/* Restore read timeout value */
my_net_set_read_timeout(net, thd->variables.net_read_timeout);
//根据command的类型来分别调用不同的执行逻辑
return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1));
}
#/sql/sql_parse.cc line 866
bool dispatch_command(enum enum_server_command command, THD *thd,char* packet, uint packet_length)
{
switch (command) {
case COM_INIT_DB:
{
}
case COM_REGISTER_SLAVE:
{
}
........
case COM_QUERY:
{
general_log_write(thd, command, thd->query(), thd->query_length());
//解析执行
mysql_parse(thd, thd->query(), thd->query_length(), &parser_state);
while (!thd->killed && (parser_state.m_lip.found_semicolon != NULL) &&! thd->is_error())
{
query_cache_end_of_result(thd);
//记录慢查询日志
log_slow_statement(thd);
//解析执行下一条命令,(用户一次可能发送多条命令)
mysql_parse(thd, beginning_of_next_stmt, length, &parser_state);
}
}
case COM_BINLOG_DUMP:
{
}
..........
}
#/sql/sql_parse.cc line 5467
void mysql_parse(THD *thd, char *rawbuf, uint length,Parser_state *parser_state)
{
//查看查询缓存当中是否已经有内容
if (query_cache_send_result_to_client(thd, rawbuf, length)>= 0){
}
else{
//解析器入口函数,解析查询SQL 调用lex和yacc编译SQL,生成LEX结构体保存编译后SQL的内部结果。
parse_sql(thd, parser_state, NULL); //====>这部分代码比较复杂,需要对lex和yacc比较熟悉,但不影响对后续逻辑的理解
//优化器的入口函数
mysql_execute_command(thd);
}
}
#sql/sql_parse.cc line 1831
int mysql_execute_command(THD *thd)
{
LEX *lex= thd->lex;
switch (lex->sql_command) {
case SQLCOM_SHOW_EVENTS:
//...........
case SQLCOM_SELECT:
{
//查看
check_table_access(thd,privileges_requested,all_tables, FALSE, UINT_MAX, FALSE);
execute_sqlcom_select(thd, all_tables);
}
thd_proc_info(thd, "closing tables");
close_thread_tables(thd);
}
#/sql/sql_parse.cc line 4451
static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
{
//打开并锁定对对应的表
open_and_lock_tables(thd, all_tables, TRUE, 0)
//缓存查询语句,稍后查询的结构也会保存到缓存当中
query_cache_store_query(thd, all_tables);
res= handle_select(thd, lex, result, 0);
}
#define query_cache_store_query(A, B) query_cache.store_query(A, B)
#/sql/sql_select line 265
bool handle_select(THD *thd, LEX *lex, select_result *result,
ulong setup_tables_done_option)
{ res= mysql_select(thd, &select_lex->ref_pointer_array,
select_lex->table_list.first,
select_lex->with_wild, select_lex->item_list,
select_lex->where,
select_lex->order_list.elements +
select_lex->group_list.elements,
select_lex->order_list.first,
select_lex->group_list.first,
select_lex->having,
lex->proc_list.first,
select_lex->options | thd->variables.option_bits |
setup_tables_done_option,
result, unit, select_lex);
}
#/sql/sel_select.cc line 2498
bool
mysql_select(THD *thd, Item ***rref_pointer_array,
TABLE_LIST *tables, uint wild_num, List<Item> &fields,
COND *conds, uint og_num, ORDER *order, ORDER *group,
Item *having, ORDER *proc_param, ulonglong select_options,
select_result *result, SELECT_LEX_UNIT *unit,
SELECT_LEX *select_lex)
{
JOIN *join;
join= select_lex->join;
//优化
join->optimize()
//执行
join->exec();
}
#/sql/sql_select.cc line 1817
void
JOIN::exec(){
error= do_select(curr_join, curr_fields_list, NULL, procedure); #2370
}
#/sql/sql_select.cc line 11401
static int
do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
{
error= sub_select(join,join_tab,0); #11466
}
#/sql/sql_select.cc line 11675
enum_nested_loop_state
sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
{
while (rc == NESTED_LOOP_OK)
{
error= info->read_record(info);
rc= evaluate_join_record(join, join_tab, error);
}
}
#sql/sql_parse.cc line 2839
case SQLCOM_INSERT:
{
if ((res= insert_precheck(thd, all_tables)))
break;
res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
lex->update_list, lex->value_list,
lex->duplicates, lex->ignore);
MYSQL_INSERT_DONE(res, (ulong) thd->get_row_count_func());
/*
If we have inserted into a VIEW, and the base table has
AUTO_INCREMENT column, but this column is not accessible through
a view, then we should restore LAST_INSERT_ID to the value it
had before the statement.
*/
if (first_table->view && !first_table->contain_auto_increment)
thd->first_successful_insert_id_in_cur_stmt=
thd->first_successful_insert_id_in_prev_stmt;
};);
break;
}
#sql/Sql_insert.cc line 649
bool mysql_insert(THD *thd,TABLE_LIST *table_list,
List<Item> &fields,
List<List_item> &values_list,
List<Item> &update_fields,
List<Item> &update_values,
enum_duplicates duplic,
bool ignore)
{
open_and_lock_tables(thd, table_list, TRUE, 0)
mysql_prepare_insert(thd, table_list, table, fields, values,……..)
while ((values= its++))
{
counter++;
if (values->elements != value_count)
{
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
goto abort;
}
if (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0))
goto abort;
}
#line 893
fill_record_n_invoke_before_triggers(thd, fields, *values, 0,
table->triggers,
TRG_EVENT_INSERT))
}
#sql/Sql_base.cc line 8598
fill_record_n_invoke_before_triggers(THD *thd, Field **ptr,
List<Item> &values, bool ignore_errors,
Table_triggers_list *triggers,
enum trg_event_type event)
{
return (fill_record(thd, ptr, values, ignore_errors) ||
(triggers && triggers->process_triggers(thd, event,
TRG_ACTION_BEFORE, TRUE)));
}
#sql/Sql_base.cc line 8424
static bool
fill_record(THD * thd, List<Item> &fields, List<Item> &values,
bool ignore_errors)
{
while ((fld= f++))
{
if (!(field= fld->filed_for_view_update()))
{
my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), fld->name);
goto err;
}
value=v++;
Field *rfield= field->field;
table= rfield->table;
if (rfield == table->next_number_field)
table->auto_increment_field_not_null= TRUE;
if ((value->save_in_field(rfield, 0) < 0) && !ignore_errors)
{
my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0));
goto err;
}
}
DBUG_RETURN(thd->is_error());
picked from:http://luckywhu.blog.163.com/blog/static/184077944201192012836958/