大家看到在构建一个ngx_hash_wildcard_t的时候,需要对通配符的哪些key进行预处理。这个处理起来比较麻烦。而当有一组key,这些里面既有无通配符的key,也有包含通配符的key的时候。我们就需要构建三个hash表,一个包含普通的key的hash表,一个包含前向通配符的hash表,一个包含后向通配符的hash表(或者也可以把这三个hash表组合成一个ngx_hash_combined_t)。在这种情况下,为了让大家方便的构造这些hash表,nginx提供给了此辅助类型。
1. ngx_hash_keys_arrays_t
以无通配符为例,该结构体用于散列表形成前的初始化。其中,keys_hash是一个分离链接法解决碰撞的散列表,每个str用来保存key,该散列表的作用是在将节点加入keys前,先检查keys_hash,避免keys中节点出现key冲突情况。
对于前向通配符情况,例如::“*.abc.com”,保存在keys->key中的字符串是“com.abc.”;“.abc.com”,保存在keys->key中的字符串是“com.abc”,两者差异是“.abc.com”既可以匹配www.abc.com,又可以匹配abc.com。
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;
hsize | 将要构建的hash表的桶的个数。对于使用这个结构中包含的信息构建的三种类型的hash表都会使用此参数。 |
pool | 构建这些hash表使用的pool。 |
temp_pool | 在构建这个类型以及最终的三个hash表过程中可能用到临时pool。该temp_pool可以在构建完成以后,被销毁掉。这里只是存放临时的一些内存消耗。 |
keys | 这是个二维数组,第一个维度代表的是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值,也就是是否有重复。 |
dns_wc_head | 放前向通配符key被处理完成以后的值。比如:“*.abc.com” 被处理完成以后,变成 “com.abc.” 被存放在此数组中。 |
dns_wc_tail | 存放后向通配符key被处理完成以后的值。比如:“mail.xxx.*” 被处理完成以后,变成 “mail.xxx.” 被存放在此数组中。 |
dns_wc_head_hash | 该值在调用的过程中用来保存和检测是否有冲突的前向通配符的key值,也就是是否有重复。 |
dns_wc_tail_hash | 该值在调用的过程中用来保存和检测是否有冲突的前向通配符的key值,也就是是否有重复。 |
2. ngx_hash_keys_array_init
对ngx_hash_keys_arrays_t进行初始化。
3. ngx_hash_add_key
将(key, value)对加入ngx_hash_keys_arrays_t初始化结构体,即填充该结构体的keys数组。
4. ngx_hash_init
形成无通配符的散列表。
5. ngx_hash_wildcard_init(形成含有通配符的散列表)
这里的传入参数names数组是经过处理后的字符串数组。对于字符串数组“.test.yexin.com”、“.yexin.com”、“.example.com”、“*.example.org”、“.yexin.org”处理完成之后就变成了“com.yexin.test.”、“com.yexin”、“com.example.”、“org.example.”、“org.yexin”。
1)把所有字符串"com.yexin.test."、“com.yexin”、“com.example.”、“org.example.”、“org.yexin"的第一个key字段提取出来,那么只有两个不相同的字段“com”、“org”。将这两个字段放入curr_names数组。
2)第一个key字段为"com"的字符串有"com.yexin”、“com.yexin.test.”、“com.example.”,那么剩余部分字符串即为"yexin"、“yexin.test”、“example”,存储next_names数组。
3)对next_names数组进行ngx_hash_wildcard_init递归调用。
4)将curr_names数组进行ngx_hash_init调用形成散列表。
00 - value 是 “example.com” 和 “.example.com"的数据指针
01 - value 仅仅是".example.com"的数据指针
10 - value 是 支持通配符哈希表是 “example.com” 和”.example.com" 指针
11 - value 仅仅是支持通配符哈希表是 ".example.com"的指针