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