ngx_int_t
ngx_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;
    if (hinit->max_size == 0) {
        ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
                      "could not build %s, you should "
                      "increase %s_max_size: %i",
                      hinit->name, hinit->name, hinit->max_size);
        return NGX_ERROR;
    }
    for (n = 0; n < nelts; n++) {
        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 %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 && nelts && 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;
    }
    size = hinit->max_size;
    ngx_log_error(NGX_LOG_WARN, hinit->pool->log, 0,
                  "could not build optimal %s, you should increase "
                  "either %s_max_size: %i or %s_bucket_size: %i; "
                  "ignoring %s_bucket_size",
                  hinit->name, hinit->name, hinit->max_size,
                  hinit->name, hinit->bucket_size, hinit->name);
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_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]));
    }
    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_t\nngx_http_variables_init_vars(ngx_conf_t *cf)\n{\n    ngx_uint_t                  i, n;\n    ngx_hash_key_t             *key;\n    ngx_hash_init_t             hash;\n    ngx_http_variable_t        *v, *av;\n    ngx_http_core_main_conf_t  *cmcf;\n    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);\n    v = cmcf->variables.elts;\n    key = cmcf->variables_keys->keys.elts;\n    for (i = 0; i < cmcf->variables.nelts; i++) {\n        for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {\n            av = key[n].value;\n            if (v[i].name.len == key[n].key.len\n                && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)\n                   == 0)\n            {\n                v[i].get_handler = av->get_handler;\n                v[i].data = av->data;\n                av->flags |= NGX_HTTP_VAR_INDEXED;\n                v[i].flags = av->flags;\n                av->index = i;\n                if (av->get_handler == NULL) {\n                    break;\n                }\n                goto next;\n            }\n        }\n        if (v[i].name.len >= 5\n            && ngx_strncmp(v[i].name.data, "http_", 5) == 0)\n        {\n            v[i].get_handler = ngx_http_variable_unknown_header_in;\n            v[i].data = (uintptr_t) &v[i].name;\n            continue;\n        }\n        if (v[i].name.len >= 10\n            && ngx_strncmp(v[i].name.data, "sent_http_", 10) == 0)\n        {\n            v[i].get_handler = ngx_http_variable_unknown_header_out;\n            v[i].data = (uintptr_t) &v[i].name;\n            continue;\n        }\n        if (v[i].name.len >= 14\n            && ngx_strncmp(v[i].name.data, "upstream_http_", 14) == 0)\n        {\n            v[i].get_handler = ngx_http_upstream_header_variable;\n            v[i].data = (uintptr_t) &v[i].name;\n            v[i].flags = NGX_HTTP_VAR_NOCACHEABLE;\n            continue;\n        }\n        if (v[i].name.len >= 7\n            && ngx_strncmp(v[i].name.data, "cookie_", 7) == 0)\n        {\n            v[i].get_handler = ngx_http_variable_cookie;\n            v[i].data = (uintptr_t) &v[i].name;\n            continue;\n        }\n        if (v[i].name.len >= 16\n            && ngx_strncmp(v[i].name.data, "upstream_cookie_", 16) == 0)\n        {\n            v[i].get_handler = ngx_http_upstream_cookie_variable;\n            v[i].data = (uintptr_t) &v[i].name;\n            v[i].flags = NGX_HTTP_VAR_NOCACHEABLE;\n            continue;\n        }\n        if (v[i].name.len >= 4\n            && ngx_strncmp(v[i].name.data, "arg_", 4) == 0)\n        {\n            v[i].get_handler = ngx_http_variable_argument;\n            v[i].data = (uintptr_t) &v[i].name;\n            v[i].flags = NGX_HTTP_VAR_NOCACHEABLE;\n            continue;\n        }\n        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,\n                      "unknown \\"%V\\" variable", &v[i].name);\n        return NGX_ERROR;\n    next:\n        continue;\n    }\n    for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {\n        av = key[n].value;\n        if (av->flags & NGX_HTTP_VAR_NOHASH) {\n            key[n].key.data = NULL;\n        }\n    }\n    hash.hash = &cmcf->variables_hash;\n    hash.key = ngx_hash_key;\n    hash.max_size = cmcf->variables_hash_max_size;\n    hash.bucket_size = cmcf->variables_hash_bucket_size;\n    hash.name = "variables_hash";\n    hash.pool = cf->pool;\n    hash.temp_pool = NULL;\n    if (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts,\n                      cmcf->variables_keys->keys.nelts)\n        != NGX_OK)\n    {\n        return NGX_ERROR;\n    }\n    cmcf->variables_keys = NULL;\n    return NGX_OK;\n}', 'ngx_int_t\nngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)\n{\n    u_char          *elts;\n    size_t           len;\n    u_short         *test;\n    ngx_uint_t       i, n, key, size, start, bucket_size;\n    ngx_hash_elt_t  *elt, **buckets;\n    if (hinit->max_size == 0) {\n        ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,\n                      "could not build %s, you should "\n                      "increase %s_max_size: %i",\n                      hinit->name, hinit->name, hinit->max_size);\n        return NGX_ERROR;\n    }\n    for (n = 0; n < nelts; n++) {\n        if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *))\n        {\n            ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,\n                          "could not build %s, you should "\n                          "increase %s_bucket_size: %i",\n                          hinit->name, hinit->name, hinit->bucket_size);\n            return NGX_ERROR;\n        }\n    }\n    test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log);\n    if (test == NULL) {\n        return NGX_ERROR;\n    }\n    bucket_size = hinit->bucket_size - sizeof(void *);\n    start = nelts / (bucket_size / (2 * sizeof(void *)));\n    start = start ? start : 1;\n    if (hinit->max_size > 10000 && nelts && hinit->max_size / nelts < 100) {\n        start = hinit->max_size - 1000;\n    }\n    for (size = start; size <= hinit->max_size; size++) {\n        ngx_memzero(test, size * sizeof(u_short));\n        for (n = 0; n < nelts; n++) {\n            if (names[n].key.data == NULL) {\n                continue;\n            }\n            key = names[n].key_hash % size;\n            test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));\n#if 0\n            ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,\n                          "%ui: %ui %ui \\"%V\\"",\n                          size, key, test[key], &names[n].key);\n#endif\n            if (test[key] > (u_short) bucket_size) {\n                goto next;\n            }\n        }\n        goto found;\n    next:\n        continue;\n    }\n    size = hinit->max_size;\n    ngx_log_error(NGX_LOG_WARN, hinit->pool->log, 0,\n                  "could not build optimal %s, you should increase "\n                  "either %s_max_size: %i or %s_bucket_size: %i; "\n                  "ignoring %s_bucket_size",\n                  hinit->name, hinit->name, hinit->max_size,\n                  hinit->name, hinit->bucket_size, hinit->name);\nfound:\n    for (i = 0; i < size; i++) {\n        test[i] = sizeof(void *);\n    }\n    for (n = 0; n < nelts; n++) {\n        if (names[n].key.data == NULL) {\n            continue;\n        }\n        key = names[n].key_hash % size;\n        test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));\n    }\n    len = 0;\n    for (i = 0; i < size; i++) {\n        if (test[i] == sizeof(void *)) {\n            continue;\n        }\n        test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size));\n        len += test[i];\n    }\n    if (hinit->hash == NULL) {\n        hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t)\n                                             + size * sizeof(ngx_hash_elt_t *));\n        if (hinit->hash == NULL) {\n            ngx_free(test);\n            return NGX_ERROR;\n        }\n        buckets = (ngx_hash_elt_t **)\n                      ((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t));\n    } else {\n        buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *));\n        if (buckets == NULL) {\n            ngx_free(test);\n            return NGX_ERROR;\n        }\n    }\n    elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size);\n    if (elts == NULL) {\n        ngx_free(test);\n        return NGX_ERROR;\n    }\n    elts = ngx_align_ptr(elts, ngx_cacheline_size);\n    for (i = 0; i < size; i++) {\n        if (test[i] == sizeof(void *)) {\n            continue;\n        }\n        buckets[i] = (ngx_hash_elt_t *) elts;\n        elts += test[i];\n    }\n    for (i = 0; i < size; i++) {\n        test[i] = 0;\n    }\n    for (n = 0; n < nelts; n++) {\n        if (names[n].key.data == NULL) {\n            continue;\n        }\n        key = names[n].key_hash % size;\n        elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]);\n        elt->value = names[n].value;\n        elt->len = (u_short) names[n].key.len;\n        ngx_strlow(elt->name, names[n].key.data, names[n].key.len);\n        test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));\n    }\n    for (i = 0; i < size; i++) {\n        if (buckets[i] == NULL) {\n            continue;\n        }\n        elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]);\n        elt->value = NULL;\n    }\n    ngx_free(test);\n    hinit->hash->buckets = buckets;\n    hinit->hash->size = size;\n#if 0\n    for (i = 0; i < size; i++) {\n        ngx_str_t   val;\n        ngx_uint_t  key;\n        elt = buckets[i];\n        if (elt == NULL) {\n            ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,\n                          "%ui: NULL", i);\n            continue;\n        }\n        while (elt->value) {\n            val.len = elt->len;\n            val.data = &elt->name[0];\n            key = hinit->key(val.data, val.len);\n            ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,\n                          "%ui: %p \\"%V\\" %ui", i, elt, &val, key);\n            elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,\n                                                   sizeof(void *));\n        }\n    }\n#endif\n    return NGX_OK;\n}', 'void *\nngx_pcalloc(ngx_pool_t *pool, size_t size)\n{\n    void *p;\n    p = ngx_palloc(pool, size);\n    if (p) {\n        ngx_memzero(p, size);\n    }\n    return p;\n}', 'void *\nngx_palloc(ngx_pool_t *pool, size_t size)\n{\n    u_char      *m;\n    ngx_pool_t  *p;\n    if (size <= pool->max) {\n        p = pool->current;\n        do {\n            m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);\n            if ((size_t) (p->d.end - m) >= size) {\n                p->d.last = m + size;\n                return m;\n            }\n            p = p->d.next;\n        } while (p);\n        return ngx_palloc_block(pool, size);\n    }\n    return ngx_palloc_large(pool, size);\n}']