nginx学习——从基本hash表到支持通配符的hash表(下)

本文深入探讨了nginx如何实现支持通配符的hash表,以解决带有通配符的域名字符串匹配问题。文章介绍了数据结构、内存布局、初始化过程以及查找策略,揭示了nginx在处理通配符时的精妙设计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上一篇博文介绍了nginx中基本hash表的实现,今天主要是来介绍nginx是如何实现支持通配符的hash表。话说在看支持通配符的hash表源码时我惊奇地发现它的设计思路居然和我之前设计的中文字典树基本一致,觉得nginx的设计也不过如此,但是看完hash表源码后我才发现我还是too young too simple,nginx的hash表考虑到的问题我想的要多得多!


二、支持通配符的hash表

nginx为了处理带有通配符的域名字符串的匹配问题,实现了支持通配符的hash表nginx中的通配符有两种形式:一种是通配符在前面的例如“*.test.com”,这样可以省略"*"号,写成“.test.com”;还有一种是通配符在后面的例如"www.test.*",这样域名不能省略“*”号,因为这样的通配符可以匹配“www.test.com”、“www.test.cn”、“www.test.org”等域名。注意:nginx不能同时包含在前和在后的通配符例如“*.test.*”。

而这个支持通配符的hash表ngx_hash_wildcard_t实际上是对基本hash表的一层封装(后面会讲到)。

在查找的字符串时,先是到基本hash表中查找元素,如果没有找到就去前置通配符的hash表中查找,如果还是没找到就去后置通配符的hash表中查找。


(1)支持通配符hash表的数据结构

//带通配符的hash表结构
typedef struct
{
    ngx_hash_t        hash;// 基本散列表
    void              *value;//指向真正的value或NULL
} ngx_hash_wildcard_t;
//组合类型哈希表 
typedef struct
{
    ngx_hash_t            hash;//基本hash表
    ngx_hash_wildcard_t  *wc_head;//前置通配符hash表
    ngx_hash_wildcard_t  *wc_tail;//后置通配符hash表
} ngx_hash_combined_t;

(2)带通配符hash表的内存布局图

nginx中通过多级hash实现了通配符的hash表,如下图所示:


(3)支持通配符hash表的初始化

nginx在初始化通配符的hash表时,实际上将key字符串以“.”为分隔符拆分成多个key字段。将所有key字符串的第一个key字段去重后存到一个基本hash表中。再将所有有相同的第一个key字段的字符串(可能有好几组)去掉第一个key字段后分别递归处理。

总的流程如下:为临时数组申请空间->遍历数组中元素找出当前字符串的第一个key字段并放入curr_names数组->将具有相同key字段的key字符串的剩余部分放入next_names数组->递归处理next_names数组->回到第二步,如果已经遍历完则将curr_names数组元素放入hash表。

初始化函数为ngx_int_t ngx_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
注意:这里的传入参数names数组是经过处理后的字符串数组。对于字符串数组 "*.test.yexin.com"、".yexin.com"、"*.example.com"、"*.example.org"、".yexin.org"处理完成之后就变成了
"com.yexin.test."、"com.yexin"、"com.example."、"org.example."、"org.yexin"。

1、为临时数组申请空间

由于是把所有key字符串的第一个key字段提取出来,那么不重复的key字段一定不会超过nelts,同样不重复的去掉key字符串剩余部分字符串个数也不会超过nelts个。

//为临时数组curr_names申请空间,用于存放当前节点的key字段数组
if (ngx_array_init(&curr_names, hinit->temp_pool, nelts, sizeof(ngx_hash_key_t)) != NGX_OK)
{
    return NGX_ERROR;
}
//为临时数组next_names申请空间,用于存放除去当前key字段后剩余字符串数组
if (ngx_array_init(&next_names, hinit->temp_pool, nelts, sizeof(ngx_hash_key_t)) != NGX_OK)
{
    return NGX_ERROR;
}

2、遍历数组中元素找出当前字符串的第一个key字段并放入 curr_names数组
把所有字符串"com.yexin.test."、"com.yexin"、"com.example."、"org.example."、"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值