大家看到在构建一个ngx_hash_wildcard_t的时候,需要对通配符的哪些key进行预处理。这个处理起来比较麻烦。而当有一组key,这些里面既有无通配符的key,也有包含通配符的key的时候。我们就需要构建三个hash表,一个包含普通的key的hash表,一个包含前向通配符的hash表,一个包含后向通配符的hash表(或者也可以把这三个hash表组合成一个ngx_hash_combined_t)。在这种情况下,为了让大家方便的构造这些hash表,nginx提供给了此辅助类型。
该类型以及相关的操作函数也定义在src/core/ngx_hash.h|c里。我们先来看一下该类型的定义。
[](http:// "点击提交Issue,反馈你的意见...")
typedef struct {
ngx_uint_t hsize;
ngx_pool_t *pool;
ngx_pool_t *temp_pool;
ngx_array_t keys;
ngx_array_t *keys_hash;
ngx_array_t dns_wc_head;
ngx_array_t *dns_wc_head_hash;
ngx_array_t dns_wc_tail;
ngx_array_t *dns_wc_tail_hash;
} ngx_hash_keys_arrays_t;
<table class="docutils field-list" frame="void" rules="none" style="margin: 0px -0.5em; border: 0px; color: rgb(0, 0, 0); font-family: 'segoe UI', sans-serif; letter-spacing: -0.1599999964237213px; line-height: 24px; white-space: normal; background-color: rgb(255, 255, 255);"><colgroup><col class="field-name"/><col class="field-body"/></colgroup><tbody valign="top"><tr class="field-odd field"><th class="field-name" style="padding: 1px 8px 1px 5px; border: 0px !important;">hsize:</th><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">将要构建的hash表的桶的个数。对于使用这个结构中包含的信息构建的三种类型的hash表都会使用此参数。</td></tr><tr class="field-even field"><th class="field-name" style="padding: 1px 8px 1px 5px; border: 0px !important;">pool:</th><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">构建这些hash表使用的pool。</td></tr><tr class="field-odd field"><th class="field-name" style="padding: 1px 8px 1px 5px; border: 0px !important;">temp_pool:</th><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">在构建这个类型以及最终的三个hash表过程中可能用到临时pool。该temp_pool可以在构建完成以后,被销毁掉。这里只是存放临时的一些内存消耗。</td></tr><tr class="field-even field"><th class="field-name" style="padding: 1px 8px 1px 5px; border: 0px !important;">keys:</th><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">存放所有非通配符key的数组。</td></tr><tr class="field-odd field"><th class="field-name" style="padding: 1px 8px 1px 5px; border: 0px !important;">keys_hash:</th><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">这是个二维数组,第一个维度代表的是bucket的编号,那么keys_hash[i]中存放的是所有的key算出来的hash值对hsize取模以后的值为i的key。假设有3个key,分别是key1,key2和key3假设hash值算出来以后对hsize取模的值都是i,那么这三个key的值就顺序存放在keys_hash[i][0],keys_hash[i][1], keys_hash[i][2]。该值在调用的过程中用来保存和检测是否有冲突的key值,也就是是否有重复。</td></tr><tr class="field-even field"><th class="field-name" style="padding: 1px 8px 1px 5px; border: 0px !important;">dns_wc_head:</th><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">放前向通配符key被处理完成以后的值。比如:“*.abc.com” 被处理完成以后,变成 “com.abc.” 被存放在此数组中。</td></tr><tr class="field-odd field"><th class="field-name" style="padding: 1px 8px 1px 5px; border: 0px !important;">dns_wc_tail:</th><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">存放后向通配符key被处理完成以后的值。比如:“mail.xxx.*” 被处理完成以后,变成 “mail.xxx.” 被存放在此数组中。</td></tr><tr class="field-even field"><th class="field-name" colspan="2" style="padding: 1px 8px 1px 5px; border: 0px !important;">dns_wc_head_hash:</th></tr><tr class="field-even field"><td style="padding: 1px 8px 1px 5px; border: 0px !important;"> </td><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">该值在调用的过程中用来保存和检测是否有冲突的前向通配符的key值,也就是是否有重复。</td></tr><tr class="field-odd field"><th class="field-name" colspan="2" style="padding: 1px 8px 1px 5px; border: 0px !important;">dns_wc_tail_hash:</th></tr><tr class="field-odd field"><td style="padding: 1px 8px 1px 5px; border: 0px !important;"> </td><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">该值在调用的过程中用来保存和检测是否有冲突的后向通配符的key值,也就是是否有重复。</td></tr></tbody></table>
在定义一个这个类型的变量,并对字段pool和temp_pool赋值以后,就可以调用函数ngx_hash_add_key把所有的key加入到这个结构中了,该函数会自动实现普通key,带前向通配符的key和带后向通配符的key的分类和检查,并将这个些值存放到对应的字段中去, 然后就可以通过检查这个结构体中的keys、dns_wc_head、dns_wc_tail三个数组是否为空,来决定是否构建普通hash表,前向通配符hash表和后向通配符hash表了(在构建这三个类型的hash表的时候,可以分别使用keys、dns_wc_head、dns_wc_tail三个数组)。
构建出这三个hash表以后,可以组合在一个ngx_hash_combined_t对象中,使用ngx_hash_find_combined进行查找。或者是仍然保持三个独立的变量对应这三个hash表,自己决定何时以及在哪个hash表中进行查询。
[](http:// "点击提交Issue,反馈你的意见...")
ngx_int_t ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type);
初始化这个结构,主要是对这个结构中的ngx_array_t类型的字段进行初始化,成功返回NGX_OK。
| ha: | 该结构的对象指针。 |
|-----|-----|
| type: | 该字段有2个值可选择,即NGX_HASH_SMALL和NGX_HASH_LARGE。用来指明将要建立的hash表的类型,如果是NGX_HASH_SMALL,则有比较小的桶的个数和数组元素大小。NGX_HASH_LARGE则相反。 |
[](http:// "点击提交Issue,反馈你的意见...")
ngx_int_t ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key,
void *value, ngx_uint_t flags);
一般是循环调用这个函数,把一组键值对加入到这个结构体中。返回NGX_OK是加入成功。返回NGX_BUSY意味着key值重复。
| ha: | 该结构的对象指针。 |
|-----|-----|
| key: | 参数名自解释了。 |
| value: | 参数名自解释了。 |
| flags: | 有两个标志位可以设置,NGX_HASH_WILDCARD_KEY和NGX_HASH_READONLY_KEY。同时要设置的使用逻辑与操作符就可以了。NGX_HASH_READONLY_KEY被设置的时候,在计算hash值的时候,key的值不会被转成小写字符,否则会。NGX_HASH_WILDCARD_KEY被设置的时候,说明key里面可能含有通配符,会进行相应的处理。如果两个标志位都不设置,传0。 |
有关于这个数据结构的使用,可以参考src/http/ngx_http.c中的ngx_http_server_names函数。
- 上篇:nginx模块开发篇
- nginx平台初探
- 初探nginx架构
- nginx基础概念
- connection
- request
- keepalive
- pipe
- lingering_close
- 基本数据结构
- ngx_str_t
- ngx_pool_t
- ngx_array_t
- ngx_hash_t
- ngx_hash_wildcard_t
- ngx_hash_combined_t
- ngx_hash_keys_arrays_t
- ngx_chain_t
- ngx_buf_t
- ngx_list_t
- ngx_queue_t
- nginx的配置系统
- 指令参数
- 指令上下文
- nginx的模块化体系结构
- 模块的分类
- nginx的请求处理
- handler模块
- handler模块简介
- 模块的基本结构
- 模块配置结构
- 模块配置指令
- 模块上下文结构
- 模块的定义
- handler模块的基本结构
- handler模块的挂载
- handler的编写步骤
- 示例: hello handler 模块
- handler模块的编译和使用
- 更多handler模块示例分析
- http access module
- http static module
- http log module
- 过滤模块
- 过滤模块简介
- 过滤模块的分析
- upstream模块
- upstream模块
- upstream模块接口
- memcached模块分析
- 本节回顾
- 负载均衡模块
- 配置
- 指令
- 钩子
- 初始化配置
- 初始化请求
- peer.get和peer.free回调函数
- 本节回顾
- 其他模块
- core模块
- event模块
- 模块开发高级篇
- 变量
- 下篇:nginx原理解析篇
- nginx架构详解
- nginx的源码目录结构
- nginx的configure原理
- 模块编译顺序
- nginx基础设施
- 内存池
- nginx的启动阶段
- 概述
- 共有流程
- 配置解析
- nginx的请求处理阶段
- 接收请求流程
- http请求格式简介
- 请求头读取
- 解析请求行
- 解析请求头
- 请求体读取
- 读取请求体
- 丢弃请求体
- 多阶段处理请求
- 多阶段执行链
- POST_READ阶段
- SERVER_REWRITE阶段
- FIND_CONFIG阶段
- REWRITE阶段
- POST_REWRITE阶段
- PREACCESS阶段
- ACCESS阶段
- POST_ACCESS阶段
- TRY_FILES阶段
- CONTENT阶段
- LOG阶段
- Nginx filter
- header filter分析
- body filter分析
- ngx_http_copy_filter_module分析
- ngx_http_write_filter_module分析
- subrequest原理解析
- https请求处理解析
- 附录A 编码风格
- 附录B 常用API
- 附录C 模块编译,调试与测试