ngx_buf_t和ngx_chain_t是nginx中操作内存的重要手段, 很多的数据都需要通过这个结构进行保存. 其中ngx_buf_t中保存一块可用内存, ngx_chain_t则是将内存块连接起来,组成一个链表, 操作这两个数据结构函数并不多, 下面进行了详解.

基本数据结构

  1. typedef struct ngx_chain_s ngx_chain_t;
  2. typedef struct ngx_buf_s ngx_buf_t;
  3. struct ngx_buf_s {
  4. /*当前读取buffer位置*/
  5. u_char *pos;
  6. /*实际占用buffer的最后位置*/
  7. u_char *last;
  8. /*当前读取文件位置*/
  9. off_t file_pos;
  10. /*文件最后位置*/
  11. off_t file_last;
  12. /*buffer开始位置*/
  13. u_char *start;
  14. /*buffer结束位置*/
  15. u_char *end;
  16. /*内存标记*/
  17. ngx_buf_tag_t tag;
  18. /*文件句柄*/
  19. ngx_file_t *file;
  20. ngx_buf_t *shadow;
  21. /*1表示内存可以修改*/
  22. unsigned temporary:1;
  23. /*1表示内存不可以修改*/
  24. unsigned memory:1;
  25. /*1表示操作内容通过mmap()函数映射不可修改*/
  26. unsigned mmap:1;
  27. /*1表示内存可以回收*/
  28. unsigned recycled:1;
  29. /*1表示操作内容在文件中*/
  30. unsigned in_file:1;
  31. /*1表示立即将内容发送出去*/
  32. unsigned flush:1;
  33. /*1表示立即将内容同步发送出去*/
  34. unsigned sync:1;
  35. /*标记chain是否为最后一块buf*/
  36. unsigned last_buf:1;
  37. /*标记chain中是否为最后一个chain,最后一块buf并不表示是最后一个chain,但最后一个chain一定是最后一块buf*/
  38. unsigned last_in_chain:1;
  39. unsigned last_shadow:1;
  40. unsigned temp_file:1;
  41. /* STUB */ int num;
  42. };
  43. struct ngx_chain_s {
  44. ngx_buf_t *buf;
  45. ngx_chain_t *next;
  46. };

操作函数

创建一个buf很简单, 直接在内存池中分配一块内存, 然后分配size大小空间, 给ngx_buf_t各个字段进行赋值即可.

  1. ngx_buf_t *
  2. ngx_create_temp_buf(ngx_pool_t *pool, size_t size)
  3. {
  4. ngx_buf_t *b;
  5. b = ngx_calloc_buf(pool);
  6. if (b == NULL) {
  7. return NULL;
  8. }
  9. b->start = ngx_palloc(pool, size);
  10. if (b->start == NULL) {
  11. return NULL;
  12. }
  13. b->pos = b->start;
  14. b->last = b->start;
  15. b->end = b->last + size;
  16. b->temporary = 1;
  17. return b;
  18. }

创建一个buf链表节点, 首先检查内存池pool->chain缓存中是否为空, 不为空直接取出使用, 为空重新分配.

  1. ngx_chain_t *
  2. ngx_alloc_chain_link(ngx_pool_t *pool)
  3. {
  4. ngx_chain_t *cl;
  5. cl = pool->chain;
  6. if (cl) {
  7. pool->chain = cl->next;
  8. return cl;
  9. }
  10. cl = ngx_palloc(pool, sizeof(ngx_chain_t));
  11. if (cl == NULL) {
  12. return NULL;
  13. }
  14. return cl;
  15. }

