`
superhj1987
  • 浏览: 203363 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Nginx源码分析之基本数据结构

阅读更多

原文链接:http://srhang.me/blog/2014/07/25/nginx-data-structure/

引言

nginx实现中有很多结构体,一般命名为ngx_xxx_t。这些结构体分散在许多头文件中。src/core/ngx_core.h中把几乎所有的头文件都集合起来。也因此造成了nginx各部分源代码的耦合。但实际上nginx各个部分逻辑划分还是很明确的,整体上是一种松散的结构。

作者之所以重复造了这些轮子,无非是为了追求高效。查看这些数据结构的源码,的确是设计的比较精巧,也保证了对内存足够小的占用以及各种操作的高效。

数据结构

nginx实现中有很多结构体,一般命名为ngx_XXX_t。这些结构体分散在许多头文件中。src/core/ngx_core.h中把几乎所有的头文件都集合起来。也因此造成了nginx各部分源代码的耦合。但实际上nginx各个部分逻辑划分还是很明确的,整体上是一种松散的结构。

  • ngx_str_t

  typedef struct{
      size_t len;
      u_char *data;
  }ngx_str_t;

这是nginx对字符串的实现,源码在ngx_string.h中。len指的是字符串的长度(不包括\0),data指向字符串。这种设计一方面,在计算字符创长度时只需要读取len字段即可,另一方面可以重复引用一段字符串内存。

常用api:

    #define ngx_string(str) { sizof(str) - 1},(u_char *) str } //从一个普通字符串构造出一个nginx字符串,用sizeof计算长度,故参数必须是一个常量字符串。

    #define ngx_null_string {0,NULL}

    ngx_strncmp(s1,s2,n)

    ngx_strcm(s1,s2)
  • ngx_pool_t

struct ngx_pool_s {
      ngx_pool_data_t       d;
      size_t                max;
      ngx_pool_t           *current;
      ngx_chain_t          *chain;
      ngx_pool_large_t     *large;
      ngx_pool_cleanup_t   *cleanup;
      ngx_log_t            *log;
  };

这个数据结构在nginx中是一个非常重要的数据结构。用来管理一系列的资源(如内存、文件等 ,使得对这些资源的使用和释放统一进行。这个是在c语言编程中值得借鉴的一个东西,代码中如果到处都是malloc和free的话,不仅会导致内存泄露,也会使代码难以阅读和维护。

  • ngx_array_t

 struct ngx_array_s {
      void        *elts; //指向实际的存储区域
      ngx_uint_t   nelts; //数组实际元素个数
      size_t       size; //数组单个元素的大小,单位是字节
      ngx_uint_t   nalloc; //数组的容量
      ngx_pool_t  *pool; //该数组用来分配内存的内存池
};
  • ngx_hash_t

    • ngx_hash_t不像其他的hash表的实现,可以插入删除元素,只能一次初始化。
    • 解决冲突使用的是开链法,但实际上是开了一段连续的存储空间,和数组差不多。 

  ngx_int_t ngx_hash_init(ngx_hash_init_t hinit, ngx_hash_key_t names,ngx_uint_t nelts);//ngx_hash_t的初始化,ngx_hash_init_t提供了初始化一个hash表所需要的一些基本信息
  
  typedef struct {
      ngx_hash_t       *hash; //指向hash表
      ngx_hash_key_pt   key; //指向从字符串生成hash值的hash函数。默认的实现为ngx_hash_key_lc
      ngx_uint_t        max_size; //hash表中的桶的个数
      ngx_uint_t        bucket_size; //每个桶的最大限制大小,单位是字节
      char             *name; //hash表的名字
      ngx_pool_t       *pool; //hash表分配内存使用的pool
      ngx_pool_t       *temp_pool; //使用的临时pool,初始化完成后,可以释放和销毁
  } ngx_hash_init_t;

  typedef struct {                
      ngx_str_t         key;              
      ngx_uint_t        key_hash;             
      void             *value;            
  } ngx_hash_key_t;
  
void *ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len); //在hash里面查找key对应的value。
  • ngx_chain_t

nginx的filter模块在处理从别的filter模块或者是handler模块传递过来的数据,数据一个链表的形式(ngx_chain_t)进行传递。

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

创建ngx_chain_t对象

ngx_chain_t *ngx_alloc_chain_link(ngx_pool_t *pool);

释放一个ngx_chain_t类型的对象。如果要释放整个chain,则迭代此链表,对每个节点使用此宏即可。

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

对ngx_chaint_t类型的释放,并不是真的释放了内存,而仅仅是把这个对象挂在了这个pool对象的一个叫做chain的字段对应的chain上,以供下次从这个pool上分配ngx_chain_t类型对象的时候,快速的从这个pool->chain上取下链首元素就返回了,当然,如果这个链是空的,才会真的在这个pool上使用ngx_palloc函数进行分配。

  • ngx_buf_t

ngx_buf_t是ngx_chain_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;
        ngx_file_t      *file;
        ngx_buf_t       *shadow;


        /* 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;
        unsigned         last_in_chain:1;

        unsigned         last_shadow:1;
        unsigned         temp_file:1;

        /* STUB */ int   num;
};
  • ngx_list_t

和普通的链表实现相比,它的节点是一个固定大小的数组。在初始化的时候,我们需要设定元素需要占用的空间大小,每个节点数组的容量大小。在添加元素到这个list里面的时候,会在最尾部的节点里的数组上添加元素,如果这个节点的数组存满了,就再增加一个新的节点到这个list里面去。

typedef struct {
        ngx_list_part_t  *last; //指向该链表的最后一个节点
        ngx_list_part_t   part; //指向该链表首个存放具体元素的节点
        size_t            size; //链表中存放的具体元素所需内存大小
        ngx_uint_t        nalloc; //每个节点所含的固定大小的数组的容量
        ngx_pool_t       *pool; //该list使用的分配内存的pool
    } ngx_list_t;

    struct ngx_list_part_s {
        void             *elts; //节点中存放具体元素的内存的开始地址   
        ngx_uint_t        nelts; //节点中已有元素个数,不能大于 nalloc
        ngx_list_part_t  *next; //指向下一个节点
    };

    ngx_list_t *ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size); //创建一个ngx_list_t类型的对象,并对该list的第一个节点分配存放元素的内存空间。

    pool:   分配内存使用的pool。
    n:  每个节点固定长度的数组的长度。
    size:   存放的具体元素的个数。
  • ngx_queue_t

struct ngx_queue_s {
      ngx_queue_t  *prev;
      ngx_queue_t  *next;
};

 

链表节点的数据成员并没有生命在链表节点的结构体中,只是声明了前向和后向指针。使用的时候需要定义一个哨兵节点。具体存放数据的节点称之为数据节点。对于数据节点,需要在数据结构体中加入一个类型为ngx_queue_s的域。使用下面的函数进行数据插入,其中x为数据节点的queue_t域。

    #define ngx_queue_insert_head(h, x)                         \
        (x)->next = (h)->next;                                  \
        (x)->next->prev = x;                                    \
        (x)->prev = h;                                          \
        (h)->next = x

    #define ngx_queue_insert_after   ngx_queue_insert_head

    #define ngx_queue_insert_tail(h, x)                          \
        (x)->prev = (h)->prev;                                   \
        (x)->prev->next = x;                                     \
        (x)->next = h;                                           \
        (h)->prev = x
    获得数据时,使用ngx_queue_data()宏。
    #define ngx_queue_data(q, type, link)                        \
        (type *) ((u_char *) q - offsetof(type, link))
0
0
分享到:
评论

相关推荐

    Nginx源码分析

    Nginx源码分析 1. Nginx代码的目录和结构 2. 基本数据结构 3. nginx的core module 的结构和运行机制 4. nginx的http module 的结构和运行机制

    nginx线程池源码分析

     本文只列出了关键数据结构和API,重在理解nginx线程池设计思路。完整代码在最后的链接里。  1.任务节点 typedef void (*CB_FUN)(void *); //任务结构体 typedef struct task { void *argv; //任务函数的参数...

    Reading-and-comprehense-nginx:nginx-1.9.2源码通读分析注释,记录学习nginx源代码的过程,持续更新

    nginx的以下功能模块的相关代码已经阅读,并进行了编码和相关数据结构进行了详细的注释,主要参考书籍为淘宝陶辉先生的《深入理解Nginx:模块开发与架构解析》,可以采用书中没有讲到的相关部分功能进行了扩展,...

    Java思维导图xmind文件+导出图片

    redis数据结构分析 Redis主从复制原理及无磁盘复制分析 Redis管道模式详解 Redis缓存与数据库一致性问题解决方案 基于redis实现分布式实战 图解Redis中的AOF和RDB持久化策略的原理 redis读写分离架构实践 ...

    java8集合源码分析-notes:记录的技术笔记或博客

    集合源码分析 ZhongJinHacker的博客 Springboot SpringCloud Netty 数据库 docker-compose docker git java K8S Linux Mac Nginx Product 设计模式 数据结构与算法 MongoDB HBase Kafka 手把手撸一个聊天系统 其他

    JAVA开发五年程序员简历模版

    包含了多个模块的面试题讲解,如:Redis、MySQL、框架、微服务、消息中间件、数据结构、Java集合源码分析、多线程、JVM、设计模式、高并发场景、企业实际问题场景等等各个方面逐一讲解。 1、具备扎实的编程基础,...

    python入门到高级全栈工程师培训 第3期 附课件代码

    04 socketserver源码分析tcp版本 05 socketserver源码分析udp版 06 ftp作业要求讲解 07 补充:认证客户端链接合法性 第32章 01 FTP之参数解析与命令分发 02 FTP之逻辑梳理 03 FTP之验证功能 05 FTP之文件上传 06 ...

    开涛高可用高并发-亿级流量核心技术

    12.2.2 HttpClient连接池源码分析 240 12.2.3 HttpClient 4.2.3配置 241 12.2.4 问题示例 243 12.3 线程池 244 12.3.1 Java线程池 245 12.3.2 Tomcat线程池配置 248 13 异步并发实战 250 13.1 同步阻塞调用 251 13.2...

    基于字符级卷积神经的中文情感分析算法源码+项目说明.zip

    1. 将顾客打分和评论情感进行两极映射,使用数据自动标注和基于弱监督预训练的数据增强方式自动扩充和优化数据集,实验证实了在情感分类中,使用本文的字符级卷积神经网络(C-CNN-SA)可以在不依赖分词的情况下,达到...

    安卓java读取网页源码-MyProjects:邵茂仁的作品附件

    熟悉常用设计模式、数据结构、多线程、HTTP,TCP/IP协议、UML建模,了解JVM内存管理及调优 熟练使用SpringBoot、SpringMVC,了解SpringCloud,初步研究过Spring、JDK部分底层源码及思想 熟练使用MySQL、Redis、...

    java8源码-Java-Interview:java面试相关的一些问题

    spring、spring组件源码分析 database 数据库 动态的切换数据源,你会怎么切?读写分离? struts 数据结构 thread 多线程、并发 有关多线程的一些小例子,在《Java编程思想》中可以找到源代码 io io操作 socket 网络...

    PHP 高级课程 商品秒杀系统 高并发高性能

    PHP商品秒杀系统 高并发高性能的极致挑战 完整视频+源码 深入基础技能 Linux / Nginx / Mysql / Redis ...从需求分析、数据结构创建 到基础功能开发、程序优化 实现完整开发思路 实现系统极致优化

    韩顺平java笔记和源码-golang:高朗

    很多章节仍然在完善中,如Go在微服务中的实践、框架的具体分析、Go的源码分析等等,后续会完善剩余章节,并分享实践经验,敬请期待。 贴士:基于Go的算法笔记一样在笔者计划之列,不过算法笔记位于系列中自成一系。 ...

    Learn-More-Do-Less:Java资料库

    源码分析 JDK 线程相关源码 框架使用 web 层框架 Spring MVC Webflux 持久层框架 Hibernate Mybatis 消息中间件框架 ActiveMQ kafka 全文搜索引擎 ElasticSearch DSL语法 Kibana 微服务架构 Spring Boot Spring ...

    我的博客

    线性代数Spring MVC源码 密码学 数据结构春云 扎比克斯詹金斯Linux 净额 MongoDB Ehcache3源码阅读 前端码头工人 Ansible 理念 多博JavaScript Windows工具 Spring整合 Spring安全Vue原始码阅读2.6.x Java CSS ...

    reading-and-annotate-mongodb-3.6:分布式文档数据库mongodb-3.6(mongos,mongod,wiredtiger存储引擎)

    阅读并注释mongodb-3.6 mongodb-3.6源码注释分析,持续更新 ================================== 对外演讲 专栏 其他 nginx高并发设计优秀思想替代其他高...他支持的数据结构非常松散,是类似json的bson格式,因此

    网络架构师148讲视频课程

    │ 第32节:Nginx的进程结构、基本配置.avi │ 第33节:Nginx常用核心模块指令.avi │ 第34节:Nginx的Http模块部分的指令.avi │ 第35节:Nginx的Location区段.avi │ 第36节:Nginx的反向代理模块.avi │ 第37节:...

    飞蛙B2B2C商城电商系统 v2.1.8.zip

    系统提供了调试模式,可用于开发过程的不同阶段,包括开发、测试和演示等情况,满足调试开发过程中的日志和分析需要,确定将来系统以最佳的方式进行部署。 4、查询机制丰富 系统内建丰富的查询机制,包括组合查询...

    t淘淘商城项目 商城项目 视频和源码教程 详细

    除了项目构建,Maven最核心的功能是软件包的依赖管理,能够自动分析项目所需要的依赖软件包,并到Maven中心仓库去下载。 A)管理依赖的jar包 B)管理工程之间的依赖关系。 3.2. Maven本地仓库 在当前系统用户的...

Global site tag (gtag.js) - Google Analytics