nginx的数据结构之nginx_buf
ngx_buf_s的定义在头文件nginx_buf.h中
typedef struct ngx_buf_s 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; //typedef void* ngx_buf_tag_t;
ngx_file_t *file;
ngx_buf_t *shadow;
//使用位域做标志位,1bit
/* 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; //标志是否为最后一个buf
unsigned last_in_chain:1;
unsigned last_shadow:1;
unsigned temp_file:1;
/* STUB */ int num;
};
nginx_chain_s 结构体:
struct ngx_chain_s {
ngx_buf_t *buf;
ngx_chain_t *next;
};
nginx_bufs_t 结构体:
typedef struct {
ngx_int_t num;
size_t size;
} ngx_bufs_t;
ngx_output_chain_ctx_s 结构体:(处理http时候使用)
struct ngx_output_chain_ctx_s {
ngx_buf_t *buf;
ngx_chain_t *in;
ngx_chain_t *free;
ngx_chain_t *busy;
unsigned sendfile:1;
unsigned directio:1;
#if (NGX_HAVE_ALIGNED_DIRECTIO)
unsigned unaligned:1;
#endif
unsigned need_in_memory:1;
unsigned need_in_temp:1;
#if (NGX_HAVE_FILE_AIO || NGX_THREADS)
unsigned aio:1;
#endif
#if (NGX_HAVE_FILE_AIO)
ngx_output_chain_aio_pt aio_handler;
#if (NGX_HAVE_AIO_SENDFILE)
ssize_t (*aio_preload)(ngx_buf_t *file);
#endif
#endif
#if (NGX_THREADS)
ngx_int_t (*thread_handler)(ngx_thread_task_t *task,
ngx_file_t *file);
ngx_thread_task_t *thread_task;
#endif
off_t alignment;
ngx_pool_t *pool;
ngx_int_t allocated;
ngx_bufs_t bufs;
ngx_buf_tag_t tag;
/**
*typedef ngx_int_t
*(*ngx_output_chain_filter_pt)(void *ctx, *ngx_chain_t *in)
**/
ngx_output_chain_filter_pt output_filter;
void *filter_ctx;
};
nginx实现的对外函数:
ngx_int_t ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in);
ngx_int_t ngx_chain_writer(void *ctx, ngx_chain_t *in);
ngx_int_t ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain,
ngx_chain_t *in);
ngx_chain_t *ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free);
void ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free,
ngx_chain_t **busy, ngx_chain_t **out, ngx_buf_tag_t tag);
off_t ngx_chain_coalesce_file(ngx_chain_t **in, off_t limit);
ngx_chain_t *ngx_chain_update_sent(ngx_chain_t *in, off_t sent);
nginx命名很规范,基本可以通过命名知道对应的变量或者函数的功能,且其ngx_buf数据结构相对来说并不是很复杂,具体功能在对http进行处理时再解析。
ngx_buf_t *
ngx_create_temp_buf(ngx_pool_t *pool, size_t size)
{
ngx_buf_t *b;
b = ngx_calloc_buf(pool); //从内存池里面为buf_t头部申请空间
if (b == NULL) {
return NULL;
}
b->start = ngx_palloc(pool, size); //申请buf空间,数据储存的地方
if (b->start == NULL) {
return NULL;
}
/*
* set by ngx_calloc_buf():
*
* b->file_pos = 0;
* b->file_last = 0;
* b->file = NULL;
* b->shadow = NULL;
* b->tag = 0;
* and flags
*/
b->pos = b->start;
b->last = b->start;
b->end = b->last + size;
b->temporary = 1;
return b;
}
ngx_chain_t *
ngx_alloc_chain_link(ngx_pool_t *pool)
{
ngx_chain_t *cl;
cl = pool->chain;
if (cl) {
pool->chain = cl->next; //被释放的chain_t不会直接被回收,而是挂载在pool->chain上
return cl;
}
cl = ngx_palloc(pool, sizeof(ngx_chain_t));
if (cl == NULL) {
return NULL;
}
return cl;
}
//申请一整条链来储存bufs
ngx_chain_t *
ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs)
{
u_char *p;
ngx_int_t i;
ngx_buf_t *b;
ngx_chain_t *chain, *cl, **ll;
//一次性申请bufs所需要的空间,再用bufs来划分每一个chain_t所拥有的buf
p = ngx_palloc(pool, bufs->num * bufs->size);
if (p == NULL) {
return NULL;
}
ll = &chain;
for (i = 0; i < bufs->num; i++) {
//从内存池里申请buf_t的空间
b = ngx_calloc_buf(pool);
if (b == NULL) {
return NULL;
}
/*
* set by ngx_calloc_buf():
*
* b->file_pos = 0;
* b->file_last = 0;
* b->file = NULL;
* b->shadow = NULL;
* b->tag = 0;
* and flags
*
*/
b->pos = p;
b->last = p;
b->temporary = 1;
b->start = p;
p += bufs->size;
b->end = p;
cl = ngx_alloc_chain_link(pool);
if (cl == NULL) {
return NULL;
}
cl->buf = b;
*ll = cl;
ll = &cl->next;
}
*ll = NULL;
return chain;
}
//将in链表添加到chain后面
ngx_int_t
ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in)
{
ngx_chain_t *cl, **ll;
ll = chain;
for (cl = *chain; cl; cl = cl->next) {
ll = &cl->next;
}
while (in) {
cl = ngx_alloc_chain_link(pool);
if (cl == NULL) {
return NGX_ERROR;
}
//并没有重新为in->buf重新分配内存来储存,而是将cl指向in->buf
cl->buf = in->buf;
*ll = cl;
ll = &cl->next;
in = in->next;
}
*ll = NULL;
return NGX_OK;
}
//获取已经被free的chain_t
ngx_chain_t *
ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free)
{
ngx_chain_t *cl;
if (*free) {
cl = *free;
*free = cl->next;
cl->next = NULL;
return cl;
}
//若是没有被释放的,则从内存池重新申请
cl = ngx_alloc_chain_link(p);
if (cl == NULL) {
return NULL;
}
cl->buf = ngx_calloc_buf(p);
if (cl->buf == NULL) {
return NULL;
}
cl->next = NULL;
return cl;
}
void
ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy,
ngx_chain_t **out, ngx_buf_tag_t tag)
{
ngx_chain_t *cl;
//busy链表为空,直接指向out链表
if (*busy == NULL) {
*busy = *out;
} else {
//否则将新读到的out链表加入busy链表
for (cl = *busy; cl->next; cl = cl->next) { /* void */ }
cl->next = *out;
}
*out = NULL;
while (*busy) {
cl = *busy;
//size不为0,说明还未被读出
if (ngx_buf_size(cl->buf) != 0) {
break;
}
if (cl->buf->tag != tag) {
*busy = cl->next;
ngx_free_chain(p, cl);
continue;
}
//如果已经被读出的话,则将chain加入到free链表上
cl->buf->pos = cl->buf->start;
cl->buf->last = cl->buf->start;
*busy = cl->next;
cl->next = *free;
*free = cl;
}
}
//计算in链表上的文件大小
off_t
ngx_chain_coalesce_file(ngx_chain_t **in, off_t limit)
{
off_t total, size, aligned, fprev;
ngx_fd_t fd;
ngx_chain_t *cl;
total = 0;
cl = *in;
fd = cl->buf->file->fd;
do {
//last-pos计算size
size = cl->buf->file_last - cl->buf->file_pos;
//限定了一个limit,不能超出这个limit的大小
if (size > limit - total) {
size = limit - total;
//进行对齐
aligned = (cl->buf->file_pos + size + ngx_pagesize - 1)
& ~((off_t) ngx_pagesize - 1);
//对齐后的指针若是小于文件末尾的指针,则直接用对齐后的指针计算
if (aligned <= cl->buf->file_last) {
size = aligned - cl->buf->file_pos;
}
}
total += size;
fprev = cl->buf->file_pos + size;
cl = cl->next;
} while (cl
&& cl->buf->in_file
&& total < limit
&& fd == cl->buf->file->fd
&& fprev == cl->buf->file_pos);
*in = cl;
return total;
}
//计算本次调用ngx_writev发送出去的send字节在in链表中所有数据的那个位置
ngx_chain_t *
ngx_chain_update_sent(ngx_chain_t *in, off_t sent)
{
off_t size;
for ( /* void */ ; in; in = in->next) {
//遍历找出只成功发出部分数据的链表节点
if (ngx_buf_special(in->buf)) {
continue;
}
if (sent == 0) {
break;
}
size = ngx_buf_size(in->buf);
if (sent >= size) { //sent大于size,证明该处已经发出
sent -= size;
if (ngx_buf_in_memory(in->buf)) { //更新pos位置
in->buf->pos = in->buf->last;
}
if (in->buf->in_file) { //更新pos位置
in->buf->file_pos = in->buf->file_last;
}
continue;
}
//找到该节点,更新位置
if (ngx_buf_in_memory(in->buf)) {
in->buf->pos += (size_t) sent;
}
if (in->buf->in_file) {
in->buf->file_pos += sent;
}
break;
}
return in;
}