您的位置:首页 > 理论基础 > 数据结构算法

nginx 学习笔记(三)基本数据结构

2017-06-14 22:38 225 查看
在开发nginx模块之前,要先了解nginx的一些基本的数据结构。。

ngx_int_t

实际上ngx_int_t就是intptr_t的一个typedef

类似的还有ngx_uint_t是uintptr_t的一个typedef

ngx_str_t

ngx_str_t在模块开发时经常用到,代表的就是一个字符串,定义如下:

typedef struct {
size_t      len;
u_char     *data;
} ngx_str_t;


其中len是字符串的长度,data指向字符串的地址,这样的话如果有多个同样的字符串,就可以让data指向同一个地址,节省空间。data不保证字符串后会添加\0,所以在使用ngx_str_t的data成员时候,不要使用strcpy等这些以\0标识结尾的函数。

用来简化ngx_str_t使用的宏有:

ngx_string(text) - 初始化ngx_str_t时使用

ngx_null_string - 相当于ngx_string(“”)

ngx_str_set(str, text) - 设置一个已有的str为text的内容

ngx_str_null(str) - 设置一个已有的str为空字符串

ngx_array_t

定义如下

typedef struct ngx_array_s       ngx_array_t;
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:内存池,也就是说需要的内存都是从pool获取的

以及相关函数

/* 在内存池p上分配n个元素,每个元素大小为size,返回构造好的ngx_array_t的地址 */
ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);

/* 销毁一个ngx_array_t,会由内存池自动释放内存 */
void ngx_array_destroy(ngx_array_t *a);

/* 在ngx_array_t上添加一个元素,返回元素的地址 */
void *ngx_array_push(ngx_array_t *a);

/* 在ngx_array_t上添加n个元素,返回元素的地址 */
void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);

/*
*初始化一个已经存在的ngx_array_t
*例如 ngx_array_t b;
*ngx_array_init(&b, pool, 5, sizeof(int));
*/
static ngx_inline ngx_int_t ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size);


ngx_buf_t

定义:

struct ngx_buf_s {
u_char          *pos;
u_char          *last;
off_t            file_pos;
off_t            file_last;

u_char          *start;         /* start of buffer */
u_char          *end;           /* end of buffer */
ngx_buf_tag_t    tag;
ngx_file_t      *file;
ngx_buf_t       *shadow;

/* the buf's content could be changed */
unsigned         temporary:1;

/*
* the buf's content is in a memory cache or in a read only memory
* and must not be changed
*/
unsigned         memory:1;

/* the buf's content is mmap()ed and must not be changed */
unsigned         mmap:1;

unsigned         recycled:1;
unsigned         in_file:1;
unsigned         flush:1;
unsigned         sync:1;
unsigned         last_buf:1;
unsigned         last_in_chain:1;

unsigned         last_shadow:1;
unsigned         temp_file:1;

/* STUB */ int   num;
};


ngx_buf_t代表的是缓冲区,其中各个成员含义如下:

pos:缓冲区的起始位置

last:缓冲区的终止位置

file_pos:缓冲文件时,file_pos代表文件的起始位置

file_last:缓冲文件时,file_last代表文件的结束位置

start:整个缓冲区的开始位置

end:整个缓冲区的结束位置

tag:实际上是一个void*类型的指针,使用者可以关联任意的对象上去,只要对使用者有意义。

file:处理文件时,代表文件对象

shadow:当某一个buf和另一个buf要处理同一个文件或者同一块缓冲区的时候,就不再拷贝一份过来,而是直接指向同一块内存,并且两个buf的shadow指向对方,所以此时释放内存的时候容易造成多次释放,要特别小心

temporary:1:为1代表是用户建立的临时内存块,并且内容可以修改

memory:1:为1代表数据在内存中,但是不能被修改

mmap:1:为1代表数据是放在使用mmap()这个系统调用映射过来的内存中,并且不可以被修改

recycled:1:可以被回收的,也就是可以被释放的

in_file:1:为1代表处理的是文件

flush:1:遇到有flush字段被设置为1的的buf的chain,则该chain的数据即便不是最后结束的数据(last_buf被设置,标志所有要输出的内容都完了),也会进行输出,不会受postpone_output配置的限制,但是会受到发送速率等其他条件的限制。

sync:1:这块内存是否用同步操作进行(可能会阻塞nginx)

last_buf:1:当这个buf在多个ngx_chain_t内,标识着是否是最后一块buf

last_in_chain:1:是否是当前这个ngx_chain_t的最后一块buf,所以last_buf一定是last_in_chain,但是last_in_chain不一定是last_buf,因为可能在另一个chain里这个buf不是那个chain的最后一个buf

last_shadow:1:当多个buf互相是shadow的时候,是否是最后一个shadow,在创建一个buf的shadow的时候,通常将新创建的一个buf的last_shadow置为1。

temp_file:1:当内存不够的时候,buf的内容需要写到临时文件内,由这个标识位来标识

nginx定义了两个宏来方便的创建buf

#define ngx_alloc_buf(pool)  ngx_palloc(pool, sizeof(ngx_buf_t))
#define ngx_calloc_buf(pool) ngx_pcalloc(pool, sizeof(ngx_buf_t))


也可以使用定义好的函数来创建一个临时的内存块,size为内存的大小

ngx_int_t ngx_create_temp_buf(ngx_pool_t *pool, size_t size)


ngx_chain_t

定义如下:

typedef struct ngx_chain_s
4000
ngx_chain_t;

struct ngx_chain_s {
ngx_buf_t    *buf;
ngx_chain_t  *next;
};


容易看出实际上ngx_chain_t就是ngx_buf_t的一个链表而已。。

可以使用ngx_alloc_chain_link()来创建一个chain,原型如下

ngx_chain_t *ngx_alloc_chain_link(ngx_pool_t *pool);


可以使用ngx_free_chain(pool, cl)宏来释放一个chain的节点

#define ngx_free_chain(pool, cl)                                   \
cl->next = pool->chain;                                        \
pool->chain = cl


容易看出,释放一个chain的节点实际上只是把这个节点放到pool的chain成员上去了,实际上节点并没有被真正的释放,这样的话下次再申请节点的时候可以直接从chain这个成员上拿下来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  nginx