nginx学习——建立hash表的前提条件

来源:互联网 发布:故宫淘宝旗舰店 编辑:程序博客网 时间:2024/05/02 04:36

在前面两篇博文中分别介绍了nginx中普通hash表和带有通配符的hash表的建立和查找,今天主要是介绍建立hash表的前提条件,并在后面附上一个完整的hash表的实现(该部分代码为转载)。

一、建立hash表的前提条件

(1)为hash表提供数据的数据结构

ngx_hash_keys_arrays_t不负责构造hash表,但是它是使用ngx_hash_init和ngx_hash_wildcard_init的前提条件,也就是说,如果先构造好了ngx_hash_keys_arrays_t就可以简单地创造支持通配符的hash表了。

//哈希key数组typedef struct{    ngx_uint_t        hsize;//hash表桶个数    ngx_pool_t       *pool;//为nginx中永久存放的hash结构体分配空间的内存    ngx_pool_t       *temp_pool;//分配临时数据空间的内存池    ngx_array_t       keys;//保存不含通配符元素中间key的动态数组    ngx_array_t      *keys_hash;//处理不含通配符元素的简易hash表(动态数组)    ngx_array_t       dns_wc_head;//保存前置通配符元素中间key的动态数组    ngx_array_t      *dns_wc_head_hash;//处理前置通配符元素的简易hash表(动态数组)    ngx_array_t       dns_wc_tail;//保存后置通配符元素中间key的动态数组    ngx_array_t      *dns_wc_tail_hash;//处理后置通配符元素的简易hash表(动态数组)} ngx_hash_keys_arrays_t;

(2)哈希key数组的初始化
ngx_hash_keys_arrays_t中有3个动态数组keys、dns_wc_head、dns_wc_tail存放均为ngx_hash_key_t的元素类型,分别保存完全匹配key、带前缀通配符key、带后缀通配符key。同ngx_hash_key_arrays_t建立了3个简易的hash表,这3个hash表用于快速向上述3个动态数组容器插入元素,这该hash表的实质是存放动态数组的固定数组,用keys_hash、dns_wc_head_hash、dns_wc_tail_hash分别指向这3个hash表。

//哈希key数组初始化ngx_int_t ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type){    ngx_uint_t  asize;    //初始化元素较少    if (type == NGX_HASH_SMALL)    {        asize = 4;        ha->hsize = 107;    }    //初始化元素较多    else    {        asize = NGX_HASH_LARGE_ASIZE;        ha->hsize = NGX_HASH_LARGE_HSIZE;    }    //初始化存放非通配符key元素的动态数组    if (ngx_array_init(&ha->keys, ha->temp_pool, asize, sizeof(ngx_hash_key_t))!= NGX_OK)    {        return NGX_ERROR;    }    //初始化存放前缀通配符key元素的动态数组    if (ngx_array_init(&ha->dns_wc_head, ha->temp_pool, asize, sizeof(ngx_hash_key_t)) != NGX_OK)    {        return NGX_ERROR;    }    //初始化存放后缀通配符key元素的动态数组    if (ngx_array_init(&ha->dns_wc_tail, ha->temp_pool, asize, sizeof(ngx_hash_key_t)) != NGX_OK)    {        return NGX_ERROR;    }    //初始化不含通配符key的简易hash表(实质是存放动态数组的固定数组)    ha->keys_hash = ngx_pcalloc(ha->temp_pool, sizeof(ngx_array_t) * ha->hsize);    if (ha->keys_hash == NULL)    {        return NGX_ERROR;    }    //初始化前缀通配符key的简易hash表(实质是存放动态数组的固定数组)    ha->dns_wc_head_hash = ngx_pcalloc(ha->temp_pool, sizeof(ngx_array_t) * ha->hsize);    if (ha->dns_wc_head_hash == NULL)    {        return NGX_ERROR;    }    //初始化后缀通配符key的简易hash表(实质是存放动态数组的固定数组)    ha->dns_wc_tail_hash = ngx_pcalloc(ha->temp_pool, sizeof(ngx_array_t) * ha->hsize);    if (ha->dns_wc_tail_hash == NULL)    {        return NGX_ERROR;    }    return NGX_OK;}

