Nginx源代码分析--基本数据结构--hash

我们来看一下wildcard初始化函数。

 

//函数ngx_int_t

 

//ngx_array_s结构体

 

 

 

//elts是指向内存池中的存储元素的指针。内存池pool需要进行元素对齐等,所以这个值不等于pool

//nelts是当前有的元素个数

//size是每个元素大小

//nalloc是元素的多少

//pool是内存池的指针

 

 

struct ngx_array_s {
    void        *elts;
    ngx_uint_t   nelts;
    size_t       size;
    ngx_uint_t   nalloc;
    ngx_pool_t  *pool;
};

 

 

 

 

 

 

//内联函数,进行数组初始化,其实是分配某个数量的元素的内存,以便于压栈等操作

 

 

//参数,数组管理结构体、内存池、元素多少,每个元素大小

 

 

static ngx_inline ngx_int_t
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
    /*
     * set "array->nelts" before "array->elts", otherwise MSVC thinks
     * that "array->nelts" may be used without having been initialized
     */

    array->nelts = 0;
    array->size = size;
    array->nalloc = n;
    array->pool = pool;

    array->elts = ngx_palloc(pool, n * size);
    if (array->elts == NULL) {
        return NGX_ERROR;
    }

    return NGX_OK;
}

 

 

 

 

 

 

 

 

 

//函数ngx_hash_wildcard_init

//这段代码,由于我从来没看过wildcard的相关代码,所以另我相当恶心

 

//一起看看吧

 

 

ngx_int_t
ngx_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
    ngx_uint_t nelts)
{
    size_t                len, dot_len;
    ngx_uint_t            i, n, dot;
    ngx_array_t           curr_names, next_names;
    ngx_hash_key_t       *name, *next_name;
    ngx_hash_init_t       h;
    ngx_hash_wildcard_t  *wdc;

 

    //在hinit->temp_pool中开辟内存,并分配nelts个大小为ngx_hash_key_t的元素的内存空间,对齐后,将指针赋给curr_names

    //该元素数组指针即 curr_names

 

 

    if (ngx_array_init(&curr_names, hinit->temp_pool, nelts,
                       sizeof(ngx_hash_key_t))
        != NGX_OK)
    {
        return NGX_ERROR;
    }

 

    //同样在hinit->temp_pool中开辟内存,分配nelts个大小为ngx_hash_key_t的元素的内存空间,对齐后,将指针赋给next_names

    //该元素数组指针即 next_names


    if (ngx_array_init(&next_names, hinit->temp_pool, nelts,
                       sizeof(ngx_hash_key_t))
        != NGX_OK)
    {
        return NGX_ERROR;
    }

 

 

 

   //对于整个数组

 

    for (n = 0; n < nelts; n = i) {

#if 0
        ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                      "wc0: /"%V/"", &names[n].key);
#endif

 

        //标识
        dot = 0;
        //如果这个数组的元素中,有dot则,赋dot为1,并跳出这个检测数组元素中是否有dot的循环,当前的len则是从数组开始到数组中的  

        //dot。
        for (len = 0; len < names[n].key.len; len++) {
            if (names[n].key.data[len] == '.') {
                dot = 1;
                break;
            }
        }

        //curr_names的指针发生移动,以便于给当前元素赋值。也就是“压栈”操作
        name = ngx_array_push(&curr_names);
        if (name == NULL) {
            return NGX_ERROR;
        }
                 //压栈操作的赋值代码,将names这个数组,的当前元素的值填充到name这个数组中,包括计算这个当前元素的key_hash的值
        name->key.len = len;
        name->key.data = names[n].key.data;
        name->key_hash = hinit->key(name->key.data, name->key.len);
        name->value = names[n].value;

#if 0
        ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                      "wc1: /"%V/" %ui", &name->key, dot);
#endif

 

        //数组中dot后其余部分的开始


        dot_len = len + 1;


        //如果dot==1,则说明数组其余部分第一个是dot,应该将len+1指向dot后第一个字符
        if (dot) {
            len++;
        }

 

 

       //初始化next_names指向的元素的实际个数为0

 

        next_names.nelts = 0;

 

        //如果names中的元素长度与当前长度不等,说明确实有dot。


        if (names[n].key.len != len) {

              //把这个压入next_names栈中

            next_name = ngx_array_push(&next_names);
            if (next_name == NULL) {
                return NGX_ERROR;
            }


           //得到新的字串的长度
            next_name->key.len = names[n].key.len - len;
           //新的字串的指针

           next_name->key.data = names[n].key.data + len;
           //新的字串的hash值

           next_name->key_hash = 0;

            //新的字串的值
           next_name->value = names[n].value;

#if 0
            ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                          "wc2: /"%V/"", &next_name->key);
#endif
        }

 

        //比较当前names[n]的值的数据是否有和n+1到nelts的元素的值相同的
        for (i = n + 1; i < nelts; i++) {

            //如果names[n]的key值的数据和names[i]的key的数据相同不相同,则跳出循环。

            if (ngx_strncmp(names[n].key.data, names[i].key.data, len) != 0) {
                break;
            }

             //到这,意味着key数据值相同

              //如果dot==0并且names[i]的key的长度大于len并且names[i]的key的数据不是dot(.)则退出循环

            if (!dot
                && names[i].key.len > len
                && names[i].key.data[len] != '.')
            {
                break;
            }

            //到这意味着dot==1,并且names[i]的后边也有字符。则将next_names压入栈,即names[i]与names[n]处理相同


            next_name = ngx_array_push(&next_names);
            if (next_name == NULL) {
                return NGX_ERROR;
            }
             //进行赋值与names[n]的相同


            next_name->key.len = names[i].key.len - dot_len;
            next_name->key.data = names[i].key.data + dot_len;
            next_name->key_hash = 0;
            next_name->value = names[i].value;

#if 0
            ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                          "wc3: /"%V/"", &next_name->key);
#endif
        }

 

 

 

 

        //如果当前没有执行过push_array_push操作,也就是dot后边没有元素

       //则意味着curr_names中已经不含有dot。

 

       //递归调用,对next_names进行

 

        if (next_names.nelts) {

            h = *hinit;
            h.hash = NULL;

            if (ngx_hash_wildcard_init(&h, (ngx_hash_key_t *) next_names.elts,
                                       next_names.nelts)
                != NGX_OK)
            {
                return NGX_ERROR;
            }

 

             //没看明白。。。。。。。。。。。。。。。。。。。。。。。。。。。。

 

            wdc = (ngx_hash_wildcard_t *) h.hash;

            if (names[n].key.len == len) {
                wdc->value = names[n].value;
            }

            name->value = (void *) ((uintptr_t) wdc | (dot ? 3 : 2));

        } else if (dot) {
            name->value = (void *) ((uintptr_t) name->value | 1);
        }
    }

 

 

  //最后,所有不含dot的元素都在curr_names中了,进行初始化hinit。

    if (ngx_hash_init(hinit, (ngx_hash_key_t *) curr_names.elts,
                      curr_names.nelts)
        != NGX_OK)
    {
        return NGX_ERROR;
    }

    return NGX_OK;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值