Nginx定义、封装的一些基本数据结构
- 整型的封装
- 字符串类型的封装
- 链表容器
size
ngx_list_part_t中每个元素的大小nalloc
ngx_list_part_t数组的容量,即最多可存储多少个数据part
链表的首个数组元素last
指向链表的最后一个数组元素pool
链表中管理内存分配的内存池对象elts
指向数组的起始地址nelts
表示数组中已经使用了多少个元素。当然,nelts必须小于ngx_list_t结构体中的nallocnext
下一个链表元素ngx_list_part_t的地址- 键值对封装
- ngx_buf_t数据结构
- ngx_chain_t数据结构
typedef intptr_t ngx_int_t; typedef uintptr_t ngx_uint_t;
typedef struct{ size_t len; u_char *data; }ngx_str_t;
ngx_str_t只有两个成员,其中data指针指向字符串起始地址,len表示字符串的有效长度。
注意:ngx_str_t的data成员指向的并不是普通的字符串,因为这段字符串未必会以’\0’作为结尾,所以使用时必须根据长度len来使用data成员。具体使用方法,参考P141.
typedef struct ngx_list_part_s ngx_list_part_t; struct ngx_list_part_s{ void *elts; ngx_uint_t nelts; ngx_list_part_t *next; }; typedef struct{ ngx_list_part_t *last; ngx_list_part_t part; size_t size; ngx_uint_t nalloc; ngx_pool_t *pool; }ngx_list_t;
这里ngx_list_t 是相当于一个链表,而链表的每个元素是ngx_list_part_s(是一个数组)
事实上,ngx_list_t中的所有数据都是由ngx_pool_t类型的pool内存池分配的,它们通常都是连续的内存
ngx_list_t的内存分布情况:
这里,pool内存池为其分配了连续的内存,最前端内存存储的是ngx_list_t结构中的成员,紧接着是第一个ngx_list_part_t结构占用的内存,然后是ngx_list_part_t结构指向的数组,它们一共占用size*nalloc字节,表示数组中拥有nalloc个大小为size的元素。其后面是第2个ngx_list_part_t结构以及它所指向的数组,依此类推
typedef struct{ ngx_uint_t hash; ngx_str_t key; ngx_str_t value; u_char *lowcase_key; }ngx_table_elt_t;
typedef struct ngx_buf_s ngx_buf_t; typedef void *ngx_buf_tag_t; struct ngx_buf_s{ /*pos通常是用来告诉使用者本次应该从pos这个位置开始处理内存中的数据, 这样设置是因为同一个ngx_buf_t可能被多次反复处理。当然, pos的含义是由使用它的模块定义的*/ u_char *pos; /*last通常表示有效的内容到此为止, 注意, pos与last之间的内存是希望nginx处理的内容*/ u_char *last; /*处理文件时, file_pos与file_last的含义与处理内存时的pos与last相同, file_pos表示将要处理的文件位置, file_last表示截止的文件位置*/ off_t file_pos; off_t file_last; //如果ngx_buf_t缓冲区用于内存, 那么start指向这段内存的起始地址 u_char *start; //与start成员对应, 指向缓冲区内存的末尾 u_char *end; /*表示当前缓冲区的类型, 例如由哪个模块使用就指向这个模块ngx_module_t变量的地址*/ ngx_buf_tag_t tag; //引用的文件 ngx_file_t *file; /*当前缓冲区的影子缓冲区, 该成员很少用到, 仅仅在12.8节描述的使用缓冲区转发上游服务器的响应时才使用了shadow成员, 这是因为Nginx太节约内存了, 分配一块内存并使用ngx_buf_t表示接收到的上游服务器响应后, 在向下游客户端转发时可能会把这块内存存储到文件中, 也可能直接向下游发送, 此时Nginx绝不会重新复制一份内存用于新的目的, 而是再次建立一个ngx_buf_t结构体指向原内存, 这样多个ngx_buf_t结构体指向了同一块内存, 它们之间的关系就通过shadow成员来引用。 这种设计过于复杂, 通常不建议使用*/ ngx_buf_t *shadow; //临时内存标志位, 为1时表示数据在内存中且这段内存可以修改 unsigned temporary:1; //标志位, 为1时表示数据在内存中且这段内存不可以被修改 unsigned memory:1; //标志位, 为1时表示这段内存是用mmap系统调用映射过来的, 不可以被修改 unsigned mmap:1; //标志位, 为1时表示可回收 unsigned recycled:1; //标志位, 为1时表示这段缓冲区处理的是文件而不是内存 unsigned in_file:1; //标志位, 为1时表示需要执行flush操作 unsigned flush:1; /*标志位, 对于操作这块缓冲区时是否使用同步方式, 需谨慎考虑, 这可能会阻塞Nginx进程, Nginx中所有操作几乎都是异步的, 这是它支持高并发的关键。 有些框架代码在sync为1时可能会有阻塞的方式进行I/O操作, 它的意义视使用它的Nginx模块而定*/ unsigned sync:1; /*标志位, 表示是否是最后一块缓冲区, 因为ngx_buf_t可以由ngx_chain_t链表串联起来, 因此, 当last_buf为1时, 表示当前是最后一块待处理的缓冲区*/ unsigned last_buf:1; //标志位, 表示是否是ngx_chain_t中的最后一块缓冲区 unsigned last_in_chain:1; /*标志位, 表示是否是最后一个影子缓冲区, 与shadow域配合使用。通常不建议使用它*/ unsigned last_shadow:1; //标志位, 表示当前缓冲区是否属于临时文件 unsigned temp_file:1; };
typedef struct ngx_chain_s ngx_chain_t; struct ngx_chain_s{ ngx_buf_t *buf; ngx_chain_t *next; };