nginx缓冲区链表chain

        nginx接收nginx服务器的http请求包头、包体,以及响应客户端的应答包头、包体都会存放到chain链表缓冲区中。

一、chain链表缓冲区数据结构

//ngx_chain_t链表节点
struct ngx_chain_s 
{
    ngx_buf_t    *buf;
    ngx_chain_t  *next;
};
//缓冲区结构
struct ngx_buf_s 
{
    u_char          *pos;		//缓冲区有效数据开始位置
    u_char          *last;		//缓冲区有效数据结束位置
    off_t            file_pos;		//文件开始位置
    off_t            file_last;		//文件结束位置

    u_char          *start;              //整个缓冲区的首地址
    u_char          *end;                //整个缓冲区的末地址
    ngx_buf_tag_t    tag;		//由哪个模块使用就执行那个模块的ngx_module_t结构,例如ngx_http_proxy_module 
    ngx_file_t      *file;		//文件对象
    ngx_buf_t       *shadow;		//影子缓冲区链表头结点,该链表下的所有节点的buf指向同一个空间

    unsigned         temporary:1;	//临时内存标记,值为1表示这段数据在内存中可以修改,
    				        //默认创建的都是可以修改的临时缓冲

    unsigned         memory:1;		//值为1表示这段数据在内存中 且不可以修改

    unsigned         mmap:1;		//表示这个buf是否通过调用mmap获取到的

    unsigned         recycled:1;	//值为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;
};


其中start与pos之间的数据为nginx读取成功并解析完成。

pos与last之间的数据为nginx读取成功的数据,但没有解析

last与end之间的空间为buf的剩余空间,新接收的数据将保持在last指针指向的空间。

二、创建一个缓冲区buf

调用ngx_create_temp_buf函数将在内存池上创建一个临时缓冲区

//创建一个ngx_buf_t结构,同时将开辟一个大小为size的缓冲区
//参数: size 缓冲区大小
ngx_buf_t * ngx_create_temp_buf(ngx_pool_t *pool, size_t size)
{
    ngx_buf_t *b;

    //创建一个缓冲区对象
    b = ngx_calloc_buf(pool);
    if (b == NULL) 
    {
        return NULL;
    }

    //开辟缓冲区空间
    b->start = ngx_palloc(pool, size);
    if (b->start == NULL)
    {
        return NULL;
    }
    //更新缓冲区开始与结束位置
    b->pos = b->start;
    b->last = b->start;
    b->end = b->last + size;
    //临时缓冲区,内存可以被修改
    b->temporary = 1;		

    return b;
}

三、创建一个缓冲区链表

ngx_create_temp_buf只是创建了单个缓冲区空间。如果要创建一片连续的缓冲区,就由链表统一管理,则需要使用ngx_create_chain_of_bufs函数。

//创建一个有bufs->num个缓冲区,每个缓冲区大小为bufs->size。并将这些缓冲区通过ngx_chain_t链表连接起来。
//返回值: ngx_chain_t链表头结点
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;

    //创建一个num个的缓冲区,每一个缓冲区大小为size.这片空间是连续的
    p = ngx_palloc(pool, bufs->num * bufs->size);
    if (p == NULL) 
    {
        return NULL;
    }

    ll = &chain;

    //将每一个缓冲区加入到ngx_chain_t链表
    for (i = 0; i < bufs->num; i++) 
    {
        //创建一个ngx_buf_t结构
        b = ngx_calloc_buf(pool);
        if (b == NULL) 
        {
            return NULL;
        }

	//初始化每个buf缓冲区的起始位置
        b->pos = p;
        b->last = p;
        b->temporary = 1;

        b->start = p;
	//此时p会指向下一个缓冲区
        p += bufs->size;
        b->end = p;

	//创建一个ngx_chain_t节点
        cl = ngx_alloc_chain_link(pool);
        if (cl == NULL)
        {
            return NULL;
        }

	//将ngx_chain_t于buf关联起来
        cl->buf = b;
        *ll = cl;
	//创建ngx_chain_t链表
        ll = &cl->next;
    }

    *ll = NULL;
    //返回ngx_chain_t表头节点
    return chain;
}

例如下面这张图将创建4个chain链表节点,同时开辟了一个连续的缓冲区,并把这个缓冲区分割成4部分。

图:chain缓冲区链表结构

四、合并两个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;

    //找到chain链表的最后一个节点
    for (cl = *chain; cl; cl = cl->next)
    {
        ll = &cl->next;
    }

    //依次将in链表中的节点插入到chain链表末尾
    while (in)
    {
        cl = ngx_alloc_chain_link(pool);
        if (cl == NULL) 
        {
            return NGX_ERROR;
        }

        cl->buf = in->buf;
        *ll = cl;
        ll = &cl->next;
        in = in->next;
    }

    *ll = NULL;

    return NGX_OK;
}
将in链表插入到chain链表末尾的布局如下:

图:合并链表


五、更新free链表

ngx_chain_update_chains函数会将busy链表中的空闲节点回收到free链表中

//将out链表插入到busy链表尾部,同时将合并后的链表从头开始的所有没有使用的节点,插入到空闲链表。
//合并链表后,out为null
void ngx_chain_update_chains(ngx_chain_t **free, ngx_chain_t **busy,
    								ngx_chain_t **out, ngx_buf_tag_t tag)
{
    ngx_chain_t  *cl;

    if (*busy == NULL) 
    {
		//busy直接指向out链表
        *busy = *out;

    }
    else 
    {
	//找到busy链表的最后一个节点
        for (cl = *busy; cl->next; cl = cl->next) 
        {

        }
	//将out链表插入到busy链表末尾
	cl->next = *out;
    }

    *out = NULL;

    while (*busy)
    {
	//合并后的该busy链表节点有内容时,则表示剩余节点都有内容,则退出
        if (ngx_buf_size((*busy)->buf) != 0)
        {
            break;
        }

        //如果该busy链表节点不属于tag指向的模块,则跳过。
        if ((*busy)->buf->tag != tag)
        {
            *busy = (*busy)->next;
            continue;
        }

        //重置buf缓冲区所有空间都可用
        (*busy)->buf->pos = (*busy)->buf->start;
        (*busy)->buf->last = (*busy)->buf->start;

        //将该空闲空闲区加入到free链表表头
        cl = *busy;
        *busy = cl->next;
        cl->next = *free;
        *free = cl;
    }
}
这个函数将执行两个操作:

1、将out链表插入到busy链表的末尾,效果图如下,其中busy链表中的第一个节点表示该节点空间不在使用了,可以回收到free链表

 

2、将合并后的chain链表中,不在使用的节点回收到free链表中。例如上图在合并后的chain链表中的第一个节点将回收到free链表,效果图如下:




  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值