大家看到在构建一个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里。我们先来看一下该类型的定义。

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:

存放所有非通配符key的数组。

keys_hash:

这是个二维数组,第一个维度代表的是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值,也就是是否有重复。

在定义一个这个类型的变量,并对字段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表中进行查询。

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则相反。

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函数。