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

咱们来继续看found后的处理:

 


found:

 

  //小样,找到你了~~

 

  //当前的size,可就是需要的桶大小了。

 //老毛子这里将test[0]~test[size-1]的值,重新计算一遍。

 //感觉是因为他太高兴了,觉得”终于成功计算出size了“,忘记了,其实test里边的除了那些被初始化为0后,一致没有分配k-v对给它的桶之 //外,不都变成了需要的内存的大小了么。其实这里是为了更加逻辑清晰,因为每个桶还要进行ngx_cacheline_size粒度的对齐呢。

 

 //你又算一遍是为了清晰?有木有,有木有!

 

    for (i = 0; i < size; i++) {
        test[i] = sizeof(void *);
    }

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

 

        //name说:我key是NULL你就别算我了
        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]));
    }

 

   //有些桶里啊,压根没有k-v对,所以啊,len这个里边就不算他们了。也就是这些都不需要内存的。

   //当前的size[i]可是在k-v对进行了sizeof(void *)为准的对齐后的值啊。

 

    len = 0;

    for (i = 0; i < size; i++) {
        if (test[i] == sizeof(void *)) {
            continue;
        }

 

        //但是仅仅k-v对齐是不够的,我整个bucket要以ngx_cacheline_size对齐。

        //你再算一下,ngx_cacheline_size对齐了吧
        test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size));

        len += test[i];
    }

 

 

  //我了个去。终于当前的len就是真正需要的内存大小了。

 

 

    if (hinit->hash == NULL) {

 

        //恩,这种情况下,也就是hinit->hash==NULL的情况,我们得分配一个ngx_hash_wildcard_t在,这个是在pool里分配的。

 

       //然后还需要把hinit->hash指向 ngx_hash_wildcard_t元素中的ngx_hash_elt_t *。

 

        hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t)
                                             + size * sizeof(ngx_hash_elt_t *));

 

         //你要是分配不成功,你就返回ERROR吧。

        if (hinit->hash == NULL) {
            ngx_free(test);
            return NGX_ERROR;
        }

 

         //经过下边这招,你发现,ngx_hash_wildcard_t中的ngx_hash_t中的ngx_hash_elt_t *的地址被放置到了buckets。

         //反过来说,buckets指向ngx_hash_wildcard_t中的ngx_hash_t中的ngx_hash_elt_t *。

         //看来下边就是要给这个buckets这个指针指向的ngx_hash_elt_t *指向的ngx_hash_elt_t赋值了。

 


        buckets = (ngx_hash_elt_t **)
                      ((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t));

    } else {

 

         //如果hinit->hash不是NULL呢,咱们就不分配ngx_hash_wildcard_t,直接整个ngx_hash_t就OK了。

         //buckets直接指向ngx_hash_elt_t *

 

        buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *));
        if (buckets == NULL) {
            ngx_free(test);
            return NGX_ERROR;
        }
    }

 

     //不仅仅是将上述ngx_hash_wildcard_t或者ngx_hash_t分配到hinit->pool,刚计算的所有bucket需要的len大小的内存和    

 

    //ngx_cacheline_size大小内存也在内存池中分配了。小样,别以为我不知道你为啥要加上ngx_cacheline_size。因为多余的这个

    //ngx_cacheline_size可以保证你调整elts后,使用新的elts指向的内存池,依然是大于len的,这样不会产生非法内存访问。因为原来的  

   //elts不会移动超过ngx_cacheline_size就可以调整到ngx_cacheline_size对齐的地方。

   //在数学上就是 [a,a+b]之间必有一个数,是b的整数倍。


    elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size);

 

    //要是分配不成功,就返回ERROR

    if (elts == NULL) {
        ngx_free(test);
        return NGX_ERROR;
    }

 

 

   //在这里做对齐调整。嘿嘿,之所以知道上边你加上ngx_cacheline_size就是因为这里,你暴露了。

 

    elts = ngx_align_ptr(elts, ngx_cacheline_size);

 

  //好了,内存初地址也有了,桶多少也知道了,每个桶的k-v占用内存的计数(包括所需数据结构占用的内存)也在test[i]了。

  //那么,我们就开始分配桶,把每个桶的指针上,都赋值正确的内存地址吧。

 

    for (i = 0; i < size; i++) {
        if (test[i] == sizeof(void *)) {
            continue;
        }

        buckets[i] = (ngx_hash_elt_t *) elts;
        elts += test[i];

    }

 

    //用完了,清下0。

 

   for (i = 0; i < size; i++) {
        test[i] = 0;
    }

 

   //最后,我们把桶k-v对的值填入就可以了。也就是根据key_hash值计算key-value应该在哪个桶,并且放进去。


    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]));
    }

 

   //分配完了k-v,我们把每个bucket的k-v结尾标志给赋值NULL。


    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;

 

//Log级别的问题,别关心了
#if 0

    for (i = 0; i < size; i++) {
        ngx_str_t   val;
        ngx_uint_t  key;

        elt = buckets[i];

        if (elt == NULL) {
            ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                          "%ui: NULL", i);
            continue;
        }

        while (elt->value) {
            val.len = elt->len;
            val.data = &elt->name[0];

            key = hinit->key(val.data, val.len);

            ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                          "%ui: %p /"%V/" %ui", i, elt, &val, key);

            elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,
                                                   sizeof(void *));
        }
    }

#endif

    return NGX_OK;
}

你可能感兴趣的:(数据结构,nginx,UI,null,wildcard,代码分析)