久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

nginx subrequest的實(shí)現(xiàn)解析

 syden1981 2011-08-21

         大家都知道nginx里面有一個(gè)subrequest的概念,,也就是子請(qǐng)求,,它并不是http標(biāo)準(zhǔn)里面的概念,它是在當(dāng)前請(qǐng)求中發(fā)起的一個(gè)新的請(qǐng)求,,它擁有自己的ngx_http_request_t結(jié)構(gòu),,uri和args。一般來(lái)說(shuō)使用subrequest的效率可能會(huì)有些影響,,因?yàn)樗枰匦聫膕erver rewrite開(kāi)始走一遍request處理的PHASE,,但是它在某些情況下使用能給我們帶來(lái)方便,現(xiàn)在我們比較常用的是用subrequest來(lái)訪問(wèn)一個(gè)upstream的后端,,并給它一個(gè)ngx_http_post_subrequest_t的回調(diào)handler,,這樣有點(diǎn)類似于一個(gè)異步的函數(shù)調(diào)用。對(duì)于從upstream返回的數(shù)據(jù),,subrequest允許根據(jù)創(chuàng)建時(shí)指定的flag,,來(lái)決定由用戶自己處理(回調(diào)handler中)還是由upstream模塊直接發(fā)送到out put filter。簡(jiǎn)單的說(shuō)一下subrequest的行為,,nginx使用subrequest訪問(wèn)某個(gè)location,,產(chǎn)生相應(yīng)的數(shù)據(jù),并插入到nginx輸出鏈的相應(yīng)位置(創(chuàng)建subrequest時(shí)的位置),,下面我用agentzh(章亦春,,之前是公司北京同事,最近離職了,,據(jù)說(shuō)回家專心搞開(kāi)源)的echo模塊(https://github.com/agentzh/echo-nginx-module)來(lái)舉例說(shuō)明一下:

 

  1. location /main {  
  2.     echo nginx;  
  3.     echo_location /sub;  
  4.     echo world;  
  5. }  
  6. location /sub {  
  7.     echo hello;  
  8. }  
訪問(wèn)/main,,將得到如下響應(yīng):

 

 

  1. nginx  
  2. hello  
  3. world  
       上面的echo_location指令是發(fā)起一個(gè)subrequest來(lái)訪問(wèn)/sub,,echo指定類似shell里面里面的echo,用來(lái)輸出其后的字符串,,順便說(shuō)一下echo模塊還有其他很多的指令,,這個(gè)模塊在測(cè)試的時(shí)候非常有用。

 

       在進(jìn)行源碼解析之前,,先來(lái)想想如果是我們自己要實(shí)現(xiàn)subrequest的上述行為,,該如何來(lái)做?subrequest還可能有自己的subrequest,,而且每個(gè)subrequest輸出數(shù)據(jù)都不一定是按照其創(chuàng)建的順序來(lái)的,,所以這里簡(jiǎn)單的采用鏈表來(lái)做是不好實(shí)現(xiàn)的,于是我們進(jìn)一步聯(lián)想到可以采用樹(shù)的結(jié)構(gòu)來(lái)做,,主請(qǐng)求即為根節(jié)點(diǎn),,每個(gè)節(jié)點(diǎn)可以有自己的子節(jié)點(diǎn),遍歷某節(jié)點(diǎn)表示處理某請(qǐng)求,,自然的可以想到這里可能是用后根(序)遍歷的方法,,沒(méi)錯(cuò),實(shí)際上Igor采用樹(shù)和鏈表結(jié)合的方式實(shí)現(xiàn)了subrequest的功能,,但是由于節(jié)點(diǎn)(請(qǐng)求)產(chǎn)生數(shù)據(jù)的順序不是固定按節(jié)點(diǎn)創(chuàng)建順序(左->右),,而且可能分多次產(chǎn)生數(shù)據(jù),不能簡(jiǎn)單的用后根(序)遍歷,。Igor使用了2個(gè)鏈表的結(jié)構(gòu)來(lái)實(shí)現(xiàn),,第一個(gè)是每個(gè)請(qǐng)求都有的postponed鏈表,一般情況下每個(gè)鏈表節(jié)點(diǎn)保存了該請(qǐng)求的一個(gè)子請(qǐng)求,,該鏈表節(jié)點(diǎn)定義如下:

 

  1. struct ngx_http_postponed_request_s {  
  2.     ngx_http_request_t               *request;  
  3.     ngx_chain_t                      *out;  
  4.     ngx_http_postponed_request_t     *next;  
  5. };  
        可以看到它有一個(gè)request字段,,可以用來(lái)保存子請(qǐng)求,另外還有一個(gè)ngx_chain_t類型的out字段,,實(shí)際上一個(gè)請(qǐng)求的postponed鏈表里面除了保存子請(qǐng)求的節(jié)點(diǎn),,還有保存該請(qǐng)求自己產(chǎn)生的數(shù)據(jù)的節(jié)點(diǎn),數(shù)據(jù)保存在out字段,;第二個(gè)是posted_requests鏈表,,它掛載了當(dāng)前需要遍歷的請(qǐng)求(節(jié)點(diǎn)), 該鏈表保存在主請(qǐng)求(根節(jié)點(diǎn))的posted_requests字段,,鏈表節(jié)點(diǎn)定義如下:

 

 

  1. struct ngx_http_posted_request_s {  
  2.     ngx_http_request_t               *request;  
  3.     ngx_http_posted_request_t        *next;  
  4. };  
        在ngx_http_run_posted_requests函數(shù)中會(huì)順序的遍歷主請(qǐng)求的posted_requests鏈表:
  1. void  
  2. ngx_http_run_posted_requests(ngx_connection_t *c)  
  3. {  
  4.     ...  
  5.     for ( ;; ) {  
  6.         /* 連接已經(jīng)斷開(kāi),,直接返回 */  
  7.         if (c->destroyed) {  
  8.             return;  
  9.         }  
  10.   
  11.         r = c->data;  
  12.         /* 從posted_requests鏈表的隊(duì)頭開(kāi)始遍歷 */  
  13.         pr = r->main->posted_requests;  
  14.   
  15.         if (pr == NULL) {  
  16.             return;  
  17.         }  
  18.       <pre name="code" class="cpp">        /* 從鏈表中移除即將要遍歷的節(jié)點(diǎn) */  
  19.         r->main->posted_requests = pr->next;  
  20.         /* 得到該節(jié)點(diǎn)中保存的請(qǐng)求 */  
  21.         r = pr->request;  
  22.   
  23.         ctx = c->log->data;  
  24.         ctx->current_request = r;  
  25.   
  26.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,  
  27.                        "http posted request: \"%V?%V\"", &r->uri, &r->args);  
  28.         /* 遍歷該節(jié)點(diǎn)(請(qǐng)求) */  
  29.         r->write_event_handler(r);  
  30.     }  
  31. }  

 


        ngx_http_run_posted_requests函數(shù)的調(diào)用點(diǎn)我后面會(huì)做說(shuō)明。

 

        OK,,了解了一些實(shí)現(xiàn)的原理,,來(lái)看代碼就簡(jiǎn)單多了,現(xiàn)在正式進(jìn)行subrequest的源碼解析, 首先來(lái)看一下創(chuàng)建subrequest的函數(shù)定義:

 

  1. ngx_int_t  
  2. ngx_http_subrequest(ngx_http_request_t *r,  
  3.     ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr,  
  4.     ngx_http_post_subrequest_t *ps, ngx_uint_t flags)  
       參數(shù)r為當(dāng)前的請(qǐng)求,,uri和args為新的要發(fā)起的uri和args,,當(dāng)然args可以為NULL,psr為指向一個(gè)ngx_http_request_t指針的指針,,它的作用就是獲得創(chuàng)建的子請(qǐng)求,,ps的類型為ngx_http_post_subrequest_t,它的定義如下:
  1. typedef struct {  
  2.     ngx_http_post_subrequest_pt       handler;  
  3.     void                             *data;  
  4. } ngx_http_post_subrequest_t;  
  5.   
  6. typedef ngx_int_t (*ngx_http_post_subrequest_pt)(ngx_http_request_t *r,  
  7.     void *data, ngx_int_t rc);  
        它就是之前說(shuō)到的回調(diào)handler,,結(jié)構(gòu)里面的handler類型為ngx_http_post_subrequest_pt,,它是函數(shù)指針,,data為傳遞給handler的額外參數(shù),。再來(lái)看一下ngx_http_subrequest函數(shù)的最后一個(gè)是flags,現(xiàn)在的源碼中實(shí)際上只有2種類型的flag,,分別為NGX_HTTP_SUBREQUEST_IN_MEMORY和NGX_HTTP_SUBREQUEST_WAITED,,第一個(gè)就是指定文章開(kāi)頭說(shuō)到的子請(qǐng)求的upstream處理數(shù)據(jù)的方式,第二個(gè)參數(shù)暫時(shí)不清楚它的具體作用,,源碼中它只對(duì)ssi模塊產(chǎn)生影響,,一般用不到。
        進(jìn)入ngx_http_subrequest函數(shù)內(nèi)部看看:
  1. {  
  2.     ...  
  3.     /* 解析flags,, subrequest_in_memory在upstream模塊解析完頭部,,發(fā)送body給downsstream時(shí)用到 */  
  4.     sr->subrequest_in_memory = (flags & NGX_HTTP_SUBREQUEST_IN_MEMORY) != 0;  
  5.     sr->waited = (flags & NGX_HTTP_SUBREQUEST_WAITED) != 0;  
  6.   
  7.     sr->unparsed_uri = r->unparsed_uri;  
  8.     sr->method_name = ngx_http_core_get_method;  
  9.     sr->http_protocol = r->http_protocol;  
  10.   
  11.     ngx_http_set_exten(sr);  
  12.     /* 主請(qǐng)求保存在main字段中 */  
  13.     sr->main = r->main;  
  14.     /* 父請(qǐng)求為當(dāng)前請(qǐng)求 */     
  15.     sr->parent = r;  
  16.     /* 保存回調(diào)handler及數(shù)據(jù),在子請(qǐng)求執(zhí)行完,,將會(huì)調(diào)用 */  
  17.     sr->post_subrequest = ps;  
  18.     /* 讀事件handler賦值為不做任何事的函數(shù),,因?yàn)樽诱?qǐng)求不用再讀數(shù)據(jù)或者檢查連接狀態(tài);寫(xiě)事件handler為ngx_http_handler,,它會(huì)重走phase */  
  19.     sr->read_event_handler = ngx_http_request_empty_handler;  
  20.     sr->write_event_handler = ngx_http_handler;  
  21.   
  22.     /* ngx_connection_s的data字段比較關(guān)鍵,,它保存了當(dāng)前可以向out chain輸出數(shù)據(jù)的請(qǐng)求,具體意義我后面會(huì)做詳細(xì)介紹 */  
  23.     if (c->data == r && r->postponed == NULL) {  
  24.         c->data = sr;  
  25.     }  
  26.     /* 默認(rèn)共享父請(qǐng)求的變量,,當(dāng)然你也可以根據(jù)需求在創(chuàng)建完子請(qǐng)求后,,再創(chuàng)建子請(qǐng)求獨(dú)立的變量集 */  
  27.     sr->variables = r->variables;  
  28.   
  29.     sr->log_handler = r->log_handler;  
  30.   
  31.     pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t));  
  32.     if (pr == NULL) {  
  33.         return NGX_ERROR;  
  34.     }  
  35.   
  36.     pr->request = sr;  
  37.     pr->out = NULL;  
  38.     pr->next = NULL;  
  39.     /* 把該子請(qǐng)求掛載在其父請(qǐng)求的postponed鏈表的隊(duì)尾 */  
  40.     if (r->postponed) {  
  41.         for (p = r->postponed; p->next; p = p->next) { /* void */ }  
  42.         p->next = pr;  
  43.   
  44.     } else {  
  45.         r->postponed = pr;  
  46.     }  
  47.     /* 子請(qǐng)求為內(nèi)部請(qǐng)求,它可以訪問(wèn)internal類型的location */  
  48.     sr->internal = 1;  
  49.     /* 繼承父請(qǐng)求的一些狀態(tài) */  
  50.     sr->discard_body = r->discard_body;  
  51.     sr->expect_tested = 1;  
  52.     sr->main_filter_need_in_memory = r->main_filter_need_in_memory;  
  53.   
  54.     sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1;  
  55.   
  56.     tp = ngx_timeofday();  
  57.     r->start_sec = tp->sec;  
  58.     r->start_msec = tp->msec;  
  59.   
  60.     r->main->subrequests++;  
  61.     /* 增加主請(qǐng)求的引用數(shù),,這個(gè)字段主要是在ngx_http_finalize_request調(diào)用的一些結(jié)束請(qǐng)求和連接的函數(shù)中使用 */  
  62.     r->main->count++;  
  63.   
  64.     *psr = sr;  
  65.     /* 將該子請(qǐng)求掛載在主請(qǐng)求的posted_requests鏈表隊(duì)尾 */  
  66.     return ngx_http_post_request(sr, NULL);  
  67. }  

 

         好了,,子請(qǐng)求創(chuàng)建完畢,一般來(lái)說(shuō)子請(qǐng)求的創(chuàng)建都發(fā)生在某個(gè)請(qǐng)求的content handler或者某個(gè)filter內(nèi),,從上面的函數(shù)可以看到子請(qǐng)求并沒(méi)有馬上被執(zhí)行,,只是被掛載在了主請(qǐng)求的posted_requests鏈表中,那它什么時(shí)候可以執(zhí)行呢,?之前說(shuō)到posted_requests鏈表是在ngx_http_run_posted_requests函數(shù)中遍歷,,那么ngx_http_run_posted_requests函數(shù)又是在什么時(shí)候調(diào)用?它實(shí)際上是在某個(gè)請(qǐng)求的讀(寫(xiě))事件的handler中,執(zhí)行完該請(qǐng)求相關(guān)的處理后被調(diào)用,,比如主請(qǐng)求在走完一遍PHASE的時(shí)候會(huì)調(diào)用ngx_http_run_posted_requests,,這時(shí)子請(qǐng)求得以運(yùn)行。

         這時(shí)實(shí)際還有1個(gè)問(wèn)題需要解決,,由于nginx是多進(jìn)程,,是不能夠隨意阻塞的(如果一個(gè)請(qǐng)求阻塞了當(dāng)前進(jìn)程,就相當(dāng)于阻塞了這個(gè)進(jìn)程accept到的所有其他請(qǐng)求,,同時(shí)該進(jìn)程也不能accept新請(qǐng)求),,一個(gè)請(qǐng)求可能由于某些原因需要阻塞(比如訪問(wèn)io),nginx的做法是設(shè)置該請(qǐng)求的一些狀態(tài)并在epoll中添加相應(yīng)的事件,,然后轉(zhuǎn)去處理其他請(qǐng)求,,等到該事件到來(lái)時(shí)再繼續(xù)處理該請(qǐng)求,這樣的行為就意味著一個(gè)請(qǐng)求可能需要多次執(zhí)行機(jī)會(huì)才能完成,,對(duì)于一個(gè)請(qǐng)求的多個(gè)子請(qǐng)求來(lái)說(shuō),,意味著它們完成的先后順序可能和它們創(chuàng)建的順序是不一樣的,所以必須有一種機(jī)制讓提前完成的子請(qǐng)求保存它產(chǎn)生的數(shù)據(jù),,而不是直接輸出到out chain,,同時(shí)也能夠讓當(dāng)前能夠往out chain輸出數(shù)據(jù)的請(qǐng)求及時(shí)的輸出產(chǎn)生的數(shù)據(jù)。作者Igor采用ngx_connection_t中的data字段,,以及一個(gè)body filter,,即ngx_http_postpone_filter,還有ngx_http_finalize_request函數(shù)中的一些邏輯來(lái)解決這個(gè)問(wèn)題,。

        下面我用一個(gè)圖來(lái)做說(shuō)明,,下圖是某時(shí)刻某個(gè)主請(qǐng)求和它的所有子孫請(qǐng)求的樹(shù)結(jié)構(gòu):

       

         圖中的root節(jié)點(diǎn)即為主請(qǐng)求,它的postponed鏈表從左至右掛載了3個(gè)節(jié)點(diǎn),,SUB1是它的第一個(gè)子請(qǐng)求,,DATA1是它產(chǎn)生的一段數(shù)據(jù),SUB2是它的第2個(gè)子請(qǐng)求,,而且這2個(gè)子請(qǐng)求分別有它們自己的子請(qǐng)求及數(shù)據(jù),。ngx_connection_t中的data字段保存的是當(dāng)前可以往out chain發(fā)送數(shù)據(jù)的請(qǐng)求,文章開(kāi)頭說(shuō)到發(fā)到客戶端的數(shù)據(jù)必須按照子請(qǐng)求創(chuàng)建的順序發(fā)送,,這里即是按后續(xù)遍歷的方法(SUB11->DATA11->SUB12->DATA12->(SUB1)->DATA1->SUB21->SUB22->(SUB2)->(ROOT)),,上圖中當(dāng)前能夠往客戶端(out chain)發(fā)送數(shù)據(jù)的請(qǐng)求顯然就是SUB11,如果SUB12提前執(zhí)行完成,,并產(chǎn)生數(shù)據(jù)DATA121,,只要前面它還有節(jié)點(diǎn)未發(fā)送完畢,DATA121只能先掛載在SUB12的postponed鏈表下,。這里還要注意一下的是c->data的設(shè)置,,當(dāng)SUB11執(zhí)行完并且發(fā)送完數(shù)據(jù)之后,,下一個(gè)將要發(fā)送的節(jié)點(diǎn)應(yīng)該是DATA11,但是該節(jié)點(diǎn)實(shí)際上保存的是數(shù)據(jù),,而不是子請(qǐng)求,,所以c->data這時(shí)應(yīng)該指向的是擁有改數(shù)據(jù)節(jié)點(diǎn)的SUB1請(qǐng)求。

        下面看下源碼具體是怎樣實(shí)現(xiàn)的,,首先是ngx_http_postpone_filter函數(shù):

  1. static ngx_int_t  
  2. ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in)  
  3. {  
  4.     ...  
  5.     /* 當(dāng)前請(qǐng)求不能往out chain發(fā)送數(shù)據(jù),,如果產(chǎn)生了數(shù)據(jù),新建一個(gè)節(jié)點(diǎn),,將它保存在當(dāng)前請(qǐng)求的postponed隊(duì)尾,。這樣就保證了數(shù)據(jù)按序發(fā)到客戶端 */  
  6.     if (r != c->data) {     
  7.   
  8.         if (in) {  
  9.             ngx_http_postpone_filter_add(r, in);  
  10.             return NGX_OK;  
  11.         }  
  12.         ...  
  13.         return NGX_OK;  
  14.     }  
  15.     /* 到這里,表示當(dāng)前請(qǐng)求可以往out chain發(fā)送數(shù)據(jù),,如果它的postponed鏈表中沒(méi)有子請(qǐng)求,,也沒(méi)有數(shù)據(jù), 
  16.        則直接發(fā)送當(dāng)前產(chǎn)生的數(shù)據(jù)in或者繼續(xù)發(fā)送out chain中之前沒(méi)有發(fā)送完成的數(shù)據(jù) */  
  17.     if (r->postponed == NULL) {    
  18.                                   
  19.         if (in || c->buffered) {  
  20.             return ngx_http_next_filter(r->main, in);  
  21.         }  
  22.         /* 當(dāng)前請(qǐng)求沒(méi)有需要發(fā)送的數(shù)據(jù) */  
  23.         return NGX_OK;  
  24.     }  
  25.     /* 當(dāng)前請(qǐng)求的postponed鏈表中之前就存在需要處理的節(jié)點(diǎn),,則新建一個(gè)節(jié)點(diǎn),,保存當(dāng)前產(chǎn)生的數(shù)據(jù)in,,并將它插入到postponed隊(duì)尾 */  
  26.     if (in) {    
  27.         ngx_http_postpone_filter_add(r, in);  
  28.     }  
  29.     /* 處理postponed鏈表中的節(jié)點(diǎn) */  
  30.     do {     
  31.         pr = r->postponed;  
  32.         /* 如果該節(jié)點(diǎn)保存的是一個(gè)子請(qǐng)求,,則將它加到主請(qǐng)求的posted_requests鏈表中,以便下次調(diào)用ngx_http_run_posted_requests函數(shù),,處理該子節(jié)點(diǎn) */  
  33.         if (pr->request) {  
  34.   
  35.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,  
  36.                            "http postpone filter wake \"%V?%V\"",  
  37.                            &pr->request->uri, &pr->request->args);  
  38.   
  39.             r->postponed = pr->next;  
  40.   
  41.             /* 按照后續(xù)遍歷產(chǎn)生的序列,,因?yàn)楫?dāng)前請(qǐng)求(節(jié)點(diǎn))有未處理的子請(qǐng)求(節(jié)點(diǎn)),必須先處理完改子請(qǐng)求,,才能繼續(xù)處理后面的子節(jié)點(diǎn),。 
  42.                這里將該子請(qǐng)求設(shè)置為可以往out chain發(fā)送數(shù)據(jù)的請(qǐng)求。  */  
  43.             c->data = pr->request;  
  44.             /* 將該子請(qǐng)求加入主請(qǐng)求的posted_requests鏈表 */  
  45.             return ngx_http_post_request(pr->request, NULL);  
  46.         }  
  47.         /* 如果該節(jié)點(diǎn)保存的是數(shù)據(jù),,可以直接處理該節(jié)點(diǎn),,將它發(fā)送到out chain */  
  48.         if (pr->out == NULL) {  
  49.             ngx_log_error(NGX_LOG_ALERT, c->log, 0,  
  50.                           "http postpone filter NULL output",  
  51.                           &r->uri, &r->args);  
  52.   
  53.         } else {  
  54.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,  
  55.                            "http postpone filter output \"%V?%V\"",  
  56.                            &r->uri, &r->args);  
  57.   
  58.             if (ngx_http_next_filter(r->main, pr->out) == NGX_ERROR) {  
  59.                 return NGX_ERROR;  
  60.             }  
  61.         }  
  62.   
  63.         r->postponed = pr->next;  
  64.   
  65.     } while (r->postponed);  
  66.   
  67.     return NGX_OK;  
  68. }  

 


          再來(lái)看ngx_http_finalzie_request函數(shù):

  1. void  
  2. ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)   
  3. {  
  4.   ...  
  5.     /* 如果當(dāng)前請(qǐng)求是一個(gè)子請(qǐng)求,檢查它是否有回調(diào)handler,,有的話執(zhí)行之 */  
  6.     if (r != r->main && r->post_subrequest) {  
  7.         rc = r->post_subrequest->handler(r, r->post_subrequest->data, rc);  
  8.     }  
  9.   
  10.   ...  
  11.       
  12.     /* 子請(qǐng)求 */  
  13.     if (r != r->main) {    
  14.         /* 該子請(qǐng)求還有未處理完的數(shù)據(jù)或者子請(qǐng)求 */  
  15.         if (r->buffered || r->postponed) {  
  16.             /* 添加一個(gè)該子請(qǐng)求的寫(xiě)事件,,并設(shè)置合適的write event hander,以便下次寫(xiě)事件來(lái)的時(shí)候繼續(xù)處理,, 
  17.                這里實(shí)際上下次執(zhí)行時(shí)會(huì)調(diào)用ngx_http_output_filter函數(shù),,最終還是會(huì)進(jìn)入ngx_http_postpone_filter進(jìn)行處理 */  
  18.             if (ngx_http_set_write_handler(r) != NGX_OK) {  
  19.                 ngx_http_terminate_request(r, 0);  
  20.             }  
  21.   
  22.             return;  
  23.         }  
  24.         ...  
  25.                 
  26.         pr = r->parent;  
  27.           
  28.   
  29.         /* 該子請(qǐng)求已經(jīng)處理完畢,如果它擁有發(fā)送數(shù)據(jù)的權(quán)利,,則將權(quán)利移交給父請(qǐng)求,, */  
  30.         if (r == c->data) {   
  31.   
  32.             r->main->count--;  
  33.   
  34.             if (!r->logged) {  
  35.   
  36.                 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);  
  37.   
  38.                 if (clcf->log_subrequest) {  
  39.                     ngx_http_log_request(r);  
  40.                 }  
  41.   
  42.                 r->logged = 1;  
  43.   
  44.             } else {  
  45.                 ngx_log_error(NGX_LOG_ALERT, c->log, 0,  
  46.                               "subrequest: \"%V?%V\" logged again",  
  47.                               &r->uri, &r->args);  
  48.             }  
  49.   
  50.             r->done = 1;  
  51.             /* 如果該子請(qǐng)求不是提前完成,則從父請(qǐng)求的postponed鏈表中刪除 */  
  52.             if (pr->postponed && pr->postponed->request == r) {  
  53.                 pr->postponed = pr->postponed->next;  
  54.             }  
  55.             /* 將發(fā)送權(quán)利移交給父請(qǐng)求,,父請(qǐng)求下次執(zhí)行的時(shí)候會(huì)發(fā)送它的postponed鏈表中可以發(fā)送的數(shù)據(jù)節(jié)點(diǎn),,或者將發(fā)送權(quán)利移交給它的下一個(gè)子請(qǐng)求 */  
  56.             c->data = pr;     
  57.   
  58.         } else {  
  59.             /* 到這里其實(shí)表明該子請(qǐng)求提前執(zhí)行完成,而且它沒(méi)有產(chǎn)生任何數(shù)據(jù),則它下次再次獲得執(zhí)行機(jī)會(huì)時(shí),,將會(huì)執(zhí)行ngx_http_request_finalzier函數(shù),, 
  60.                它實(shí)際上是執(zhí)行ngx_http_finalzie_request(r,0),也就是什么都不干,,直到輪到它發(fā)送數(shù)據(jù)時(shí),,ngx_http_finalzie_request函數(shù)會(huì)將它從 
  61.                父請(qǐng)求的postponed鏈表中刪除 */  
  62.             r->write_event_handler = ngx_http_request_finalizer;  
  63.   
  64.             if (r->waited) {  
  65.                 r->done = 1;  
  66.             }  
  67.         }  
  68.         /* 將父請(qǐng)求加入posted_request隊(duì)尾,獲得一次運(yùn)行機(jī)會(huì) */  
  69.         if (ngx_http_post_request(pr, NULL) != NGX_OK) {  
  70.             r->main->count++;  
  71.             ngx_http_terminate_request(r, 0);  
  72.             return;  
  73.         }  
  74.   
  75.         return;  
  76.     }  
  77.     /* 這里是處理主請(qǐng)求結(jié)束的邏輯,,如果主請(qǐng)求有未發(fā)送的數(shù)據(jù)或者未處理的子請(qǐng)求,,則給主請(qǐng)求添加寫(xiě)事件,并設(shè)置合適的write event hander,, 
  78.        以便下次寫(xiě)事件來(lái)的時(shí)候繼續(xù)處理 */  
  79.     if (r->buffered || c->buffered || r->postponed || r->blocked) {  
  80.   
  81.         if (ngx_http_set_write_handler(r) != NGX_OK) {  
  82.             ngx_http_terminate_request(r, 0);  
  83.         }  
  84.   
  85.         return;  
  86.     }  
  87.   
  88.  ...  
  89. }   

 


           總結(jié)一下,,nginx的subrequest的代碼實(shí)現(xiàn)還是稍有些難懂,但是如果先了解了它的原理思想,,再看代碼就不難理解了,。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多