标签:
Nginx的hash结构,创建后不可修改,唯一的操作就是查询;
ngx_hash_key_t的提供将是ngx_hash_init的参数,由ngx_hash_keys_arrays_t提供;
typedef struct { ngx_str_t key; //元素关键字,字符串 ngx_uint_t key_hash; //散列计算出的关键码 void *value; //指向用户自定义的数据 } ngx_hash_key_t;
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;
初始化ngx_hash_keys_arrays_t
ngx_int_t
ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type)
添加ngx_hash_key_t
ngx_int_t
ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key, void *value,
ngx_uint_t flags)
//hash初始化 ngx_int_t ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) { u_char *elts; size_t len; u_short *test; ngx_uint_t i, n, key, size, start, bucket_size; ngx_hash_elt_t *elt, **buckets; for (n = 0; n < nelts; n++) { if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) //确保一个bucket至少能存放一个实际元素以及结束哨兵 { ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, "could not build the %s, you should " "increase %s_bucket_size: %i", hinit->name, hinit->name, hinit->bucket_size); return NGX_ERROR; } } //ngx_hash_t test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log); if (test == NULL) { return NGX_ERROR; } //bucket_size为一个槽的空间最大大小 bucket_size = hinit->bucket_size - sizeof(void *); //计算一个bucket除去哨兵所占空间后的实际可用空间大小 //bucket_size / (2 * sizeof(void*))为最大可以存储的实际元素个数 start = nelts / (bucket_size / (2 * sizeof(void *))); //计算所需bucket的最小个数 start = start ? start : 1; if (hinit->max_size > 10000 && nelts && hinit->max_size / nelts < 100) { //说明要存的实际个数非常多,那就有必要将start起始值抬高,经验值 start = hinit->max_size - 1000; } //根据初始化散列表预先加入的所有元素确定size for (size = start; size < hinit->max_size; size++) { //获得hash结构最终节点数的逻辑 ngx_memzero(test, size * sizeof(u_short)); for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; //大小 test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); //这个bucket的总大小 #if 0 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, "%ui: %ui %ui \"%V\"", size, key, test[key], &names[n].key); #endif if (test[key] > (u_short) bucket_size) { //如果任何一个buckets满溢了,就到下一个 goto next; } } goto found; next: continue; } ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, "could not build the %s, you should increase " "either %s_max_size: %i or %s_bucket_size: %i", hinit->name, hinit->name, hinit->max_size, hinit->name, hinit->bucket_size); ngx_free(test); return NGX_ERROR; found: for (i = 0; i < size; i++) { test[i] = sizeof(void *); } for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); } len = 0; for (i = 0; i < size; i++) { if (test[i] == sizeof(void *)) { continue; } test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size)); len += test[i]; } if (hinit->hash == NULL) { hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t) + size * sizeof(ngx_hash_elt_t *)); if (hinit->hash == NULL) { ngx_free(test); return NGX_ERROR; } buckets = (ngx_hash_elt_t **) ((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t)); } else { buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *)); if (buckets == NULL) { ngx_free(test); return NGX_ERROR; } } elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size); if (elts == NULL) { ngx_free(test); return NGX_ERROR; } elts = ngx_align_ptr(elts, ngx_cacheline_size); for (i = 0; i < size; i++) { if (test[i] == sizeof(void *)) { continue; } buckets[i] = (ngx_hash_elt_t *) elts; elts += test[i]; } for (i = 0; i < size; i++) { test[i] = 0; } for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]); elt->value = names[n].value; elt->len = (u_short) names[n].key.len; ngx_strlow(elt->name, names[n].key.data, names[n].key.len); test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); //存放 } for (i = 0; i < size; i++) { if (buckets[i] == NULL) { continue; } elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]); elt->value = NULL; } ngx_free(test); hinit->hash->buckets = buckets; hinit->hash->size = size; //大小 return NGX_OK; }
//查询元素 void * ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len) { ngx_uint_t i; ngx_hash_elt_t *elt; #if 0 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "hf:\"%*s\"", len, name); #endif elt = hash->buckets[key % hash->size]; //找到对应的槽 if (elt == NULL) { return NULL; } while (elt->value) { //用户自定义的数据 if (len != (size_t) elt->len) { //首先比较的是元素关键字的长度,长度不相等直接跳出 goto next; } for (i = 0; i < len; i++) { if (name[i] != elt->name[i]) { //然后比较每一个字符的大小 goto next; } } return elt->value; //找到了 next: elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len, //到下一个偏移的elt位置 sizeof(void *)); continue; } return NULL; }
标签:
原文地址:http://blog.csdn.net/skyuppour/article/details/44759337