直接创建一个ngx_buf_t链表

  1. ngx_chain_t *
  2. ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs)
  3. {
  4. u_char *p;
  5. ngx_int_t i;
  6. ngx_buf_t *b;
  7. ngx_chain_t *chain, *cl, **ll;
  8. /*首先分配所有buf需要的一整块内存, 没有循环分配小内存, 显然为了提高速度, 处处体现了作者对代码质量和性能的要求之高*/
  9. p = ngx_palloc(pool, bufs->num * bufs->size);
  10. if (p == NULL) {
  11. return NULL;
  12. }
  13. /*这里用一个二级指针保存第一个节点指针地址, 同样也保存后面节点指针地址, 为什么这么干, 每次保存下上次节点也可以实现,
  14. *这么干少了一次循环内的判断, 否则我们需要判断出第一次循环, 并给chain赋值
  15. */
  16. ll = &chain;
  17. for (i = 0; i < bufs->num; i++) {
  18. b = ngx_calloc_buf(pool);
  19. if (b == NULL) {
  20. return NULL;
  21. }
  22. b->pos = p;
  23. b->last = p;
  24. b->temporary = 1;
  25. b->start = p;
  26. p += bufs->size;
  27. b->end = p;
  28. cl = ngx_alloc_chain_link(pool);
  29. if (cl == NULL) {
  30. return NULL;
  31. }
  32. cl->buf = b;
  33. /*ll保存的上一个节点指针的指针, 赋值相当于给上一个节点next指针赋值*/
  34. *ll = cl;
  35. /*取本节点next指针地址, 用于下次循环赋值使用*/
  36. ll = &cl->next;
  37. }
  38. *ll = NULL;
  39. return chain;
  40. }

buf链表添加或者copy, 我觉得这里叫append(附加)可能更好, 因为只是将in链表复制到chain链表后面, 可以看到这里用到了和上面同样的二级指针进行操作.

  1. ngx_int_t
  2. ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in)
  3. {
  4. ngx_chain_t *cl, **ll;
  5. ll = chain;
  6. for (cl = *chain; cl; cl = cl->next) {
  7. ll = &cl->next;
  8. }
  9. while (in) {
  10. cl = ngx_alloc_chain_link(pool);
  11. if (cl == NULL) {
  12. return NGX_ERROR;
  13. }
  14. cl->buf = in->buf;
  15. *ll = cl;
  16. ll = &cl->next;
  17. in = in->next;
  18. }
  19. *ll = NULL;
  20. return NGX_OK;
  21. }

更新链表函数功能是回收busy和out链表中闲置资源, 如果tag标志位与传入的一致, 则链表回收到free链表中, 否则直接释放会pool中, 多用于过滤模块

  1. void
  2. ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy,
  3. ngx_chain_t **out, ngx_buf_tag_t tag)
  4. {
  5. ngx_chain_t *cl;
  6. if (*busy == NULL) {
  7. *busy = *out;
  8. } else {
  9. for (cl = *busy; cl->next; cl = cl->next) { /* void */ }
  10. cl->next = *out;
  11. }
  12. *out = NULL;
  13. while (*busy) {
  14. cl = *busy;
  15. if (ngx_buf_size(cl->buf) != 0) {
  16. break;
  17. }
  18. if (cl->buf->tag != tag) {
  19. *busy = cl->next;
  20. ngx_free_chain(p, cl);
  21. continue;
  22. }
  23. cl->buf->pos = cl->buf->start;
  24. cl->buf->last = cl->buf->start;
  25. *busy = cl->next;
  26. cl->next = *free;
  27. *free = cl;
  28. }
  29. }

