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
该部分内容转载自: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);#endifhash_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
- nginx学习——建立hash表的前提条件
- 学习Hadoop的前提条件
- nginx学习——从基本hash表到支持通配符的hash表(上)
- nginx学习——从基本hash表到支持通配符的hash表(下)
- 归纳偏置:ML学习能力的前提条件
- nginx的hash表结构
- nginx学习7——日志建立以及分割
- 中国农业革命(1978-2012)——大国城市化的前提条件(卢锋,2012)
- nginx的hash
- nginx的hash
- 做网站的前提条件
- 执行索引的前提条件
- nginx源码分析—hash结构
- hash表建立,查找,详解
- Exchange Server 2013 运维系列——运行邮件删除命令(search-mailbox)的前提条件
- 发布webservice服务的前提条件
- Internet 客户端类的前提条件
- nginx中hash表的设计与实现
- 第一个吃 Wayland 螃蟹的 Fedora 25
- CF#571 B. Minimization (DP)
- U3D开发学习之路--RayCast中layerMask的使用
- 转 [学习笔记]时钟中断的定义及作用
- Java开发中的23种设计模式详解
- nginx学习——建立hash表的前提条件
- leetcode 33. Search in Rotated Sorted Array
- 在Linux下进入目录,目录下创建、修改、删除文件所需权限
- 使用QtCreator作为嵌入式Linux的IDE及可视化调试工具
- Java之美[从菜鸟到高手演变]系列之博文阅读导航
- Git基础知识1——个人笔记
- centos 7.0 查看selinux状态|关闭|开启
- spring总结
- concat_ws和concat实现多字段模糊搜索