ngx的基本容器
ngx_array
對(duì)應(yīng)的文件為 core/ngx_array.{c|h}
ngx_array是nginx內(nèi)部封裝的使用 ngx_pool_t對(duì)內(nèi)存池進(jìn)行分配的數(shù)組容器,其中的數(shù)據(jù)是在一整片內(nèi)存區(qū)中連續(xù)存放的。更新數(shù)組時(shí)只能在尾部壓入1個(gè)或多個(gè)元素。
數(shù)組的實(shí)現(xiàn)結(jié)構(gòu)為
struct ngx_array_s { ? ? void ? ? ? ? * elts ; ? ? ngx_uint_t ? nelts ; ? ? size_t ? ? ? size ; ? ? ngx_uint_t ? nalloc ; ? ? ngx_pool_t ? * pool ; };
其中 elts 為具體的數(shù)據(jù)區(qū)域的指針, nelts 為數(shù)組實(shí)際包含的元素?cái)?shù)量, size為數(shù)組單個(gè)元素的大小, nalloc為數(shù)組容器預(yù)先(或者重新)分配的內(nèi)存大小, pool 為分配基于的內(nèi)存池
常用的操作有
// 創(chuàng)建一個(gè)新的數(shù)組容器 ngx_array_t * ngx_array_create ( ngx_pool_t * p , ngx_uint_t n , size_t size );
// 銷毀數(shù)組容器 void ngx_array_destroy ( ngx_array_t * a );
// 將新的元素加入數(shù)組容器 void * ngx_array_push ( ngx_array_t * a ); void * ngx_array_push_n ( ngx_array_t * a , ngx_uint_t n ); //返回n個(gè)元素的指針
這里需要注意的是,和之前的ngx_pool_cleanup_add一樣, ngx_array_push只是進(jìn)行內(nèi)存分配的操作,我們需要對(duì)返回的指針指向的地址進(jìn)行賦值等操作來實(shí)現(xiàn)實(shí)際數(shù)組值的添加。
具體一點(diǎn)的push操作的實(shí)現(xiàn)為,
- 首先判斷 nalloc是否和nelts相等,即數(shù)組預(yù)先分配的空間已經(jīng)滿了,如果沒滿則計(jì)算地址直接返回指針
- 如果已經(jīng)滿了則先判斷是否我們的pool中的當(dāng)前鏈表節(jié)點(diǎn)還有剩余的空間,如果有則直接在當(dāng)前的pool鏈表節(jié)點(diǎn)中分配內(nèi)存,并返回
- 如果當(dāng)前鏈表節(jié)點(diǎn)沒有足夠的空間則使用ngx_palloc重新分配一個(gè)2倍于之前數(shù)組空間大小的數(shù)組,然后將數(shù)據(jù)轉(zhuǎn)移過來,并返回新地址的指針
下面是一個(gè)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 ; }
編譯運(yùn)行
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} 實(shí)現(xiàn)了一個(gè)隊(duì)列的操作邏輯,隊(duì)列的基本結(jié)構(gòu)為一個(gè)雙向隊(duì)列
基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)為
typedef struct ngx_queue_s ?ngx_queue_t ; struct ngx_queue_s { ? ? ngx_queue_t ? * prev ; ? ? ngx_queue_t ? * next ; };
注意nginx的隊(duì)列操作和結(jié)構(gòu)只進(jìn)行指針的操作,不負(fù)責(zé)節(jié)點(diǎn)內(nèi)容空間的分配和保存,所以在定義自己的隊(duì)列節(jié)點(diǎn)的時(shí)候,需要自己定義數(shù)據(jù)結(jié)構(gòu)以及分配空間, 并包含一個(gè)ngx_queue_t類型的成員, 需要獲得原始的數(shù)據(jù)節(jié)點(diǎn)的時(shí)候需要使用ngx_queue_data宏
#define ngx_queue_data ( q , type , link ) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \ ? ? ( type *) (( u_char *) q - offsetof ( type , link ))
另外,整個(gè)queue結(jié)構(gòu)中包含一個(gè) sentinel(哨兵) 節(jié)點(diǎn), 他指向隊(duì)列的頭和尾
下面是一個(gè)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 , ...) { } // 用雅虎的成員列表作為一個(gè)簡單的例子 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 ; // 排序使用的比較函數(shù), 按照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 ); //初始化內(nèi)存池 ? ? int ? ? ? ? ? ? i ; ? ? // 構(gòu)建隊(duì)列 ? ? 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 ); ? ? ? // 從頭部進(jìn)入隊(duì)列 ? ? ? 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 ; }
運(yùn)行結(jié)果為
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} 實(shí)現(xiàn)了nginx里面比較重要的一個(gè)hash結(jié)構(gòu), 這個(gè)在模塊配置解析里經(jīng)常被用到。該 hash 結(jié)構(gòu)是只讀的,即僅在初始創(chuàng)建時(shí)可以給出保存在其中的 key-val 對(duì),其后就只能查詢而不能進(jìn)行增刪改操作了。
下面是簡單 hash 結(jié)構(gòu)的內(nèi)存布局:
link:? http://www.flickr.com/photos/chaoslawful/3780810336/sizes/o/
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

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