NGINX(一)内存结构的更多相关文章

  1. nginx的内存管理

    先来看内存池的实现,nginx的内存池实现的非常简单. 这里内存池的一些图表可以看老朱同学的slides : http://blog.zhuzhaoyuan.com/2009/09/nginx-int ...

  2. Nginx源码研究四:NGINX的内存管理

    关于nginx的内存使用,我们先看代码,下面是nginx_cycle.c中对全局数据结构cycle的初始化过程 pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, ...

  3. Nginx 之 内存池

    1.基本结构 先来学习一下nginx内存池的几个主要数据结构:[见:./src/core/ngx_palloc.h/.c]     ngx_pool_data_t(内存池数据块结构) 1: typed ...

  4. Nginx 的进程结构,你明白吗?

    Nginx 进程结构 这篇文章我们来看下 Nginx 的进程结构,Nginx 其实有两种进程结构: 单进程结构 多进程结构 单进程结构实际上不适用于生产环境,只适合我们做开发调试使用.因为在生产环境中 ...

  5. jvm系列(二):JVM内存结构

    JVM内存结构 所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能 ...

  6. JVM之内存结构

    JVM是按照运行时数据的存储结构来划分内存结构的.JVM在运行Java程序时,将他们划分成不同格式的数据,分别存储在不同的区域,这些数据就是运行时数据.运行时数据区域包括堆,方法区,运行时常量池,程序 ...

  7. Delphi XE7中各种字符串与字符类型的内存结构

    1. ShortString 类型 定义:type ShortString = string[255]; 内存结构与大小:ShortString 是每个字符为单字节的字符串.ShortString 的 ...

  8. Oracle之内存结构(SGA、PGA)

    一.内存结构 SGA(System Global Area):由所有服务进程和后台进程共享: PGA(Program Global Area):由每个服务进程.后台进程专有:每个进程都有一个PGA. ...

  9. UNDO内存结构剖析

    UNDO内存结构剖析 一.场景 Oracle的 C事物从早上9:00开始读取A表全部10w行数据,这个而读取需要经历5分钟.在9:01的时候,B事物将A表删除100条记录,那么,当9:05的时候,事物 ...

随机推荐

  1. 【BZOJ 1070】[SCOI2007]修车

    Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使 ...

  2. ExtJs 4.2.1 报错:Uncaught TypeError: Cannot call method 'getItems' of null

    做项目的时候遇到这个问题,搞了一上午终于解决了,让我们看看是什么问题: buttons: [ { text: '保存', icon: '../../../Images/extjs/disk.png', ...

  3. Linux学习笔记(4)-文本编辑器vi的使用

    vi的三种编辑模式 命令模式(Command mode) 在此模式下可以控制光标的移动,可以删除字符,删除行,还可以对某个段落进行复制和移动 输入模式(Insert mode) 只有在此模式下,可以输 ...

  4. Spring 注解 @Resource和@Autowired(转)

    鸣谢:http://my.oschina.net/u/216467/blog/205951 @Resource和@Autowired两者都是做bean的注入使用. 其实@Resource并不是Spri ...

  5. ExtJS4.2学习(八)表格限制输入数据的类型(转)

    鸣谢:http://www.shuyangyang.com.cn/jishuliangongfang/qianduanjishu/2013-11-14/177.html --------------- ...

  6. c_str 以及atoi

    const char *c_str();c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同. 这是为了与c语言兼容,在c语言中没有string类型,故必须通过string类 ...

  7. Ubuntu环境下手动配置openSSH

    配置openSSH 1.手动下载压缩文件(.tar.gz) zlib-1.2.7.tar.gz openssl-1.0.1j.tar.gz openssh-6.0p1.tar.gz 2.安装zlib ...

  8. Java中的try、catch、finally块简单的解析

    package com.wangzhu; import java.util.HashMap; import java.util.Map; /** * 在try.catch.finally块中,若try ...

  9. codeforces #313 div1 E

    首先我们要注意到一个事情 如果一个灯塔向左覆盖,那么比他小的某个灯塔如果向左覆盖的端点大于当前塔向左覆盖的端点,他一定向右覆盖 对于当前灯塔向右覆盖也是同理 那么我们只需要记录当前覆盖到的端点就可以完 ...

  10. codeforces #310 div1 D

    一开始写了个暴力模拟绳子的摆动轨迹 然后在Test 16 T掉了 后来%了一下别人的代码,发现需要对特殊情况进行特殊处理 首先我们考虑绳子的向右摆动,设当前位置为p,绳子当前长度为L 如果其旋转中心位 ...