在二十一節中,提到過調用ngx_eventfind_timer()擷取timer,然後傳遞給epoll模組,做等待時間,今天我們主要講解下這個方法。
本文來自於:http://blog.csdn.net/lengzijian
nginx中的timer用紅/黑樹狀結構的結構排序。ngx_event_timer_rbtree就是nginx中timer的紅/黑樹狀結構。
1.下面我們來看一下ngx_event_timer_rbtree的結構:
src/core/ngx_rbtree.htypedef struct ngx_rbtree_s ngx_rbtree_t;typedef void (*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);struct ngx_rbtree_s { ngx_rbtree_node_t *root; //根節點 ngx_rbtree_node_t *sentinel; //哨兵節點 ngx_rbtree_insert_pt insert; //插入方法指標};
2.樹中節點的結構:
src/core/ngx_rbtree.htypedef ngx_uint_t ngx_rbtree_key_t;typedef ngx_int_t ngx_rbtree_key_int_t;typedef struct ngx_rbtree_node_s ngx_rbtree_node_t;struct ngx_rbtree_node_s { ngx_rbtree_key_t key; ngx_rbtree_node_t *left; //左節點 ngx_rbtree_node_t *right; //右節點 ngx_rbtree_node_t *parent; //父節點 u_char color; //當前節點顏色 u_char data; //當前節點資料};
3.ngx_event_find_timer函數:
src/event/ngx_event_timer.cngx_msec_tngx_event_find_timer(void){ ngx_msec_int_t timer; ngx_rbtree_node_t *node, *root, *sentinel; //如果根節點地址等於哨兵將節點地址,返回-1 if (ngx_event_timer_rbtree.root == &ngx_event_timer_sentinel) { return NGX_TIMER_INFINITE; } //對ngx_event_timer_mutex上鎖 ngx_mutex_lock(ngx_event_timer_mutex); root = ngx_event_timer_rbtree.root; sentinel = ngx_event_timer_rbtree.sentinel; //擷取最小的timer界定 node = ngx_rbtree_min(root, sentinel); //解鎖 ngx_mutex_unlock(ngx_event_timer_mutex); //用最小值的timer節點的值減去ngx_current_mses值 timer = (ngx_msec_int_t) node->key - (ngx_msec_int_t) ngx_current_msec; return (ngx_msec_t) (timer > 0 ? timer : 0);}
nginx中,當前所有可能被觸發的定時器被儲存在紅/黑樹狀結構這種資料結構中,通過紅/黑樹狀結構,你可以很快的得到距離當前最快發生的定時器時間的時間差,將這個時間差作為select/poll/epoll等函數的參數,也就是說最多等待這麼長時間就返回。得到函數調用總共花費了多少時間,根據這個時間取出紅/黑樹狀結構的根節點比較查看是否應該觸發該定時器時間,如果可以,則將定時器從紅/黑樹狀結構中刪除,然後繼續查看新的成為樹根的定時器的節點,這個過程一直進行下去,知道沒有定時器滿足被觸發條件,也就是還沒有被觸發的事件。
nginx中,新接收了一個串連,就會儲存這個串連上來的時間,並且以這個時間來加入紅/黑樹狀結構定時器。