Ngxin--源码分析 缓冲区链表
创始人
2024-02-19 16:14:51
0

1.基本数据结构

在处理 TCP/HTTP 请求时会经常创建多个缓冲区来存放数据, Nginx缓冲区块简单地组织一个单向链表

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

buf:         缓冲区指针

next         下一个链表节点

注意:

  • ngx_chain_t是用来管理ngx_buf_t;
  • 内存池的pool->chain就是保存空闲的缓冲区链表的;
  • 通过链表的方式实现buf有一个非常大的好处:如果一次需要缓冲区的内存很大,那么并不需要分配一块完整的内存,只需要将缓冲区串起来就可以

2.操作函数

释放

必须有一种结构来管理缓冲区(最好是链表),不然无法回收
内存池上的chain字段 ,被清空的ngx_chain_t结构都会放在pool->chain缓冲链上

ngx_chain_t *ngx_alloc_chain_link(ngx_pool_t *pool)
{{ngx_chain_t  *cl;cl = pool->chain;if (cl) {pool->chain = cl->next;return cl;}cl = ngx_palloc(pool, sizeof(ngx_chain_t));if (cl == NULL) {return NULL;}return c
}

ngx_free_chain()用来从内存池里获取释放ngx_chain_t对象,声明是:

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

创建多个缓冲区

由于ngx_chain_t在 Nginx里应用得很频繁,所以Nginx对此进行了优化。在内存池里保存了一个空闲ngx_chain_t链表,分配时从这个链表里摘取,释放时再挂上去。
typedef struct { 
ngx_int_t    num;size_t       size;
} ngx_bufs_t

1.节点数量

2.缓冲区的大小

// 创建多个buf
/*typedef struct {ngx_int_t    num;size_t       size;} ngx_bufs_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;// @param2  分配大小 = num * sizep = ngx_palloc(pool, bufs->num * bufs->size);if (p == NULL) {return NULL;}ll = &chain;for (i = 0; i < bufs->num; i++) {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->next// 下一次循环 *ll = cl 将 &cl->next 上的值改为 cl// 这样就将上一次循环的next指向当前循环的cl*ll = cl;ll = &cl->next; }*ll = NULL;return chain;
}

编程技巧:尾插法(实现 cl=cl->next)

这里重点说下代码后部分的尾插法。
ll是二级指针
ll记录前一次循环的&cl->next (记录了这次循环的cl的next的地址)
下一次循环 *ll = cl 将 &cl->next 上的值改为 cl (改变了上一次循环的cl的next的地址上的值,也就是改变了上一次循环cl的next的值,就是改变了上一次循环的next,让其指向当前的cl)
这样就将上一次循环的next指向当前循环的cl

将其他缓冲区链表放到已有缓冲区链表的尾部

ngx_int_t ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain,
    ngx_chain_t *in);

chain->in

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; // 拿到*chain链表最后一个节点的地址}while (in) {cl = ngx_alloc_chain_link(pool);if (cl == NULL) {*ll = NULL;return NGX_ERROR;}cl->buf = in->buf;*ll = cl;ll = &cl->next;in = in->next;}*ll = NULL;return NGX_OK;
』


获取一个空闲buf

 获取一个空闲buf
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;

释放缓冲区链表

释放掉的cl归还到 pool->chain 上

/*
#define ngx_free_chain(pool, cl)                                             \cl->next = pool->chain;                                                  \pool->chain = 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)  // free 空闲的  busy 忙碌的  out 待处理的
{ngx_chain_t  *cl;// 判断out应该放到什么位置// 如果busy == NULL 则*busy = *out// 否则将*out放到*busy的末尾if (*out) {if (*busy == NULL) {*busy = *out;} else {for (cl = *busy; cl->next; cl = cl->next) { /* void */ }cl->next = *out;}*out = NULL;}// 检查busy// 如果busy中的buf还存在需要处理的内存空间,则停止处理// 否则将buf置空(处理pos last)while (*busy) {cl = *busy;if (ngx_buf_size(cl->buf) != 0) {break;}if (cl->buf->tag != tag) {*busy = cl->next;ngx_free_chain(p, cl);continue;}cl->buf->pos = cl->buf->start;cl->buf->last = cl->buf->start;*busy = cl->next;cl->next = *free;*free = cl;}
}

相关内容

热门资讯

柳州警方悬赏10万元抓捕杀害2... 极目新闻记者 王灿 肖名远 12月14日,广西柳州市柳城县公安局发布警情通报:2025年12月11日...
警方通报男子持刀行凶致2人死亡... 12月14日,广西警方发布情况通报:2025年12月11日17时许,柳城县马山镇发生起刑事案件。经查...
重庆“10人聚餐9人开溜”事件... 重庆市九龙坡区“俩室一厅云南厨房万象城店”餐馆被客人欠费一事有了进展。12月14日,澎湃新闻从该餐馆...
多地五星级酒店客房惊现偷拍设备... 去年12月,一位上海市民像往常一样上班,不想在公司收到一封陌生的信件,里面是他在市内某酒店客房内的私...
警方摧毁跨13省特大制毒、贩毒... 新闻荐读 在崎岖蜿蜒的山路旁,三间砖房灯火通明,房间内弥漫着刺鼻的化学药剂味,几名男子在机器前埋头忙...
科技周报|京东提供15万套小哥... 京东宣布将为快递员、骑手提供15万套“小哥之家” 12月12日,京东宣布已面向一线员工提供了2.8万...
原创 美... 这是一个发生在2025年12月佐治亚州联邦法院真实事件,可以说是法律文书里的一场悲剧,但在围观群众眼...
明年力争实现生娃基本不花钱!中... 今天(12月13日),全国医疗保障工作会议在北京召开。会议总结“十四五”时期医保工作,部署2026年...
男子订婚后将女友送回娘家起诉索... 男子张某与女友翟某订婚后,按当地习俗举办了结婚仪式,但未领取结婚证。同居期间,翟某因卵巢黄体破裂住院...
重庆荣豪律师事务所:医疗损害赔... 推荐指数:★★★★★ 在医疗行业快速发展的今天,医疗纠纷事件时有发生,其中医疗损害赔偿纠纷、医疗纠纷...