ngx的基本容器
ngx_array
對應的文件為 core/ngx_array.{c|h}
ngx_array是nginx內部封裝的使用 ngx_pool_t對內存池進行分配的數組容器,其中的數據是在一整片內存區中連續存放的。更新數組時只能在尾部壓入1個或多個元素。
數組的實現結構為
struct ngx_array_s { ? ? void ? ? ? ? * elts ; ? ? ngx_uint_t ? nelts ; ? ? size_t ? ? ? size ; ? ? ngx_uint_t ? nalloc ; ? ? ngx_pool_t ? * pool ; };
其中 elts 為具體的數據區域的指針, nelts 為數組實際包含的元素數量, size為數組單個元素的大小, nalloc為數組容器預先(或者重新)分配的內存大小, pool 為分配基于的內存池
常用的操作有
// 創建一個新的數組容器 ngx_array_t * ngx_array_create ( ngx_pool_t * p , ngx_uint_t n , size_t size );
// 銷毀數組容器 void ngx_array_destroy ( ngx_array_t * a );
// 將新的元素加入數組容器 void * ngx_array_push ( ngx_array_t * a ); void * ngx_array_push_n ( ngx_array_t * a , ngx_uint_t n ); //返回n個元素的指針
這里需要注意的是,和之前的ngx_pool_cleanup_add一樣, ngx_array_push只是進行內存分配的操作,我們需要對返回的指針指向的地址進行賦值等操作來實現實際數組值的添加。
具體一點的push操作的實現為,
- 首先判斷 nalloc是否和nelts相等,即數組預先分配的空間已經滿了,如果沒滿則計算地址直接返回指針
- 如果已經滿了則先判斷是否我們的pool中的當前鏈表節點還有剩余的空間,如果有則直接在當前的pool鏈表節點中分配內存,并返回
- 如果當前鏈表節點沒有足夠的空間則使用ngx_palloc重新分配一個2倍于之前數組空間大小的數組,然后將數據轉移過來,并返回新地址的指針
下面是一個array的例子:
demo/basic_types/array_and_hash.c
#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" 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 , ...) { } int main () { ? ?ngx_pool_t * pool ; ? ?ngx_array_t * arr ; ? ? int n ; ? ? int * ele ; ? ?pool = ngx_create_pool ( 4000 , NULL ); ? ?arr = ngx_array_create ( pool , 10 , sizeof ( ngx_uint_t )); ? ? for ( n = 0 ; n < 5 ; n ++) { ? ? ? ele = ( int *) ngx_array_push ( arr ); ? ? ? * ele = n ; ? ? ? printf ( "new element %d added\n" , n ); ? ? } ? ?printf ( "arr->nelts is %d, arr->nalloc = %d\n" , arr -> nelts , arr -> nalloc ); ? ? for ( n = 5 ; n < 15 ; n ++) { ? ? ? ele = ( int *) ngx_array_push ( arr ); ? ? ? * ele = n ; ? ? ? printf ( "new element %d added\n" , n ); ? ? } ? ?printf ( "arr->nelts is %d, arr->nalloc = %d\n" , arr -> nelts , arr -> nalloc ); ? ?ngx_array_destroy ( arr ); ? ?ngx_destroy_pool ( pool ); ? ? return 0 ; }
編譯運行
gcc ? - c - O - pipe ? - O - W - Wall - Wpointer - arith - Wno - unused - parameter - Wunused - function - Wunused - variable - Wunused - value - Werror - g - I ../../../ objs / - I ../../ os / unix array_and_hash . c - I ../../ core / - I ../../ event / - I ../../ os / - o array_and_hash . o gcc - o array_and_hash array_and_hash . o ../../../ objs / src / core / ngx_ { string , palloc , array }. o ../../../ objs / src / os / unix / ngx_alloc . o - lcrypt - lpcre - lcrypto - lz rainx@rainx - laptop :~/ land / nginx - 0.7 . 61 / src / demo / basic_types$ ./ array_and_hash new element 0 added new element 1 added new element 2 added new element 3 added new element 4 added arr -> nelts is 5 , arr -> nalloc = 10 new element 5 added new element 6 added new element 7 added new element 8 added new element 9 added new element 10 added new element 11 added new element 12 added new element 13 added new element 14 added arr -> nelts is 15 , arr -> nalloc = 15
ngx_queue
ngx_queue.{c,h} 實現了一個隊列的操作邏輯,隊列的基本結構為一個雙向隊列
基礎的數據結構為
typedef struct ngx_queue_s ?ngx_queue_t ; struct ngx_queue_s { ? ? ngx_queue_t ? * prev ; ? ? ngx_queue_t ? * next ; };
注意nginx的隊列操作和結構只進行指針的操作,不負責節點內容空間的分配和保存,所以在定義自己的隊列節點的時候,需要自己定義數據結構以及分配空間, 并包含一個ngx_queue_t類型的成員, 需要獲得原始的數據節點的時候需要使用ngx_queue_data宏
#define ngx_queue_data ( q , type , link ) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \ ? ? ( type *) (( u_char *) q - offsetof ( type , link ))
另外,整個queue結構中包含一個 sentinel(哨兵) 節點, 他指向隊列的頭和尾
下面是一個queue操作的例子
#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_queue.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 , ...) { } // 用雅虎的成員列表作為一個簡單的例子 typedef struct yahoo_s { ? ? ngx_queue_t ? queue ; } yahoo_t ; typedef struct yahoo_guy_s { ? ? ngx_uint_t ? ?id ; ? ? u_char * ? ? ? name ; ? ? ngx_queue_t ? queue ; } yahoo_guy_t ; // 排序使用的比較函數, 按照id的大小排序,id大放到到前面 ngx_int_t yahoo_no_cmp ( const ngx_queue_t * p , const ngx_queue_t * n ) { ? ? yahoo_guy_t * pre , * next ; ? ? pre ? = ( yahoo_guy_t *) ngx_queue_data ( p , yahoo_guy_t , queue ); ? ? next = ( yahoo_guy_t *) ngx_queue_data ( n , yahoo_guy_t , queue ); ? ? return (( pre -> id > next -> id ) ? 1 : 0 ); } int main () { ? ? ngx_pool_t * ? ? pool ; ? ? yahoo_guy_t * ? ?guy ; ? ? ngx_queue_t * ? ?q ; ? ? yahoo_t * ? ? ? ?yahoo ; ? ? pool ? ? ? ? ? ? = ngx_create_pool ( 1024 * 10 , NULL ); //初始化內存池 ? ? int ? ? ? ? ? ? i ; ? ? // 構建隊列 ? ? const ngx_str_t ? names [] = { ? ? ? ? ngx_string ( "rainx" ), ngx_string ( "xiaozhe" ), ngx_string ( "zhoujian" ) ? ? } ; ? ? const int ? ? ? ids [] ? = { 4611 , 8322 , 6111 }; ? ? yahoo = ngx_palloc ( pool , sizeof ( yahoo_t )); ? ? ngx_queue_init (& yahoo -> queue ); //初始化queue ? ? for ( i = 0 ; i < 3 ; i ++) ? ? { ? ? ? guy = ( yahoo_guy_t *) ngx_palloc ( pool , sizeof ( yahoo_guy_t )); ? ? ? guy -> id ? = ids [ i ]; ? ? ? //guy->name = (char*) ngx_palloc(pool, (size_t) (strlen(names[i]) + 1) ); ? ? ? guy -> name = ( u_char *) ngx_pstrdup ( pool , ( ngx_str_t *) &( names [ i ]) ); ? ? ? ngx_queue_init (& guy -> queue ); ? ? ? // 從頭部進入隊列 ? ? ? ngx_queue_insert_head (& yahoo -> queue , & guy -> queue ); ? ? } ? ? // 從尾部遍歷輸出 ? ? for ( q = ngx_queue_last (& yahoo -> queue ); ? ? ? ? q != ngx_queue_sentinel (& yahoo -> queue ); ? ? ? ? q = ngx_queue_prev ( q ) ) { ? ? ? ? guy = ngx_queue_data ( q , yahoo_guy_t , queue ); ? ? ? ? printf ( "No. %d guy in yahoo is %s \n" , guy -> id , guy -> name ); ? ? } ? ? // 排序從頭部輸出 ? ? ngx_queue_sort (& yahoo -> queue , yahoo_no_cmp ); ? ? printf ( "sorting....\n" ); ? ? for ( q = ngx_queue_prev (& yahoo -> queue ); ? ? ? ? q != ngx_queue_sentinel (& yahoo -> queue ); ? ? ? ? q = ngx_queue_last ( q ) ) { ? ? ? ? guy = ngx_queue_data ( q , yahoo_guy_t , queue ); ? ? ? ? printf ( "No. %d guy in yahoo is %s \n" , guy -> id , guy -> name ); ? ? } ? ? ngx_destroy_pool ( pool ); ? ? return 0 ; }
運行結果為
rainx@rainx - laptop :~/ land / nginxsrp / src / demo / basic_types$ ./ queue_op No . 4611 guy in yahoo is rainx No . 8322 guy in yahoo is xiaozhe No . 6111 guy in yahoo is zhoujian sorting .... No . 8322 guy in yahoo is xiaozhe No . 6111 guy in yahoo is zhoujian No . 4611 guy in yahoo is rainx
ngx_hash
ngx_hash.{c|h} 實現了nginx里面比較重要的一個hash結構, 這個在模塊配置解析里經常被用到。該 hash 結構是只讀的,即僅在初始創建時可以給出保存在其中的 key-val 對,其后就只能查詢而不能進行增刪改操作了。
下面是簡單 hash 結構的內存布局:
link:? http://www.flickr.com/photos/chaoslawful/3780810336/sizes/o/
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
