nginx构建static location tree和查找

来源:互联网 发布:网络调试助手的作用 编辑:程序博客网 时间:2024/06/04 18:53

参考地址 : http://blog.chinaunix.net/uid-27767798-id-3759557.html
nginx在处理location的配置的时候,用到了一种三叉排序树,加速了通过request的url和location的映射速度

三叉排序树的形成过程:

这里写图片描述

pclcf->static_locations = ngx_http_create_locations_tree(cf, locations, 0);

看一下nginx是如何uri和location之间快速做映射的:

static ngx_int_tngx_http_core_find_static_location(ngx_http_request_t *r,    ngx_http_location_tree_node_t *node){    u_char *uri;    size_t len, n;    ngx_int_t rc, rv;    len = r->uri.len;  //request的请求路径长度     uri = r->uri.data; //request请求的地址     rv = NGX_DECLINED; //默认精准匹配和前缀匹配 匹配不到,需要匹配后面的正则    for ( ;; ) {        if (node == NULL) {            return rv;        }        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,                       "test location: "%*s"", node->len, node->name);        //n是uri的长度和node name长度的最小值,好比较他们的交集        n = (len <= (size_t) node->len) ? len : node->len;         //比较uri和node 的name交集        rc = ngx_filename_cmp(uri, node->name, n);         //不得0表示uri和node的name不相等,这时候三叉树就能加速查找的效率,选择node的左节点或者右节点        if (rc != 0) {                 node = (rc < 0) ? node->left : node->right;            continue; //更新节点后重新开始比较匹配        }         //如果交集相等,如果uri的长度比node的长度还要长        if (len > (size_t) node->len) {            if (node->inclusive) {//如果这个节点是前缀匹配的那种需要递归tree节点,因为tree节点后面的子节点拥有相同的前缀。        //因为前缀已经匹配到了,所以这里先暂且把loc_conf作为target,但是不保证后面的tree节点的子节点是否有和uri完全匹配或者更多前缀匹配的。例如如果uri是/abc,当前node节点是/a,虽然匹配到了location /a,先把/a的location配置作为target,但是有可能在/a的tree节点有/abc的location,所以需要递归tree节点看一下。                 r->loc_conf = node->inclusive->loc_conf;         //设置成again表示需要递归嵌套location,为什么要嵌套递归呢,因为location的嵌套配置虽然官方不推荐,但是配置的话,父子location需要有相同的前缀。所以需要递归嵌套location                rv = NGX_AGAIN;                node = node->tree; //node重新变为tree节点                uri += n;                len -= n;       continue;            }            /* exact only */        //对于精确匹配的location不会放在公共前缀节点的tree节点中,会单拉出来一个node和前缀节点平行。也就是说对于精确匹配 =/abcd 和前缀匹配的/abc两个location配置,=/abcd不会是/abc节点的tree节点。=/abcd 只能是/abc的right节点            node = node->right;             continue;        }        if (len == (size_t) node->len) { //如果是uri和node的name是完全相等的            if (node->exact) {           //如果是精确匹配,那么就是直接返回ok了                r->loc_conf = node->exact->loc_conf;                return NGX_OK;            } else {                 //如果还是前缀模式的location,那么需要递归嵌套location了,需要提前设置loc_conf,如果嵌套有匹配的再覆盖                r->loc_conf = node->inclusive->loc_conf;                return NGX_AGAIN;            }        }        /* len < node->len */        if (len + 1 == (size_t) node->len && node->auto_redirect) {            r->loc_conf = (node->exact) ? node->exact->loc_conf:                                          node->inclusive->loc_conf;            rv = NGX_DONE;        }        //如果前缀相等,uri的长度比node的长度还要小,比如node的name是/abc ,uri是/ab,这种情况是/abc 一定是精确匹配,因为如果是前缀匹配那么/abc 肯定会再/ab的tree 指针里面。        node = node->left;     } 

总结:
static location tree大大优化了精准匹配和前缀匹配的location的查找过程,线性递归查找效率低下,三叉树的左节点代表当前比node节点的name小的节点,右节点代表比当前node节点name大的节点,tree节点表示拥有相同前缀的节点。

问题:
关于request的请求过程

0 0
原创粉丝点击