标签:
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