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ì)您有幫助就好】元

