Ningxコード研究(四)


コードの理解は混乱していますが、使用は簡単です.hashの作成とhashでの検索の2つの操作がよく使われています.hashの作成の操作では、一般的に次のようになります.
  • ngx_を構築hash_key_tはメンバーの配列であり、key、value、およびkeyを用いて計算されたhash値
  • を含む.
  • ngx_を構築hash_init_t構造体の変数で、ngx_が含まれています.hash_tのメンバーは、hashの構造体であり、bucketのサイズ、メモリプールなどの
  • などの他の初期設定も含む.
  • 呼び出しngx_hash_init転送ngx_hash_init_t構造、ngx_hash_key_tの配列と配列の長さを初期化し、ngx_hash_init_tのhashメンバーは、我々が望むhash構造
  • である.
    検索のプロセスは簡単です
  • keyのhash値
  • を計算する
  • ngx_を使用hash_findは検索を行い、hash値とkeyを同時に入力する必要があり、valueのポインタ
  • を返す.
     
    なお、nginxのhashは、検索時にバケツ後線形検索法を用いるため、バケツ数が決定されると、検索効率はその中の総key−val対数に反比例する.
    次はいくつかのdemoコードです(svnから見つけることができます)
    #include <stdio.h>
    #include "ngx_config.h"
    #include "ngx_conf_file.h"
    #include "nginx.h"
    #include "ngx_core.h"
    #include "ngx_string.h"
    #include "ngx_palloc.h"
    #include "ngx_array.h"
    #include "ngx_hash.h"
    volatile ngx_cycle_t  *ngx_cycle;
    void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, const char *fmt, ...) { }
    
    
    static ngx_str_t names[] = {ngx_string("rainx"),
                                ngx_string("xiaozhe"),
                                ngx_string("zhoujian")};
    static char* descs[] = {"rainx's id is 1","xiaozhe's id is 2","zhoujian's id is 3"};
    
    // hash table       
    int main()
    {
        ngx_uint_t          k; //, p, h;
        ngx_pool_t*         pool;
        ngx_hash_init_t     hash_init;
        ngx_hash_t*         hash;
        ngx_array_t*        elements;
        ngx_hash_key_t*     arr_node;
        char*               find;
        int                 i;
    
        ngx_cacheline_size = 32;
        // hash key cal start
        ngx_str_t str       = ngx_string("hello, world");
        k                   = ngx_hash_key_lc( str.data, str.len);
        pool                = ngx_create_pool(1024*10, NULL);
        printf("caculated key is %u 
    "
    , k);     // hask key cal end     //     hash = (ngx_hash_t*) ngx_pcalloc(pool, sizeof(hash));     hash_init.hash      = hash;                      // hash     hash_init.key       = &ngx_hash_key_lc;          // hash     hash_init.max_size  = 1024*10;                   // max_size     hash_init.bucket_size = 64; // ngx_align(64, ngx_cacheline_size);     hash_init.name      = "yahoo_guy_hash";          // log     hash_init.pool           = pool;                 //     hash_init.temp_pool      = NULL;     //     elements = ngx_array_create(pool, 32, sizeof(ngx_hash_key_t));     for(i = 0; i < 3; i++) {         arr_node            = (ngx_hash_key_t*) ngx_array_push(elements);         arr_node->key       = (names[i]);         arr_node->key_hash  = ngx_hash_key_lc(arr_node->key.data, arr_node->key.len);         arr_node->value     = (void*) descs[i];         //         printf("key: %s , key_hash: %u
    "
    , arr_node->key.data, arr_node->key_hash);     }     if (ngx_hash_init(&hash_init, (ngx_hash_key_t*) elements->elts, elements->nelts)!=NGX_OK){         return 1;     }     //     k    = ngx_hash_key_lc(names[0].data, names[0].len);     printf("%s key is %d
    "
    , names[0].data, k);     find = (char*)         ngx_hash_find(hash, k, (u_char*) names[0].data, names[0].len);     if (find) {         printf("get desc of rainx: %s
    "
    , (char*) find);     }     ngx_array_destroy(elements);     ngx_destroy_pool(pool);     return 0; }

    実行結果
    rainx@rainx-laptop:~/land/nginxsrp/src/demo/basic_types$ ./hash_op 
    caculated key is 3654358412 
    key: rainx , key_hash: 108275556
    key: xiaozhe , key_hash: 2225329080
    key: zhoujian , key_hash: 3269715264
    rainx key is 108275556
    get desc of rainx: rainx's id is 1

    ngx_list
    ngx_listの構造は複雑ではありません.ngxは私たちのためにngxをカプセル化しました.list_create, ngx_list_init,およびngx_list_pushなど(作成,初期化,追加)操作は,我々にとって最もよく用いられる遍歴操作であるが,以下はnginxの注釈で述べた遍歴の例である.
       part = &list.part;
       data = part->elts;
     
       for (i = 0 ;; i++) {
     
           if (i >= part->nelts) {
               if (part->next == NULL) {
                   break;
               }
     
               part = part->next;
               data = part->elts;
               i = 0;
           }
     
           ...  data[i] ...
     
       }

    nginxのcore moduleの構造と実行メカニズムを理解する
    参考資料
    このtaskの勉強を始めたとき、langwanさんの前のnginxのソースコードの研究資料を検索して発見しました.参考になりましたので、私たちの仕事を大幅に節約しました.本章の進行に役立つのは、次のいくつかの文章だと思います.
  • nginxソースコード分析  http://hi.baidu.com/langwan/blog/item/6b18ef24cd859e064c088d28.html
  • nginxバッファ構造  http://hi.baidu.com/langwan/blog/item/822b758d5d1d9a1ab31bbaf8.html
  • Nginxソース分析-ログ処理  http://hi.baidu.com/langwan/blog/item/7e7db51978e04e4d43a9ad32.html

  • Debug情報の出力
    研究を容易にするためにnginxのdebug情報を開き,再コンパイルする
    rainx@rainx-laptop:~/land/nginx-0.7.61$ ./configure --prefix=/home/rainx/land/test --with-debug

    次にnginx.confを変更します
    worker_processes  2; 
    error_log  logs/error.log  debug;

    Debug情報のサポートを開き、2つのworkerプロセスを使用してlog情報を表示してnginxの実行状況を把握します.
    上記の構成情報に基づいて、簡単なhttpアクセス操作と組み合わせて、ここに記録しました.  logログの例
    ngx_init_cycle
    重要な関数呼び出しの1つは、kscope出力を使用する彼の呼び出し関係であるngx_init_cycleであり、main、ngx_master_process_cycle、ngx_single_process_cycleであり、後者はreconfigureのときに呼び出される
    彼は主に以下のことをしました.
       cycle      cycle init_cycleold cycle   log               ,  pool, shared mem, file handler, listening socket cycle    

    また、ngx_master/single_process_cycleではinit_processが呼び出され、ngx_process_events_and_timersがループして呼び出されます.ここでngx_process_events(cycle,timer,flags)が呼び出されます.イベントループのpolliing時間は一般的に500 msがデフォルトです
    nginxのhttp core moduleの構造と実行メカニズムを理解する
    HTTP関連のModuleはすべてsrc/httpディレクトリとそのサブディレクトリの下にあり、src/http下のファイルはhttpモジュールのコアファイルであり、src/http/modules下のファイルはhttpモジュールの拡張モジュールである.
    次のようになります.
    ngx_http.[c|h]
    ngx_http.cには、httpという命令の処理モジュールが登録されており、ngx_http_block関数に対応
    static ngx_command_t  ngx_http_commands[] = {
    
        { ngx_string("http"),
          NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
          ngx_http_block,
          0,
          0,
          NULL },
    
          ngx_null_command
    };

    この関数ではconfリソース割り当て/Merge、プロファイル解析などの作業が行われます.nginx httpに登録されているphase handlerが重要な作業です
        if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {
            return NGX_CONF_ERROR;
        }

    phase handlerのタイプは、ngx_http_core_moduleで定義します.
    typedef enum {
        NGX_HTTP_POST_READ_PHASE = 0,
    
        NGX_HTTP_SERVER_REWRITE_PHASE,
    
        NGX_HTTP_FIND_CONFIG_PHASE,
        NGX_HTTP_REWRITE_PHASE,
        NGX_HTTP_POST_REWRITE_PHASE,
    
        NGX_HTTP_PREACCESS_PHASE,
    
        NGX_HTTP_ACCESS_PHASE,
        NGX_HTTP_POST_ACCESS_PHASE,
    
        NGX_HTTP_TRY_FILES_PHASE,
        NGX_HTTP_CONTENT_PHASE,
    
        NGX_HTTP_LOG_PHASE
    } ngx_http_phases;

    各phaseのhandlersは配列で、複数の要素を含んでngx_array_pushで新しいhandlerを追加できます.
    各phaseの処理の多くは、ngx_request_tのwriteまたはread eventの書き換えを含む.
    ngx_http_core_content_phaseには、r->content_handlerが実行時刻にlocation handlerから登録されているlocation handlerへの呼び出しがあります.
        if (r->content_handler) {
            r->write_event_handler = ngx_http_request_empty_handler;
            ngx_http_finalize_request(r, r->content_handler(r)); /*         */
            return NGX_OK;
        }

    ここで,各phaseの終了段階では,一般に呼び出しである.
        r->phase_handler++;
        return NGX_AGAIN;

    requestのphase_handlerのポインタを移動し、メインプログラムの続行を示します.
    ここではphase handlerでもlocation handlerでもプログラムに登録できます.
    また、ngx_http_blockでは、listeningとconnectionに関連する変数を初期化およびチューニングし、最終的にngx_http_add_listening(ngx_http_add_listening呼び出し)にlisteningを登録したhandlerがngx_http_init_connectionとなるngx_http_optimize_serversが呼び出される
        ls->handler = ngx_http_init_connection;

    ngx_http_init_connectionはngx_http_request.cで定義されていますが、詳細は後述します
    ngx_http_request.[c|h]
    ここで、ngx_http_init_connectionはconnectionイベントの読み出し操作のコールバック関数を登録し、書き込み操作を空の関数に設定します
        rev = c->read;
        rev->handler = ngx_http_init_request;
        c->write->handler = ngx_http_empty_handler;

    新しい接続が入ると、ngx_http_init_requestに実行され、主にrevのhandlerがngx_http_process_request_lineに設定され、ngx_http_process_request_lineがngx_http_process_request_lineにスケジューリングされ、ngx_http_process_request関数が読み出されたeventが処理されます.、ngx_http_process_request_headersではhttpのリクエストヘッダが解析され、ngx_http_process_requestはevent handlerからngx_http_request_handlerに設定され、ngx_http_request_handlerではイベントの読み取りか書き込みかの操作に応じてrequestのread_event_handlerとwrite_event_handlerが呼び出されるので、後続プログラムではrequestのread/writeevent_handler調整は本質的にrevとwevのhandlerの調整に似ているが、コールバック関数のパラメータは、以前のngx_event_tではなくngx_request_tに変更されるだけである.
        c->read->handler = ngx_http_request_handler;
        c->write->handler = ngx_http_request_handler;
        r->read_event_handler = ngx_http_block_reading;

    上記のコードから分かるように、モジュールはngx_http_block_readingというhandlerを使用して後続の読み取り要求を処理し始めた.
    イベントの登録が完了すると、ngx_http_process_requestは次の2つの関数をそれぞれ呼び出します.
        ngx_http_handler(r);
        ngx_http_run_posted_requests(c);

    ここで、ngx_http_handlerは、ngx_http_core_moduleで定義され、プロセッサのプライマリリクエスト、ngx_http_run_posted_requestsは、ngx_http_request.cで定義され、コミットされたすべてのサブリクエストデータの出力を処理する.
    ngx_http_core_module.[c|h]
    ngx_http_core_moduleはhttpモジュールの中で比較的重要なモジュールであり、彼自身はNGX_HTTP_MODULE(ngx_http_moduleとは異なり、ngx_http_moduleは本質的にNGX_CORE_MODULEである
    ここでは、server、locationなど、http blockの次のコマンドを処理します.また、上記のngx_http_handlerもここにあります.
    ngx_http_handlerの最も核心的な仕事は、最後に呼び出され、write eventをngx_http_core_run_phasesに設定し、各段階のhandlerの順次処理を開始することである.
    handler処理が完了するとhttpの処理フローもほぼ完了する.
        while (ph[r->phase_handler].checker) {
    
            rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
    
            if (rc == NGX_OK) {
                return;
            }
        }

    run_phasesのプロセスは実際には非常に簡単で、各handlerを一度に実行し、任意のhandlerがokまたはすべてのhandlerの実行が完了すると、プロセス全体が終了します.
    ここで、phの下付き文字の変化は、r->phase_handler変数によって決まるので、各handler内部で、次のhandlerをメインプログラムで処理し続けるには、手動のr->phase_handler++が必要であり、phase handler配列の下付き文字を次のメンバーに移すことに注意してください.