zoukankan      html  css  js  c++  java
  • 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/

  • 相关阅读:
    在C#中实现高性能计时[转]
    序列化(Serializable)的学习
    日常常用英语
    使用javascript灵活控制DIV的位置
    酷我创始人雷鸣:程序员个人成长的四个要素
    String.Format格式说明
    各种类型转换的比较
    学好计算机英语
    AS关键字进行类型转化的优点以及限制
    Spoken English美国人常用的英语口语
  • 原文地址:https://www.cnblogs.com/johnchain/p/2775721.html
Copyright © 2011-2022 走看看