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から見つけることができます)
実行結果
ngx_list
ngx_listの構造は複雑ではありません.ngxは私たちのためにngxをカプセル化しました.list_create, ngx_list_init,およびngx_list_pushなど(作成,初期化,追加)操作は,我々にとって最もよく用いられる遍歴操作であるが,以下はnginxの注釈で述べた遍歴の例である.
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情報を開き,再コンパイルする
次にnginx.confを変更します
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のときに呼び出される
彼は主に以下のことをしました.
また、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関数に対応
この関数ではconfリソース割り当て/Merge、プロファイル解析などの作業が行われます.nginx httpに登録されているphase handlerが重要な作業です
phase handlerのタイプは、ngx_http_core_moduleで定義します.
各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への呼び出しがあります.
ここで,各phaseの終了段階では,一般に呼び出しである.
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が呼び出される
ngx_http_init_connectionはngx_http_request.cで定義されていますが、詳細は後述します
ngx_http_request.[c|h]
ここで、ngx_http_init_connectionはconnectionイベントの読み出し操作のコールバック関数を登録し、書き込み操作を空の関数に設定します
新しい接続が入ると、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に変更されるだけである.
上記のコードから分かるように、モジュールはngx_http_block_readingというhandlerを使用して後続の読み取り要求を処理し始めた.
イベントの登録が完了すると、ngx_http_process_requestは次の2つの関数をそれぞれ呼び出します.
ここで、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の処理フローもほぼ完了する.
run_phasesのプロセスは実際には非常に簡単で、各handlerを一度に実行し、任意のhandlerがokまたはすべてのhandlerの実行が完了すると、プロセス全体が終了します.
ここで、phの下付き文字の変化は、r->phase_handler変数によって決まるので、各handler内部で、次のhandlerをメインプログラムで処理し続けるには、手動のr->phase_handler++が必要であり、phase handler配列の下付き文字を次のメンバーに移すことに注意してください.
検索のプロセスは簡単です
なお、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のソースコードの研究資料を検索して発見しました.参考になりましたので、私たちの仕事を大幅に節約しました.本章の進行に役立つのは、次のいくつかの文章だと思います.
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_cycle, old 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配列の下付き文字を次のメンバーに移すことに注意してください.