nginx构建static location tree和查找

参考地址 : 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_t
ngx_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的请求过程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值