Skip to content

Latest commit

 

History

History
149 lines (103 loc) · 3.59 KB

ngx_hash_wildcard.markdown

File metadata and controls

149 lines (103 loc) · 3.59 KB

#nginx含有通配符的hash表: ngx_hash_wildcard_t

支持通配符的hash表的初始化更加复杂。以点为分割点,将关键字分成多个串,每个传单独进行hash。并且前面的串形成的ngx_hash_wildcard_t结构会记录后面的串形成的hash表的内存地址和统配类型。因此形成一个树形的结构。

init过程理解了上面这段话就不难理解了。看看ngx_hash_find_combined函数。

void *
ngx_hash_find_combined(ngx_hash_combined_t *hash, ngx_uint_t key, u_char *name,
    size_t len)
{
    void  *value;
    
    //首先找普通的hash表,获得key所在的桶,然后一个一个的比较
    if (hash->hash.buckets) {
        value = ngx_hash_find(&hash->hash, key, name, len);

        if (value) {
            return value;
        }
    }

    if (len == 0) {
        return NULL;
    }
    
    //对于通配符在前面的情况,比如*.andone.com,对于这类关键字,是先将关键字倒序,然后进行hash操作。因此查找的时候,也是从后面开始找被点隔开的字符串。看下面ngx_hash_find_wc_head的详细解释
    if (hash->wc_head && hash->wc_head->hash.buckets) {
        value = ngx_hash_find_wc_head(hash->wc_head, name, len);

        if (value) {
            return value;
        }
    }

    if (hash->wc_tail && hash->wc_tail->hash.buckets) {
        value = ngx_hash_find_wc_tail(hash->wc_tail, name, len);

        if (value) {
            return value;
        }
    }

    return NULL;
}
void *
ngx_hash_find_wc_head(ngx_hash_wildcard_t *hwc, u_char *name, size_t len)
{
    void        *value;
    ngx_uint_t   i, n, key;

#if 0
    ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wch:\"%*s\"", len, name);
#endif

    n = len;


    //找到被点隔开的最后一个一个字符串
    while (n) {
        if (name[n - 1] == '.') {
            break;
        }

        n--;
    }

    key = 0;
       
    //计算hash值
    for (i = n; i < len; i++) {
        key = ngx_hash(key, name[i]);
    }
    

#if 0
    ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "key:\"%ui\"", key);
#endif

    value = ngx_hash_find(&hwc->hash, key, &name[n], len - n);

#if 0
    ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "value:\"%p\"", value);
#endif

    if (value) {

        /*
         * the 2 low bits of value have the special meaning:
         *     00 - value is data pointer for both "example.com"
         *          and "*.example.com";
         *     01 - value is data pointer for "*.example.com" only;
         *     10 - value is pointer to wildcard hash allowing
         *          both "example.com" and "*.example.com";
         *     11 - value is pointer to wildcard hash allowing
         *          "*.example.com" only.
         */
         
        if ((uintptr_t) value & 2) {

            if (n == 0) {

                /* "example.com" */
                
                if ((uintptr_t) value & 1) {
                    return NULL;
                }

                hwc = (ngx_hash_wildcard_t *)
                
                return hwc->value;
            }

            hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3);

            value = ngx_hash_find_wc_head(hwc, name, n - 1);

            if (value) {
                return value;
            }

            return hwc->value;
        }

        if ((uintptr_t) value & 1) {

            if (n == 0) {

                /* "example.com" */

                return NULL;
            }

            return (void *) ((uintptr_t) value & (uintptr_t) ~3);
        }

        return value;
        }

    return hwc->value;
}