MySQL源代码分析:(1)Main函数

#/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/

原文地址:https://www.cnblogs.com/johnchain/p/2775721.html