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

    技术2022-05-20  41

    咱们来继续看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;}


    最新回复(0)