1 定义
ngx_hash_find 函数 定义在 ./nginx-1.24.0/src/core/ngx_hash.c
void*ngx_hash_find(ngx_hash_t*hash,ngx_uint_tkey,u_char*name,size_tlen){ngx_uint_ti;ngx_hash_elt_t*elt;#if0ngx_log_error(NGX_LOG_ALERT,ngx_cycle->log,0,"hf:\"%*s\"",len,name);#endifelt=hash->buckets[key%hash->size];if(elt==NULL){returnNULL;}while(elt->value){if(len!=(size_t)elt->len){gotonext;}for(i=0;i<len;i++){if(name[i]!=elt->name[i]){gotonext;}}returnelt->value;next:elt=(ngx_hash_elt_t*)ngx_align_ptr(&elt->name[0]+elt->len,sizeof(void*));continue;}returnNULL;}
ngx_hash_find 函数 用于在 Nginx 的静态哈希表中, 根据预先计算的哈希键值、键字符串及其长度,查找并返回对应的数据指针。 它通过取模定位桶,然后在该桶的连续内存区域中遍历元素, 依次比较长度和字符内容 直至找到匹配项或返回 `NULL` 表示未命中。
2 详解
1 函数签名
void*ngx_hash_find(ngx_hash_t*hash,ngx_uint_tkey,u_char*name,size_tlen)
返回值 返回一个无类型指针,指向哈希表中存储的“值”
参数1 ngx_hash_t *hash 要查找的静态哈希表
参数2 ngx_uint_t key 已预先计算好的哈希键值,用于确定键所在的桶
参数3 u_char *name 指向待查找的键字符串(或称键名)
参数4 size_t len 表示 name 指向的字节序列的长度
2 逻辑流程
1 局部变量 2 定位桶元素 3 遍历桶内元素 4 返回 NULL
1 局部变量
{ngx_uint_ti;ngx_hash_elt_t*elt;#if0ngx_log_error(NGX_LOG_ALERT,ngx_cycle->log,0,"hf:\"%*s\"",len,name);#endif
2 定位桶元素
elt=hash->buckets[key%hash->size];if(elt==NULL){returnNULL;}
3 遍历桶内元素
while(elt->value){if(len!=(size_t)elt->len){gotonext;}for(i=0;i<len;i++){if(name[i]!=elt->name[i]){gotonext;}}returnelt->value;next:elt=(ngx_hash_elt_t*)ngx_align_ptr(&elt->name[0]+elt->len,sizeof(void*));continue;}
开始遍历桶内元素 检查当前元素的 value 字段是否非 NULL。 在 Nginx 哈希实现中,每个 ngx_hash_elt_t 元素存储一个键值对, 且规定有效的 value 一定是一个非空指针。 当元素序列到达结束时,会有一个特殊的“哨兵”元素, 其 value 字段被置为 NULL(即0),作为链尾标记。 因此 while (elt->value) 即“当未到达桶内元素链尾时循环”。
长度快速比较 若待查键的长度与元素键长度不同,两者必然不匹配。 通过 goto next 直接跳到“移动到下一元素”的处理代码
逐字符比较 从索引 0 到 len-1,依次比较 name 和 elt->name 中的每个字节。 name[i] != elt->name[i]:一旦发现任何字节不同,说明当前元素键不匹配, 立即跳转到 next 处理下一个元素。 全部相等:若循环执行完毕仍未跳转,说明所有字节完全匹配,表示找到了目标元素。
匹配成功,返回数据 当执行到这一行时,表示长度一致且所有字符匹配,键值对已找到。 直接返回当前元素的 value 字段,即存储的数据指针。调用者获得所需的结构体地址。
标签 next,用于从上面的 goto next 语句跳转至此, 统一处理“移动到下一个元素”的操作。 计算下一个元素地址 &elt->name[0]:取当前元素的 name 数组首地址 &elt->name[0] + elt->len:指针向后移动 elt->len 字节, 到达当前键字符串数据的尾后地址, 即当前元素实际占用的内存末尾(不包括可能为对齐而填充的额外字节) ngx_align_ptr(ptr, sizeof(void *)): 这是一个宏,用于将指针 ptr 按 sizeof(void *) (指针大小,32位系统为4,64位系统为8)向上对齐 由于下一个 ngx_hash_elt_t 结构体必须满足内存对齐要求 所以从当前元素尾部开始,需要向上取整到指针大小的倍数,才能作为下一个元素的起始地址。 continue 使程序跳转回 while 循环的起始处, 检查新 elt 的 value 是否为非 NULL,即开始处理下一个元素。 配合上面的地址计算,形成隐式链表遍历。
4 返回 NULL
returnNULL;}
当 while 循环因 elt->value == NULL 而退出时, 说明已经遍历完桶内所有有效元素, 没有找到匹配的键。返回 NULL 表示查找失败。