ngx_hash.c

来自「Nginx是一个高性能的HTTP和反向代理服务器」· C语言 代码 · 共 956 行 · 第 1/2 页

C
956
字号
/* * Copyright (C) Igor Sysoev */#include <ngx_config.h>#include <ngx_core.h>void *ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len){    ngx_uint_t       i;    ngx_hash_elt_t  *elt;#if 0    ngx_str_t  line;    line.len = len;    line.data = name;    ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "hf:\"%V\"", &line);#endif    elt = hash->buckets[key % hash->size];    if (elt == NULL) {        return NULL;    }    while (elt->value) {        if (len != (size_t) elt->len) {            goto next;        }        for (i = 0; i < len; i++) {            if (name[i] != elt->name[i]) {                goto next;            }        }        return elt->value;    next:        elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,                                               sizeof(void *));        continue;    }    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_str_t  line;    line.len = len;    line.data = name;    ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wch:\"%V\"", &line);#endif    n = len;    while (n) {        if (name[n - 1] == '.') {            break;        }        n--;    }    key = 0;    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 (value) {        /*         * the 2 low bits of value have the special meaning:         *     00 - value is data pointer,         *     01 - value is pointer to wildcard hash allowing         *          "*.example.com" only,         *     11 - value is pointer to wildcard hash allowing         *          both "example.com" and "*.example.com".         */        if ((uintptr_t) value & 1) {            hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3);            if (n == 0) {                if ((uintptr_t) value & 2) {                    return hwc->value;                } else {                    return NULL;                }            }            value = ngx_hash_find_wc_head(hwc, name, n - 1);            if (value) {                return value;            }            return hwc->value;        }        return value;    }    return hwc->value;}void *ngx_hash_find_wc_tail(ngx_hash_wildcard_t *hwc, u_char *name, size_t len){    void        *value;    ngx_uint_t   i, key;#if 0    ngx_str_t  line;    line.len = len;    line.data = name;    ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wct:\"%V\"", &line);#endif    key = 0;    for (i = 0; i < len; i++) {        if (name[i] == '.') {            break;        }        key = ngx_hash(key, name[i]);    }    if (i == len) {        return NULL;    }#if 0    ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "key:\"%ui\"", key);#endif    value = ngx_hash_find(&hwc->hash, key, name, i);    if (value) {        /*         * the 2 low bits of value have the special meaning:         *     00 - value is data pointer,         *     01 - value is pointer to wildcard hash allowing "example.*".         */        if ((uintptr_t) value & 1) {            i++;            hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3);            value = ngx_hash_find_wc_tail(hwc, &name[i], len - i);            if (value) {                return value;            }            return hwc->value;        }        return value;    }    return hwc->value;}void *ngx_hash_find_combined(ngx_hash_combined_t *hash, ngx_uint_t key, u_char *name,    size_t len){    void  *value;    if (hash->hash.buckets) {        value = ngx_hash_find(&hash->hash, key, name, len);        if (value) {            return value;        }    }    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;}#define NGX_HASH_ELT_SIZE(name)                                               \    (sizeof(void *) + ngx_align((name)->key.len + 1, sizeof(void *)))ngx_int_tngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts){    u_char          *elts;    size_t           len;    u_short         *test;    ngx_uint_t       i, n, key, size, start, bucket_size;    ngx_hash_elt_t  *elt, **buckets;    for (n = 0; n < nelts; n++) {        if (names[n].key.len >= 255) {            ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,                          "the \"%V\" value to hash is to long: %uz bytes, "                          "the maximum length can be 255 bytes only",                          &names[n].key, names[n].key.len);            return NGX_ERROR;        }        if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *))        {            ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,                          "could not build the %s, you should "                          "increase %s_bucket_size: %i",                          hinit->name, hinit->name, hinit->bucket_size);            return NGX_ERROR;        }    }    test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log);    if (test == NULL) {        return NGX_ERROR;    }    bucket_size = hinit->bucket_size - sizeof(void *);    start = nelts / (bucket_size / (2 * sizeof(void *)));    start = start ? start : 1;    if (hinit->max_size > 10000 && hinit->max_size / nelts < 100) {        start = hinit->max_size - 1000;    }    for (size = start; size < hinit->max_size; size++) {        ngx_memzero(test, size * sizeof(u_short));        for (n = 0; n < nelts; n++) {            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]));#if 0            ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,                          "%ui: %ui %ui \"%V\"",                          size, key, test[key], &names[n].key);#endif            if (test[key] > (u_short) bucket_size) {                goto next;            }        }        goto found;    next:        continue;    }    ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,                  "could not build the %s, you should increase "                  "either %s_max_size: %i or %s_bucket_size: %i",                  hinit->name, hinit->name, hinit->max_size,                  hinit->name, hinit->bucket_size);    ngx_free(test);    return NGX_ERROR;found:    for (i = 0; i < size; i++) {        test[i] = sizeof(void *);    }    for (n = 0; n < nelts; n++) {        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]));    }    len = 0;    for (i = 0; i < size; i++) {        if (test[i] == sizeof(void *)) {            continue;        }        test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size));        len += test[i];    }    if (hinit->hash == NULL) {        hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t)                                             + size * sizeof(ngx_hash_elt_t *));        if (hinit->hash == NULL) {            ngx_free(test);            return NGX_ERROR;        }        buckets = (ngx_hash_elt_t **)                      ((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t));    } else {        buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *));        if (buckets == NULL) {            ngx_free(test);            return NGX_ERROR;        }    }    elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size);    if (elts == NULL) {        ngx_free(test);        return NGX_ERROR;    }    elts = ngx_align_ptr(elts, ngx_cacheline_size);    for (i = 0; i < size; i++) {        if (test[i] == sizeof(void *)) {            continue;        }        buckets[i] = (ngx_hash_elt_t *) elts;        elts += test[i];    }    for (i = 0; i < size; i++) {        test[i] = 0;    }    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_char) names[n].key.len;        for (i = 0; i < names[n].key.len; i++) {            elt->name[i] = ngx_tolower(names[n].key.data[i]);        }        test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));    }    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;#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;}ngx_int_tngx_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;    if (ngx_array_init(&curr_names, hinit->temp_pool, nelts,                       sizeof(ngx_hash_key_t))        != NGX_OK)    {        return NGX_ERROR;    }    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);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?