(3)向哈希key数组添加key-value对
前面介绍了对于字串"com.yexin.test."、"com.yexin"、"com.example."、"org.example."、"org.yexin"的第一个key字段提取出来,那么不相同的字段只有“com”、"org"。最后存到curr_names数组中的也只有"com"和"org"两个元素。在把key字段添加到动态数组的过程中,为了知道该key字段之前是否已经添加,这里采用了一个简单的hash表,每次向动态数组中添加元素前都要去查hash表,这样添加同名key时,就可以通过hash值获得之前曾经添加过的key,从而判断是否合法或者以及是否进行元素合并操作。
总的流程:字符串检测->字符串处理->判断该key字符串是否在hash表中存在->若不存在则把元素(key-value)放入动态数组,并把key加入hash表
1、字符串检测
nginx中只接受形如"*.example.com"、".example.com"、"www.example.com"、"www.example.*"的字符串。
if (flags & NGX_HASH_WILDCARD_KEY){    //key中“*”出现次数    n = 0;    for (i = 0; i < key->len; i++)    {        if (key->data[i] == '*')        {            //key中“*”超过一个            if (++n > 1)            {                return NGX_DECLINED;            }        }        //key中有两个连续的"."        if (key->data[i] == '.' && key->data[i + 1] == '.')        {            return NGX_DECLINED;        }    }    //以"."开头的key,形如".example.com"    if (key->len > 1 && key->data[0] == '.')    {        skip = 1;        goto wildcard;    }    if (key->len > 2)    {        //以"*."开头的key,形如"*.example.com"        if (key->data[0] == '*' && key->data[1] == '.')        {            skip = 2;            goto wildcard;        }        //以".*"结尾的key,形如"www.example.*"        if (key->data[i - 2] == '.' && key->data[i - 1] == '*')        {            skip = 0;            last -= 2;            goto wildcard;        }    }    //出现过"*"号,又不满足以上几种情况    if (n)    {        return NGX_DECLINED;    }}

2、字符串处理
if (skip){    //将"*.example.com"转换成"com.example."    //或将".example.com" 转换成"com.example"    p = ngx_pnalloc(ha->temp_pool, last);    if (p == NULL)    {        return NGX_ERROR;    }    len = 0;    n = 0;    for (i = last - 1; i; i--)    {        if (key->data[i] == '.')        {            ngx_memcpy(&p[n], &key->data[i + 1], len);            n += len;            p[n++] = '.';            len = 0;            continue;        }        len++;    }    if (len)    {        ngx_memcpy(&p[n], &key->data[1], len);        n += len;    }    p[n] = '\0';    ......}else{    //将"www.example.*"转换成"www.example"    last++;    p = ngx_pnalloc(ha->temp_pool, last);    if (p == NULL)    {        return NGX_ERROR;    }    ngx_cpystrn(p, key->data, last);    ......}

3、判断该key字符串是否在hash表中存在
对于keys_hash、dns_wc_head_hash、dns_wc_tail_hash检测key字符串是否存在处理方式是一样的,这里用keys_hash来举例。
//对不含通配符key的元素的处理k = 0;for (i = 0; i < last; i++){    if (!(flags & NGX_HASH_READONLY_KEY))     {        key->data[i] = ngx_tolower(key->data[i]);    }    //计算该key的hash值    k = ngx_hash(k, key->data[i]);}//在不含通配符的简易hash表中查找相应的桶(动态数组)下标k %= ha->hsize;name = ha->keys_hash[k].elts;//该桶(动态数组)已经存在(之前已经初始化并存放过key)if (name){    //查找桶中是否存在和当前要存放的key相同的key    for (i = 0; i < ha->keys_hash[k].nelts; i++)    {        //长度不一样,一定不冲突        if (last != name[i].len)        {            continue;        }        //桶内之前已经存放过相同的key,冲突        if (ngx_strncmp(key->data, name[i].data, last) == 0)        {            return NGX_BUSY;        }    }}//初始化该元素要存放的桶(动态数组)else{    if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4, sizeof(ngx_str_t)) != NGX_OK)    {        return NGX_ERROR;    }}

4、若不存在则把元素(key-value)放入动态数组,并把key加入hash表
这里依然用不含通配符的key存入keys(动态数组)、keys_hash(hash表)来举例,前缀key、后缀key同理。
//将key存放到不含通配符的hash表keys_hash中name = ngx_array_push(&ha->keys_hash[k]);if (name == NULL){    return NGX_ERROR;}*name = *key;//将元素(key-value对)存放到不含通配符的动态数组keys中hk = ngx_array_push(&ha->keys);if (hk == NULL){    return NGX_ERROR;}hk->key = *key;hk->key_hash = ngx_hash_key(key->data, last);hk->value = value;return NGX_OK;

(4)哈希key数组的内存布局
例如将以下key-value对创建哈希key数组如下图所示。
key = "*..com."         value = "1.1.1.1"
key = "*.baidu.com.cn"  value = "180.97.33.107"
key = "*.baidu.com"     value = "180.97.33.107"
key = ".baidu.com"      value = "180.97.33.107"
key = "www.qq.*"        value = "14.17.42.40"
key = "*.google.com"    value = "93.46.8.89"
key = "www.qq.com"      value = "14.17.42.40"
key = "www.baidu.com"   value = "180.97.33.107"
key = "www.taobao.com"  value = "116.207.117.62"
key = "www.360.cn"      value = "119.84.14.199"
key = "www.google.com"  value = "93.46.8.89"
key = "www.sina.com.cn" value = "121.14.1.189"
key = "www.163.com"     value = "61.136.167.72"
key = "www.sohu.com"    value = "119.97.155.2"
key = "test.yexin.com"  value = "255.255.255.1"
key = ".baidu.com"      value = "180.97.33.107"
key = "test.yexin.*"    value = "255.255.255.255"
key = "www.qq.*"        value = "14.17.42.40"

二、完整的hash查找的实现
该部分内容转载自:http://www.cnblogs.com/chengxuyuancc/p/3782808.html
hash_test.h
#ifndef HASH_TEST_H#define HASH_TEST_H#include <stdio.h>#include "ngx_config.h"#include "ngx_conf_file.h"#include "nginx.h"#include "ngx_core.h"#include "ngx_string.h"#include "ngx_palloc.h"#include "ngx_array.h"#include "ngx_hash.h"#include "ngx_log.h"#define DEEPTH 4#define MAX_NUM 18 #define MAX_SIZE 1024#define BUCKET_SIZE 64 #define MAX_URL_LEN 15#define MAX_IP_LEN 15#define MAX_NUM2 3#define NGX_HASH_ELT_SIZE(name) (sizeof(void *) + ngx_align((name)->key.len + 2, sizeof(void *)))static ngx_str_t urls[MAX_NUM] = {    ngx_string("*..com."),  //1.1.1.1ngx_string("*.baidu.com.cn"),//180.97.33.107ngx_string("*.baidu.com"),//180.97.33.107ngx_string(".baidu.com"),//180.97.33.107    ngx_string("www.qq.*"),//14.17.42.40ngx_string("*.google.com"),//93.46.8.89    ngx_string("www.qq.com"),//14.17.42.40    ngx_string("www.baidu.com"),//180.97.33.107    ngx_string("www.taobao.com"),//116.207.117.62    ngx_string("www.360.cn"),//119.84.14.199    ngx_string("www.google.com"),  //93.46.8.89    ngx_string("www.sina.com.cn"),  //121.14.1.189    ngx_string("www.163.com"),  //61.136.167.72    ngx_string("www.sohu.com"),  //119.97.155.2    ngx_string("test.yexin.com"),  //255.255.255.1    ngx_string(".baidu.com"),  //180.97.33.107    ngx_string("test.yexin.*"),//255.255.255.255    ngx_string("www.qq.*"),//14.17.42.40};static ngx_str_t values[MAX_NUM] = {    ngx_string("1.1.1.1"),    ngx_string("180.97.33.107"),    ngx_string("180.97.33.107"),    ngx_string("180.97.33.107"),    ngx_string("14.17.42.40"),    ngx_string("93.46.8.89"),    ngx_string("14.17.42.40"),    ngx_string("180.97.33.107"),    ngx_string("116.207.117.62"),    ngx_string("119.84.14.199"),    ngx_string("93.46.8.89"),    ngx_string("121.14.1.189"),    ngx_string("61.136.167.72"),    ngx_string("119.97.155.2"),    ngx_string("255.255.255.1"),    ngx_string("180.97.33.107"),    ngx_string("255.255.255.255"),    ngx_string("14.17.42.40")};/* for finding test */static ngx_str_t urls2[MAX_NUM2] = {    ngx_string("*.xx.xx"),  //60.217.58.79    ngx_string("www.baidu.com"),  //117.79.157.242    ngx_string("www.baidu.")  //117.79.157.242};void* init_hash(ngx_pool_t *pool, ngx_hash_keys_arrays_t *ha, ngx_hash_combined_t *hash);void dump_pool(ngx_pool_t* pool);void dump_hash_array(ngx_array_t* a);void dump_combined_hash(ngx_hash_combined_t *hash, ngx_hash_keys_arrays_t *array);void dump_hash(ngx_hash_t *hash, ngx_array_t *array);void* add_urls_to_array(ngx_pool_t *pool, ngx_hash_keys_arrays_t *ha, ngx_array_t *url, ngx_array_t *value);void find_test(ngx_hash_combined_t *hash, ngx_str_t addr[], int num);void dump_hash_wildcard(ngx_hash_wildcard_t *wc_hash, ngx_uint_t deepth);#endif
hash_test.c
#include "hash_test.h"volatile ngx_cycle_t  *ngx_cycle;ngx_log_t ngx_log;void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, const char *fmt, ...){}static int ngx_http_cmp_dns_wildcards(const void *one, const void *two){    ngx_hash_key_t  *first, *second;    first = (ngx_hash_key_t *) one;    second = (ngx_hash_key_t *) two;    return ngx_dns_strcmp(first->key.data, second->key.data);}int main(/* int argc, char **argv */){    ngx_pool_t *pool = NULL;    ngx_hash_keys_arrays_t array;    ngx_hash_combined_t hash;ngx_array_t *key, *value;hash.wc_head = hash.wc_tail = NULL;    printf("--------------------------------\n");    printf("          the pool:\n");    printf("--------------------------------\n");    //create a new pool    pool = ngx_create_pool(1024, &ngx_log);    dump_pool(pool);    ngx_int_t loop;    printf("--------------------------------\n");    printf("create and add urls to it:\n");    printf("--------------------------------\n");if ((key = ngx_array_create(pool, MAX_NUM, sizeof(ngx_str_t))) == NULL){printf("Failed to initialize url!\n");        return -1;}if ((value = ngx_array_create(pool, MAX_NUM, sizeof(ngx_str_t))) == NULL){printf("Failed to initialize value!\n");        return -1;}ngx_str_t *temp;//常量字符串是不可修改的,而后面需要修改,所以重新拷贝一份for (loop = 0; loop < MAX_NUM; loop++){temp = ngx_array_push(key);temp->len = urls[loop].len;temp->data = ngx_palloc(pool, urls[loop].len);ngx_memcpy(temp->data, urls[loop].data, temp->len);}//由于key-value中的value的地址必须是4对齐的,所以需要重新拷贝一份vaulefor (loop = 0; loop < MAX_NUM; loop++){temp = ngx_array_push(value);temp->len = values[loop].len;temp->data = ngx_palloc(pool, values[loop].len);ngx_memcpy(temp->data, values[loop].data, temp->len);}   if (add_urls_to_array(pool, &array, key, value) == NULL){        printf("Failed to initialize array!\n");        return -1;    }    printf("--------------------------------\n");    printf("         array.keys :\n");    printf("--------------------------------\n");    dump_hash_array(&array.keys);    printf("--------------------------------\n");    printf("         array.dns_wc_head :\n");    printf("--------------------------------\n");   dump_hash_array(&array.dns_wc_head);    printf("--------------------------------\n");    printf("         array.dns_wc_tail :\n");    printf("--------------------------------\n");dump_hash_array(&array.dns_wc_tail);     printf("--------------------------------\n");    printf("         array.keys_hash :\n");    printf("--------------------------------\n");        for (int i = 0; i < 10007; i++)    {            if (array.keys_hash[i].nelts != 0)            {                printf("i = %d\n", i);            dump_hash_array(&(array.keys_hash[i]));            }    }    printf("--------------------------------\n");    printf("         array.dns_wc_head_hash :\n");    printf("--------------------------------\n");        for (int i = 0; i < 10007; i++)    {            if (array.dns_wc_head_hash[i].nelts != 0)            {                printf("i = %d\n", i);            dump_hash_array(&(array.dns_wc_head_hash[i]));            }    }    printf("--------------------------------\n");    printf("         array.dns_wc_tail_hash :\n");    printf("--------------------------------\n");        for (int i = 0; i < 10007; i++)    {            if (array.dns_wc_tail_hash[i].nelts != 0)            {                printf("i = %d\n", i);            dump_hash_array(&(array.dns_wc_tail_hash[i]));            }    }    printf("--------------------------------\n");    printf("          the pool:\n");    printf("--------------------------------\n");    dump_pool(pool);    if (init_hash(pool, &array, &hash) == NULL)    {        printf("Failed to initialize hash!\n");        return -1;    }    printf("--------------------------------\n");    printf("the hash:\n");    printf("--------------------------------\n");        dump_combined_hash(&hash, &array);    printf("\n");    printf("--------------------------------\n");    printf("the pool:\n");    printf("--------------------------------\n");    dump_pool(pool);    //find test    printf("--------------------------------\n");    printf("find test:\n");    printf("--------------------------------\n");    find_test(&hash, urls, MAX_NUM);    printf("\n");    find_test(&hash, urls2, MAX_NUM2);    //release    return 0;}void* init_hash(ngx_pool_t *pool, ngx_hash_keys_arrays_t *ha, ngx_hash_combined_t *hash){    ngx_hash_init_t hinit;    ngx_cacheline_size = 32;  //here this variable for nginx must be defined    hinit.hash = NULL;  //if hinit.hash is NULL, it will alloc memory for it in ngx_hash_init    hinit.key = &ngx_hash_key_lc;  //hash function    hinit.max_size = MAX_SIZE;    hinit.bucket_size = BUCKET_SIZE;    hinit.name = "my_hash_sample";    hinit.pool = pool;  //the hash table exists in the memory poolhinit.temp_pool = ha->temp_pool;    if (ha->keys.nelts) {  //无通配hinit.hash = &hash->hash;        if (ngx_hash_init(&hinit, ha->keys.elts, ha->keys.nelts) != NGX_OK) {            goto failed;        }    }    if (ha->dns_wc_head.nelts) {  //前缀通配hinit.hash = NULL;        ngx_qsort(ha->dns_wc_head.elts, (size_t) ha->dns_wc_head.nelts,                  sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards);printf("--------------------------------\n");printf("  array.dns_wc_head after sort:\n");printf("--------------------------------\n"); dump_hash_array(&ha->dns_wc_head);                if (ngx_hash_wildcard_init(&hinit, ha->dns_wc_head.elts,                                   ha->dns_wc_head.nelts)            != NGX_OK)        {            goto failed;        }        hash->wc_head = (ngx_hash_wildcard_t *) hinit.hash;    }    if (ha->dns_wc_tail.nelts) {  //后缀通配        ngx_qsort(ha->dns_wc_tail.elts, (size_t) ha->dns_wc_tail.nelts,                  sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards);printf("--------------------------------\n");printf("  array.dns_wc_tail after sort:\n");printf("--------------------------------\n"); dump_hash_array(&ha->dns_wc_tail);        hinit.hash = NULL;        if (ngx_hash_wildcard_init(&hinit, ha->dns_wc_tail.elts,                                   ha->dns_wc_tail.nelts)            != NGX_OK)        {            goto failed;        }        hash->wc_tail = (ngx_hash_wildcard_t *) hinit.hash;    }    //ngx_destroy_pool(ha->temp_pool);return hash;failed:    //ngx_destroy_pool(ha->temp_pool);    return NULL;}void dump_pool(ngx_pool_t* pool){    while (pool)    {        printf("pool = %p\n", pool);        printf("  .d\n");        printf("    .last = %p\n", pool->d.last);        printf("    .end = %p\n", pool->d.end);        printf("    .next = %p\n", pool->d.next);        printf("    .failed = %d\n", pool->d.failed);        printf("  .max = %d\n", pool->max);        printf("  .current = %p\n", pool->current);        printf("  .chain = %p\n", pool->chain);        printf("  .large = %p\n", pool->large);        printf("  .cleanup = %p\n", pool->cleanup);        printf("  .log = %p\n", pool->log);        printf("available pool memory = %d\n\n", pool->d.end - pool->d.last);        pool = pool->d.next;    }}void dump_hash_array(ngx_array_t* a){    char prefix[] = "              ";ngx_uint_t i;    if (a == NULL)        return;    printf("array = %p\n", a);    printf("  .elts = %p\n", a->elts);    printf("  .nelts = %d\n", a->nelts);    printf("  .size = %d\n", a->size);    printf("  .nalloc = %d\n", a->nalloc);    printf("  .pool = %p\n", a->pool);    printf("  elements:\n");    ngx_hash_key_t *ptr = a->elts;    for (i = 0; i < a->nelts; i++)    {    if (ptr[i].value)    {        printf("    %p: {key = (\"%.*s\"%.*s, %-2d), key_hash = %-11d , value = \"%.*s\"%.*s}\n", ptr + i, ptr[i].key.len, ptr[i].key.data, MAX_URL_LEN - ptr[i].key.len, prefix, ptr[i].key.len, ptr[i].key_hash, ((ngx_str_t*)ptr[i].value)->len, ((ngx_str_t*)ptr[i].value)->data, MAX_IP_LEN - ((ngx_str_t*)ptr[i].value)->len, prefix);        }        else        {        printf("    %p: {key = (\"%.*s\"%.*s, %-2d), key_hash = %-11d }\n", ptr + i, ptr[i].key.len, ptr[i].key.data, MAX_URL_LEN - ptr[i].key.len, prefix, ptr[i].key.len, ptr[i].key_hash);        }    }    printf("\n");}void display_str_data(ngx_str_t *str){    int len = str->len;    for (int i = 0; i < len; i++)    {            printf("%c", str->data[i]);    }    printf("\0");}/** * pass array pointer to read elts[i].key_hash, then for getting the position - key */void dump_combined_hash(ngx_hash_combined_t *hash, ngx_hash_keys_arrays_t *array){dump_hash(&hash->hash, &array->keys);dump_hash_wildcard(hash->wc_head, 0);dump_hash_wildcard(hash->wc_tail, 0);}void dump_hash_wildcard(ngx_hash_wildcard_t *wc_hash, ngx_uint_t deepth){ngx_uint_t loop;    char prefix[] = "                         ";ngx_hash_wildcard_t *wdc;ngx_hash_t *hash = &wc_hash->hash;if (wc_hash == NULL)return;if (wc_hash->value != NULL)printf("%.*svalue = \"%.*s\"\n", deepth * DEEPTH, prefix, ((ngx_str_t*)wc_hash->value)->len,((ngx_str_t*)wc_hash->value)->data);elseprintf("%.*svalue = NULL\n", deepth * DEEPTH, prefix);    printf("%.*shash = %p: **buckets = %p, size = %d\n", deepth * DEEPTH, prefix, hash, hash->buckets, hash->size);    for (loop = 0; loop < hash->size; loop++)    {        ngx_hash_elt_t *elt = hash->buckets[loop];        printf("%.*s%p: buckets[%d] = %p\n", deepth * DEEPTH * 2, prefix, &(hash->buckets[loop]), loop, elt);if (elt){while (elt->value){uintptr_t value = (uintptr_t)elt->value;if ((value & 3) == 0 || (value & 3) == 1)  //注意位操作与逻辑运算符的优先级{value &= (uintptr_t)~3;//值得参考的是%.*s的输出,通过参数控制输出字符的个数printf("%.*sbuckets %d: %p {value = \"%.*s\"%.*s, len = %d, name = \"%.*s\"%.*s}\n", deepth * DEEPTH * 2, prefix, loop, elt, ((ngx_str_t*)value)->len, ((ngx_str_t*)value)->data, MAX_IP_LEN - ((ngx_str_t*)value)->len, prefix, elt->len, elt->len, elt->name, MAX_URL_LEN - elt->len, prefix); }else{wdc = (ngx_hash_wildcard_t *)(value & (uintptr_t)~3);printf("%.*sbuckets %d: %p: {value = \"%-16p\", len = %d, name = \"%.*s\"%.*s}\n", deepth * DEEPTH * 2, prefix, loop, elt, wdc, elt->len, elt->len, elt->name, MAX_URL_LEN - elt->len, prefix); dump_hash_wildcard(wdc, deepth + 1);}elt = (ngx_hash_elt_t *)ngx_align_ptr(&elt->name[0] + elt->len, sizeof(void *));}}    }}void dump_hash(ngx_hash_t *hash, ngx_array_t *array){    ngx_uint_t loop;    char prefix[] = "                 ";    u_short test[MAX_NUM] = {0};    ngx_uint_t key;    ngx_hash_key_t* elts;    if (hash == NULL)        return;    printf("hash = %p: **buckets = %p, size = %d\n", hash, hash->buckets, hash->size);    for (loop = 0; loop < hash->size; loop++)    {        ngx_hash_elt_t *elt = hash->buckets[loop];        printf("  %p: buckets[%d] = %p\n", &(hash->buckets[loop]), loop, elt);    }    printf("\n");    elts = (ngx_hash_key_t*)array->elts;    for (loop = 0; loop < array->nelts; loop++)    {        key = elts[loop].key_hash % hash->size;        ngx_hash_elt_t *elt = (ngx_hash_elt_t *) ((u_char *) hash->buckets[key] + test[key]);//值得参考的是%.*s的输出,通过参数控制输出字符的个数        printf("  key %-10d: buckets %d: %p: {value = \"%.*s\"%.*s, len = %d, name = \"%.*s\"%.*s}\n",             elts[loop].key_hash, key, elt, ((ngx_str_t*)elt->value)->len, ((ngx_str_t*)elt->value)->data, MAX_IP_LEN - ((ngx_str_t*)elt->value)->len, prefix, elt->len,              elt->len, elt->name, MAX_URL_LEN - elt->len, prefix); //replace elt->name with url        test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&elts[loop]));    }}void* add_urls_to_array(ngx_pool_t *pool, ngx_hash_keys_arrays_t *ha, ngx_array_t *url, ngx_array_t *value){ngx_uint_t loop;ngx_int_trc;ngx_str_t*strUrl, *strValue;memset(ha, 0, sizeof(ngx_hash_keys_arrays_t));ha->temp_pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, &ngx_log);ha->pool = pool;    if (ngx_hash_keys_array_init(ha, NGX_HASH_LARGE) != NGX_OK) {        goto failed;    }strUrl = url->elts;strValue = value->elts;for (loop = 0; loop < url->nelts; loop++){rc = ngx_hash_add_key(ha, &strUrl[loop], &strValue[loop],                                  NGX_HASH_WILDCARD_KEY);            if (rc == NGX_ERROR) {                goto failed;            }}    return ha;    failed:    ngx_destroy_pool(ha->temp_pool);    return NULL;}void find_test(ngx_hash_combined_t *hash, ngx_str_t addr[], int num){    ngx_uint_t key;    int loop;    char prefix[] = "          ";    for (loop = 0; loop < num; loop++)    {        key = ngx_hash_key_lc(addr[loop].data, addr[loop].len);        ngx_str_t *value = ngx_hash_find_combined(hash, key, addr[loop].data, addr[loop].len);        if (value)        {            printf("(url = \"%s\"%.*s, key = %-11d) found, (ip = \"%.*s%.*s\")\n",                 addr[loop].data, MAX_URL_LEN - addr[loop].len, prefix, key, value->len, value->data, MAX_IP_LEN - value->len, prefix);        }        else        {            printf("(url = \"%s\"%.*s, key = %-11d) not found!\n",                 addr[loop].data, MAX_URL_LEN - addr[loop].len, prefix, key);        }    }}
测试结果:
--------------------------------          the pool:--------------------------------pool = 0x20b7020  .d    .last = 0x20b7070    .end = 0x20b7420    .next = (nil)    .failed = 0  .max = 944  .current = 0x20b7020  .chain = (nil)  .large = (nil)  .cleanup = (nil)  .log = 0x608700available pool memory = 944--------------------------------create and add urls to it:----------------------------------------------------------------         array.keys :--------------------------------array = 0x7ffce5196448  .elts = 0x7f04ed9bc010  .nelts = 9  .size = 32  .nalloc = 16384  .pool = 0x20b7840  elements:    0x7f04ed9bc010: {key = ("www.qq.com"     , 10), key_hash = 203430122   , value = "14.17.42.40"    }    0x7f04ed9bc030: {key = ("www.baidu.com"  , 13), key_hash = 270263191   , value = "180.97.33.107"  }    0x7f04ed9bc050: {key = ("www.taobao.com" , 14), key_hash = 123724152   , value = "116.207.117.62" }    0x7f04ed9bc070: {key = ("www.360.cn"     , 10), key_hash = -1626056701 , value = "119.84.14.199"  }    0x7f04ed9bc090: {key = ("www.google.com" , 14), key_hash = -702889725  , value = "93.46.8.89"     }    0x7f04ed9bc0b0: {key = ("www.sina.com.cn", 15), key_hash = 1528635686  , value = "121.14.1.189"   }    0x7f04ed9bc0d0: {key = ("www.163.com"    , 11), key_hash = -640386838  , value = "61.136.167.72"  }    0x7f04ed9bc0f0: {key = ("www.sohu.com"   , 12), key_hash = 1313636595  , value = "119.97.155.2"   }    0x7f04ed9bc110: {key = ("test.yexin.com" , 14), key_hash = -650258232  , value = "255.255.255.1"  }--------------------------------         array.dns_wc_head :--------------------------------array = 0x7ffce5196478  .elts = 0x7f04ed93b010  .nelts = 3  .size = 32  .nalloc = 16384  .pool = 0x20b7840  elements:    0x7f04ed93b010: {key = ("cn.com.baidu."  , 13), key_hash = 0           , value = "180.97.33.107"  }    0x7f04ed93b030: {key = ("com.baidu."     , 10), key_hash = 0           , value = "180.97.33.107"  }    0x7f04ed93b050: {key = ("com.google."    , 11), key_hash = 0           , value = "93.46.8.89"     }--------------------------------         array.dns_wc_tail :--------------------------------array = 0x7ffce51964a8  .elts = 0x7f04ed8ba010  .nelts = 2  .size = 32  .nalloc = 16384  .pool = 0x20b7840  elements:    0x7f04ed8ba010: {key = ("www.qq"         , 6 ), key_hash = 0           , value = "14.17.42.40"    }    0x7f04ed8ba030: {key = ("test.yexin"     , 10), key_hash = 0           , value = "255.255.255.255"}--------------------------------         array.keys_hash :--------------------------------i = 474array = 0x7f04ed40da20  .elts = 0x20b7bb0  .nelts = 1  .size = 16  .nalloc = 4  .pool = 0x20b7840  elements:    0x20b7bb0: {key = ("www.google.com" , 14), key_hash = 0           , value = NULL}i = 2741array = 0x7f04ed423c58  .elts = 0x20b7bf0  .nelts = 1  .size = 16  .nalloc = 4  .pool = 0x20b7840  elements:    0x20b7bf0: {key = ("www.sina.com.cn", 15), key_hash = 0           , value = NULL}i = 2876array = 0x7f04ed425170  .elts = 0x20b7c70  .nelts = 1  .size = 16  .nalloc = 4  .pool = 0x20b7840  elements:    0x20b7c70: {key = ("www.sohu.com"   , 12), key_hash = 0           , value = NULL}i = 3339array = 0x7f04ed4299c8  .elts = 0x20b7c30  .nelts = 1  .size = 16  .nalloc = 4  .pool = 0x20b7840  elements:    0x20b7c30: {key = ("www.163.com"    , 11), key_hash = 0           , value = NULL}i = 5437array = 0x7f04ed43e198  .elts = 0x20b7b30  .nelts = 1  .size = 16  .nalloc = 4  .pool = 0x20b7840  elements:    0x20b7b30: {key = ("www.taobao.com" , 14), key_hash = 0           , value = NULL}i = 6447array = 0x7f04ed447f68  .elts = 0x20b7ab0  .nelts = 1  .size = 16  .nalloc = 4  .pool = 0x20b7840  elements:    0x20b7ab0: {key = ("www.qq.com"     , 10), key_hash = 0           , value = NULL}i = 7515array = 0x7f04ed452648  .elts = 0x20b7af0  .nelts = 1  .size = 16  .nalloc = 4  .pool = 0x20b7840  elements:    0x20b7af0: {key = ("www.baidu.com"  , 13), key_hash = 0           , value = NULL}i = 7611array = 0x7f04ed453548  .elts = 0x20b7cb0  .nelts = 1  .size = 16  .nalloc = 4  .pool = 0x20b7840  elements:    0x20b7cb0: {key = ("test.yexin.com" , 14), key_hash = 0           , value = NULL}i = 7759array = 0x7f04ed454c68  .elts = 0x20b79a8  .nelts = 1  .size = 16  .nalloc = 4  .pool = 0x20b7840  elements:    0x20b79a8: {key = ("baidu.com"      , 9 ), key_hash = 0           , value = NULL}i = 9371array = 0x7f04ed464848  .elts = 0x20b7b70  .nelts = 1  .size = 16  .nalloc = 4  .pool = 0x20b7840  elements:    0x20b7b70: {key = ("www.360.cn"     , 10), key_hash = 0           , value = NULL}--------------------------------         array.dns_wc_head_hash :--------------------------------i = 4033array = 0x7f04ed3ce638  .elts = 0x20b7900  .nelts = 1  .size = 16  .nalloc = 4  .pool = 0x20b7840  elements:    0x20b7900: {key = ("baidu.com.cn"   , 12), key_hash = 0           , value = NULL}i = 4603array = 0x7f04ed3d3f48  .elts = 0x20b7a60  .nelts = 1  .size = 16  .nalloc = 4  .pool = 0x20b7840  elements:    0x20b7a60: {key = ("google.com"     , 10), key_hash = 0           , value = NULL}i = 7759array = 0x7f04ed3f2c68  .elts = 0x20b7958  .nelts = 1  .size = 16  .nalloc = 4  .pool = 0x20b7840  elements:    0x20b7958: {key = ("baidu.com"      , 9 ), key_hash = 0           , value = NULL}--------------------------------         array.dns_wc_tail_hash :--------------------------------i = 2198array = 0x7f04ed35a780  .elts = 0x20b7d00  .nelts = 1  .size = 16  .nalloc = 4  .pool = 0x20b7840  elements:    0x20b7d00: {key = ("test.yexin."    , 11), key_hash = 0           , value = NULL}i = 8396array = 0x7f04ed396ff0  .elts = 0x20b7a08  .nelts = 1  .size = 16  .nalloc = 4  .pool = 0x20b7840  elements:    0x20b7a08: {key = ("www.qq."        , 7 ), key_hash = 0           , value = NULL}--------------------------------          the pool:--------------------------------pool = 0x20b7020  .d    .last = 0x20b741d    .end = 0x20b7420    .next = 0x20b7430    .failed = 0  .max = 944  .current = 0x20b7020  .chain = (nil)  .large = (nil)  .cleanup = (nil)  .log = 0x608700available pool memory = 3pool = 0x20b7430  .d    .last = 0x20b754b    .end = 0x20b7830    .next = (nil)    .failed = 0  .max = 774912049  .current = 0x3730312e33  .chain = 0x332e37392e303831  .large = 0x3730312e33  .cleanup = 0x32342e37312e3431  .log = 0x30342eavailable pool memory = 741--------------------------------  array.dns_wc_head after sort:--------------------------------array = 0x7ffce5196478  .elts = 0x7f04ed93b010  .nelts = 3  .size = 32  .nalloc = 16384  .pool = 0x20b7840  elements:    0x7f04ed93b010: {key = ("cn.com.baidu."  , 13), key_hash = 0           , value = "180.97.33.107"  }    0x7f04ed93b030: {key = ("com.baidu."     , 10), key_hash = 0           , value = "180.97.33.107"  }    0x7f04ed93b050: {key = ("com.google."    , 11), key_hash = 0           , value = "93.46.8.89"     }--------------------------------  array.dns_wc_tail after sort:--------------------------------array = 0x7ffce51964a8  .elts = 0x7f04ed8ba010  .nelts = 2  .size = 32  .nalloc = 16384  .pool = 0x20b7840  elements:    0x7f04ed8ba010: {key = ("test.yexin"     , 10), key_hash = 0           , value = "255.255.255.255"}    0x7f04ed8ba030: {key = ("www.qq"         , 6 ), key_hash = 0           , value = "14.17.42.40"    }--------------------------------the hash:--------------------------------hash = 0x7ffce5196410: **buckets = 0x20b7550, size = 9  0x20b7550: buckets[0] = 0x20b75a0  0x20b7558: buckets[1] = 0x20b75c0  0x20b7560: buckets[2] = 0x20b75e0  0x20b7568: buckets[3] = 0x20b7600  0x20b7570: buckets[4] = 0x20b7620  0x20b7578: buckets[5] = 0x20b7660  0x20b7580: buckets[6] = (nil)  0x20b7588: buckets[7] = 0x20b76a0  0x20b7590: buckets[8] = (nil)  key 203430122 : buckets 4: 0x20b7620: {value = "14.17.42.40"    , len = 10, name = "www.qq.com"     }  key 270263191 : buckets 2: 0x20b75e0: {value = "180.97.33.107"  , len = 13, name = "www.baidu.com"  }  key 123724152 : buckets 0: 0x20b75a0: {value = "116.207.117.62" , len = 14, name = "www.taobao.com" }  key -1626056701: buckets 7: 0x20b76a0: {value = "119.84.14.199"  , len = 10, name = "www.360.cn"     }  key -702889725: buckets 1: 0x20b75c0: {value = "93.46.8.89"     , len = 14, name = "www.google.com" }  key 1528635686: buckets 5: 0x20b7660: {value = "121.14.1.189"   , len = 15, name = "www.sina.com.cn"}  key -640386838: buckets 7: 0x20b76b8: {value = "61.136.167.72"  , len = 11, name = "www.163.com"    }  key 1313636595: buckets 3: 0x20b7600: {value = "119.97.155.2"   , len = 12, name = "www.sohu.com"   }  key -650258232: buckets 4: 0x20b7638: {value = "255.255.255.1"  , len = 14, name = "test.yexin.com" }value = NULLhash = 0x20b77d8: **buckets = 0x20b77f0, size = 10x20b77f0: buckets[0] = 0x20bc0e0buckets 0: 0x20bc0e0: {value = "0x20b7758       ", len = 2, name = "cn"             }    value = NULL    hash = 0x20b7758: **buckets = 0x20b7770, size = 1        0x20b7770: buckets[0] = 0x20b7780        buckets 0: 0x20b7780: {value = "0x20b76f8       ", len = 3, name = "com"            }        value = NULL        hash = 0x20b76f8: **buckets = 0x20b7710, size = 1                0x20b7710: buckets[0] = 0x20b7720                buckets 0: 0x20b7720 {value = "180.97.33.107"  , len = 5, name = "baidu"          }buckets 0: 0x20bc0f0: {value = "0x20b77b8       ", len = 3, name = "com"            }    value = NULL    hash = 0x20b77b8: **buckets = 0x20b77d0, size = 1        0x20b77d0: buckets[0] = 0x20bc080        buckets 0: 0x20bc080 {value = "180.97.33.107"  , len = 5, name = "baidu"          }        buckets 0: 0x20bc090 {value = "93.46.8.89"     , len = 6, name = "google"         }value = NULLhash = 0x20bc1e0: **buckets = 0x20bc1f8, size = 10x20bc1f8: buckets[0] = 0x20bc200buckets 0: 0x20bc200: {value = "0x20b77f8       ", len = 4, name = "test"           }    value = NULL    hash = 0x20b77f8: **buckets = 0x20b7810, size = 1        0x20b7810: buckets[0] = 0x20bc140        buckets 0: 0x20bc140 {value = "255.255.255.255", len = 5, name = "yexin"          }buckets 0: 0x20bc210: {value = "0x20bc180       ", len = 3, name = "www"            }    value = NULL    hash = 0x20bc180: **buckets = 0x20bc198, size = 1        0x20bc198: buckets[0] = 0x20bc1a0        buckets 0: 0x20bc1a0 {value = "14.17.42.40"    , len = 2, name = "qq"             }--------------------------------the pool:--------------------------------pool = 0x20b7020  .d    .last = 0x20b741d    .end = 0x20b7420    .next = 0x20b7430    .failed = 1  .max = 944  .current = 0x20b7020  .chain = (nil)  .large = (nil)  .cleanup = (nil)  .log = 0x608700available pool memory = 3pool = 0x20b7430  .d    .last = 0x20b7818    .end = 0x20b7830    .next = 0x20bc060    .failed = 0  .max = 774912049  .current = 0x3730312e33  .chain = 0x332e37392e303831  .large = 0x3730312e33  .cleanup = 0x32342e37312e3431  .log = 0x30342eavailable pool memory = 24pool = 0x20bc060  .d    .last = 0x20bc260    .end = 0x20bc460    .next = (nil)    .failed = 0  .max = 34304513  .current = 0x75646961620005  .chain = 0x20b7231  .large = 0x656c676f6f670006  .cleanup = (nil)  .log = (nil)available pool memory = 512--------------------------------find test:--------------------------------(url = "*..com."        , key = -17068745  ) not found!(url = "*.baidu.com.cn" , key = 234385007  ) found, (ip = "180.97.33.107  ")(url = "*.baidu.com"    , key = -724157846 ) found, (ip = "180.97.33.107  ")(url = ".baidu.com"     , key = 1733355200 ) found, (ip = "180.97.33.107  ")(url = "www.qq.*"       , key = -1367384621) found, (ip = "14.17.42.40    ")(url = "*.google.com"   , key = -1465170800) found, (ip = "93.46.8.89     ")(url = "www.qq.com"     , key = 203430122  ) found, (ip = "14.17.42.40    ")(url = "www.baidu.com"  , key = 270263191  ) found, (ip = "180.97.33.107  ")(url = "www.taobao.com" , key = 123724152  ) found, (ip = "116.207.117.62 ")(url = "www.360.cn"     , key = -1626056701) found, (ip = "119.84.14.199  ")(url = "www.google.com" , key = -702889725 ) found, (ip = "93.46.8.89     ")(url = "www.sina.com.cn", key = 1528635686 ) found, (ip = "121.14.1.189   ")(url = "www.163.com"    , key = -640386838 ) found, (ip = "61.136.167.72  ")(url = "www.sohu.com"   , key = 1313636595 ) found, (ip = "119.97.155.2   ")(url = "test.yexin.com" , key = -650258232 ) found, (ip = "255.255.255.1  ")(url = ".baidu.com"     , key = 1733355200 ) found, (ip = "180.97.33.107  ")(url = "test.yexin.*"   , key = -2061009615) found, (ip = "255.255.255.255")(url = "www.qq.*"       , key = -1367384621) found, (ip = "14.17.42.40    ")(url = "*.xx.xx"        , key = 51835370   ) not found!(url = "www.baidu.com"  , key = 270263191  ) found, (ip = "180.97.33.107  ")(url = "www.baidu."     , key = -239024726 ) not found!

参考:
《深入理解nginx》
http://www.cnblogs.com/chengxuyuancc/p/3782808.html
http://www.uml.org.cn/zjjs/201504131.asp



0 0
原创粉丝点击