【笔记】深入理解Nginx-worker-03-Nginx中的数据类型和数据结构

Nginx定义、封装的一些基本数据结构

  1. 整型的封装
  2. typedef intptr_t ngx_int_t;
    typedef uintptr_t ngx_uint_t; 
    

  3. 字符串类型的封装
  4. typedef struct{
      size_t len;
      u_char *data;
    }ngx_str_t; 
    

    ngx_str_t只有两个成员,其中data指针指向字符串起始地址,len表示字符串的有效长度。

    注意:ngx_str_t的data成员指向的并不是普通的字符串,因为这段字符串未必会以’\0’作为结尾,所以使用时必须根据长度len来使用data成员。具体使用方法,参考P141.

  5. 链表容器
  6. typedef struct ngx_list_part_s ngx_list_part_t;
    struct ngx_list_part_s{
      void *elts;
      ngx_uint_t nelts;
      ngx_list_part_t *next;
    };
    typedef struct{
      ngx_list_part_t *last;
      ngx_list_part_t part;
      size_t size;
      ngx_uint_t nalloc;
      ngx_pool_t *pool;
    }ngx_list_t; 
    
    • size ngx_list_part_t中每个元素的大小
    • nalloc ngx_list_part_t数组的容量,即最多可存储多少个数据
    • part 链表的首个数组元素
    • last指向链表的最后一个数组元素
    • pool链表中管理内存分配的内存池对象
    • elts指向数组的起始地址
    • nelts表示数组中已经使用了多少个元素。当然,nelts必须小于ngx_list_t结构体中的nalloc
    • next下一个链表元素ngx_list_part_t的地址

    这里ngx_list_t 是相当于一个链表,而链表的每个元素是ngx_list_part_s(是一个数组)

    事实上,ngx_list_t中的所有数据都是由ngx_pool_t类型的pool内存池分配的,它们通常都是连续的内存

    ngx_list_t的内存分布情况:

    ngx_list_t_内存结构.png

    这里,pool内存池为其分配了连续的内存,最前端内存存储的是ngx_list_t结构中的成员,紧接着是第一个ngx_list_part_t结构占用的内存,然后是ngx_list_part_t结构指向的数组,它们一共占用size*nalloc字节,表示数组中拥有nalloc个大小为size的元素。其后面是第2个ngx_list_part_t结构以及它所指向的数组,依此类推

  7. 键值对封装
  8. typedef struct{
      ngx_uint_t hash;
      ngx_str_t key;
      ngx_str_t value;
      u_char *lowcase_key;
    }ngx_table_elt_t; 
    

  9. ngx_buf_t数据结构
  10. typedef struct ngx_buf_s ngx_buf_t;
    typedef void *ngx_buf_tag_t;
    struct ngx_buf_s{
      /*pos通常是用来告诉使用者本次应该从pos这个位置开始处理内存中的数据, 
      这样设置是因为同一个ngx_buf_t可能被多次反复处理。当然, 
      pos的含义是由使用它的模块定义的*/
      u_char *pos;
      /*last通常表示有效的内容到此为止, 注意, pos与last之间的内存是希望nginx处理的内容*/
      u_char *last;
      /*处理文件时, file_pos与file_last的含义与处理内存时的pos与last相同, 
      file_pos表示将要处理的文件位置, file_last表示截止的文件位置*/
      off_t file_pos;
      off_t file_last;
      //如果ngx_buf_t缓冲区用于内存, 那么start指向这段内存的起始地址
      u_char *start;
      //与start成员对应, 指向缓冲区内存的末尾
      u_char *end;
      /*表示当前缓冲区的类型, 例如由哪个模块使用就指向这个模块ngx_module_t变量的地址*/
      ngx_buf_tag_t tag;
      //引用的文件
      ngx_file_t *file;
      /*当前缓冲区的影子缓冲区, 该成员很少用到, 
      仅仅在12.8节描述的使用缓冲区转发上游服务器的响应时才使用了shadow成员, 
      这是因为Nginx太节约内存了, 分配一块内存并使用ngx_buf_t表示接收到的上游服务器响应后, 
      在向下游客户端转发时可能会把这块内存存储到文件中, 也可能直接向下游发送, 
      此时Nginx绝不会重新复制一份内存用于新的目的, 而是再次建立一个ngx_buf_t结构体指向原内存, 
      这样多个ngx_buf_t结构体指向了同一块内存, 它们之间的关系就通过shadow成员来引用。
      这种设计过于复杂, 通常不建议使用*/
      ngx_buf_t *shadow;
      //临时内存标志位, 为1时表示数据在内存中且这段内存可以修改
      unsigned temporary:1;
      //标志位, 为1时表示数据在内存中且这段内存不可以被修改
      unsigned memory:1;
      //标志位, 为1时表示这段内存是用mmap系统调用映射过来的, 不可以被修改
      unsigned mmap:1;
      //标志位, 为1时表示可回收
      unsigned recycled:1;
      //标志位, 为1时表示这段缓冲区处理的是文件而不是内存
      unsigned in_file:1;
      //标志位, 为1时表示需要执行flush操作
      unsigned flush:1;
      /*标志位, 对于操作这块缓冲区时是否使用同步方式, 需谨慎考虑, 这可能会阻塞Nginx进程, 
      Nginx中所有操作几乎都是异步的, 这是它支持高并发的关键。
      有些框架代码在sync为1时可能会有阻塞的方式进行I/O操作, 它的意义视使用它的Nginx模块而定*/
      unsigned sync:1;
      /*标志位, 表示是否是最后一块缓冲区, 因为ngx_buf_t可以由ngx_chain_t链表串联起来, 
      因此, 当last_buf为1时, 表示当前是最后一块待处理的缓冲区*/
      unsigned last_buf:1;
      //标志位, 表示是否是ngx_chain_t中的最后一块缓冲区
      unsigned last_in_chain:1;
      /*标志位, 表示是否是最后一个影子缓冲区, 与shadow域配合使用。通常不建议使用它*/
      unsigned last_shadow:1;
      //标志位, 表示当前缓冲区是否属于临时文件
      unsigned temp_file:1;
    }; 
    

  11. ngx_chain_t数据结构
  12. typedef struct ngx_chain_s ngx_chain_t;
    struct ngx_chain_s{
      ngx_buf_t *buf;
      ngx_chain_t *next;
    }; 
    

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部