为了进行平台无关层(PAL, Platform Abstraction Layer)抽象, 优化数据结构对内存空间的占用以及同一代码风格等因素, Nginx为此定义,封装了一些基本数据结构。
整型的封装
1 | typedef intptr_t ngx_int_t; |
2 | typedef uintptr_t ngx_uint_t; |
ngx_str_t字符串封装
该结构定义在/src/core/ngx_string.h
文件中, ngx_str_t只有两个成员,其中data指针指向字符串起始地址,len表示字符串的有效长度。注意,ngx_str_t的data成员指向的并不是普通的字符串,
因为这段字符串未必会以’\0’作为结尾,所以使用时必须根据长度len来使用data成员。
1 | typedef struct { |
2 | size_t len; |
3 | u_char *data; |
4 | } |
5 |
|
6 | if (0 == ngx_strncmp(r->method_name.data,"PUT", r->method_name.len)) { |
7 | |
8 | } |
9 |
|
10 | #define ngx_strcmp(s1, s2, n) strncmp((const char *)s1, (const char*)s2, n) |
ngx_list_t链表容器
ngx_list_t
不是一个单纯的链表,是一种存储数组的链表,定义在/src/core/ngx_list.h
文件中。这样设计的目的是为了:
- 存储元素更加灵活,可以是任何一种数据结构。
- 链表元素需要占用的内存由ngx_list_t管理,它已经通过数组分配好了。
- 通过数组偏移量来访问元素,比零散的小块内存效率更高。
1 | typedef struct ngx_list_part_s ngx_list_part_t; |
2 |
|
3 | struct ngx_list_part_s { |
4 | void *elts; |
5 | ngx_uint_t nelts; |
6 | ngx_list_part_t *next; |
7 | } |
8 |
|
9 | typedef struct { |
10 | ngx_list_part_t *last; |
11 | ngx_list_part_t part; |
12 | size_t size; |
13 | |
14 | ngx_uint_t nalloc; |
15 | ngx_pool_t *pool; |
16 | } ngx_list_t; |
ngx_list_t接口
ngx_list_init
接口用于初始化一个已有的链表,size
,n
分别对应ngx_list_t
中的size
和nalloc
。
1 | static ngx_inline ngx_int_t ngx_list_init(ngx_list_t *list, \ |
2 | ngx_pool_t *pool, ngx_uint_t n, size_t size) |
3 | { |
4 | list->part.elts = ngx_palloc(pool, n * size); |
5 | if (list->part.elts == NULL) { |
6 | return NGX_ERROR; |
7 | } |
8 |
|
9 | list->part.nelts = 0; |
10 | list->part.next = NULL; |
11 | list->last = &list->part; |
12 | list->size = size; |
13 | list->nalloc = n; |
14 | list->pool = pool; |
15 |
|
16 | return NGX_OK; |
17 | } |
ngx_list_create
接口用于创建新的链表,size
是每个元素的大小,n
是每个链表数组可容纳元素的个数。
1 | ngx_list_t *ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size) |
2 | { |
3 | ngx_list_t *list; |
4 |
|
5 | list = ngx_palloc(pool, sizeof(ngx_list_t)); |
6 | if (list == NULL) { |
7 | return NULL; |
8 | } |
9 |
|
10 | if (ngx_list_init(list, pool, n, size) != NGX_OK) { |
11 | return NULL; |
12 | } |
13 |
|
14 | return list; |
15 | } |
ngx_list_push
表示添加新的元素,传入参数是ngx_list_t
链表。
1 | void *ngx_list_push(ngx_list_t *l) |
2 | { |
3 | void *elt; |
4 | ngx_list_part_t *last; |
5 |
|
6 | last = l->last; |
7 |
|
8 | if (last->nelts == l->nalloc) { |
9 |
|
10 | |
11 |
|
12 | last = ngx_palloc(l->pool, sizeof(ngx_list_part_t)); |
13 | if (last == NULL) { |
14 | return NULL; |
15 | } |
16 |
|
17 | last->elts = ngx_palloc(l->pool, l->nalloc * l->size); |
18 | if (last->elts == NULL) { |
19 | return NULL; |
20 | } |
21 |
|
22 | last->nelts = 0; |
23 | last->next = NULL; |
24 |
|
25 | l->last->next = last; |
26 | l->last = last; |
27 | } |
28 |
|
29 | elt = (char *) last->elts + l->size * last->nelts; |
30 | last->nelts++; |
31 |
|
32 | return elt; |
33 | } |
34 |
|
35 | ngx_str_t *str = ngx_list_push(testlist); |
36 | if(str == NULL) { |
37 | return NGX_ERROR; |
38 | } |
39 |
|
40 | str->len = sizeof("Hello World!"); |
41 | str->data = "Hello World!"; |
遍历链表容器
Nginx没有提供遍历链表容器的接口,实际上也没必要,可以用如下方法遍历链表中的元素:
1 |
|
2 | ngx_list_part* part = &testlist.part; |
3 |
|
4 |
|
5 | ngx_str_t* str = part->elts; |
6 |
|
7 |
|
8 | for(i = 0; ; i++) { |
9 | if(i >= part->nelts) { |
10 | if(part-next == NULL) { |
11 | |
12 | break; |
13 | } |
14 | |
15 | part = part->next; |
16 |
|
17 | str = part->elts; |
18 |
|
19 | i = 0; |
20 | } |
21 | printf("list element: %*s\n", str[i].len, str[i].data); |
22 | } |
ngx_table_elt_t数据结构
1 | typedef struct { |
2 | ngx_uint_t hash; |
3 | ngx_str_t key; |
4 | ngx_str_t value; |
5 | u_char *lowcase_key; |
6 | } |
ngx_buf_t数据结构
ngx_buf_t
是nginx处理大数据块的关键数据结构,定义在core/ngx_buf.h
文件中,它即应用于内存数据也应用于磁盘数据,上一章中ngx_buf_t
配置读取缓冲区是一个使用该结构的例子。
1 | typedef struct ngx_buf_s ngx_buf_t; |
2 |
|
3 | struct ngx_buf_s { |
4 | |
5 |
|
6 |
|
7 | u_char *pos; |
8 | u_char *last; |
9 |
|
10 | |
11 |
|
12 |
|
13 | off_t file_pos; |
14 | off_t file_last; |
15 |
|
16 | |
17 |
|
18 |
|
19 | u_char *start; |
20 | u_char *end; |
21 |
|
22 | |
23 |
|
24 |
|
25 | ngx_buf_tag_t tag; |
26 | ngx_file_t *file; |
27 | ngx_buf_t *shadow; |
28 |
|
29 | |
30 | |
31 |
|
32 | unsigned temporary:1; |
33 |
|
34 | |
35 |
|
36 |
|
37 |
|
38 | unsigned memory:1; |
39 |
|
40 | |
41 | unsigned mmap:1; |
42 |
|
43 | unsigned recycled:1; |
44 | unsigned in_file:1; |
45 | unsigned flush:1; |
46 | unsigned sync:1; |
47 | unsigned last_buf:1; |
48 | unsigned last_in_chain:1; |
49 |
|
50 | unsigned last_shadow:1; |
51 | unsigned temp_file:1; |
52 |
|
53 | int num; |
54 | }; |
ngx_chain_t结构
ngx_chain_t
是与ngx_buf_t
配合使用的链表数据结构,如果处于最后一个ngx_chain_t
结构,则需要把next置为NULL。
1 | typedef struct ngx_chain_s ngx_chain_t; |
2 | struct ngx_chain_s { |
3 | ngx_buf_t *buf; |
4 | ngx_chain_t *next; |
5 | }; |