Ubuntu 下 nginx-1.24.0 源码分析 - ngx_str_rbtree_insert_value

devtools/2025/3/4 8:16:06/

ngx_str_rbtree_insert_value


声明src\core\ngx_string.h

void ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
ngx_str_node_t *ngx_str_rbtree_lookup(ngx_rbtree_t *rbtree, ngx_str_t *name,uint32_t hash);

实现src\core\ngx_string.c

void
ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
{ngx_str_node_t      *n, *t;ngx_rbtree_node_t  **p;for ( ;; ) {n = (ngx_str_node_t *) node;t = (ngx_str_node_t *) temp;if (node->key != temp->key) {p = (node->key < temp->key) ? &temp->left : &temp->right;} else if (n->str.len != t->str.len) {p = (n->str.len < t->str.len) ? &temp->left : &temp->right;} else {p = (ngx_memcmp(n->str.data, t->str.data, n->str.len) < 0)? &temp->left : &temp->right;}if (*p == sentinel) {break;}temp = *p;}*p = node;node->parent = temp;node->left = sentinel;node->right = sentinel;ngx_rbt_red(node);
}

ngx_str_rbtree_insert_value 是 Nginx 中用于向红黑树插入字符串节点的函数,其核心作用是根据特定的键值比较逻辑维护红黑树的有序性。

该函数实现了红黑树的节点插入逻辑,将新节点 node 插入到红黑树的正确位置,并初始化其属性(父节点、子节点、颜色)。插入后,红黑树的平衡调整由其他函数(如 ngx_rbtree_insert)处理。


函数签名

void ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,ngx_rbtree_node_t *node,ngx_rbtree_node_t *sentinel
);

参数详解

  1. ngx_rbtree_node_t *temp

当前遍历的红黑树节点,作为临时指针用于逐层比较。

初始指向红黑树的根节点(或插入路径上的某个中间节点)。
在循环中,通过比较 tempnode 的键值,确定 node 的插入方向(左子树或右子树)。

最终会成为新插入节点的父节点(node->parent = temp)。
若树为空,temp 可能指向哨兵节点(此时 node 成为根节点)。

2 . ngx_rbtree_node_t *node

待插入的红黑树节点。

包含需要插入的字符串数据(ngx_str_node_t 类型,继承自 ngx_rbtree_node_t)。

需要被插入到红黑树的正确位置,并初始化其 parentleftright 和颜色属性。

  1. ngx_rbtree_node_t *sentinel

红黑树的哨兵节点(NIL 节点)。

标记树的叶子节点或空子节点(代替 NULL)。

作为插入操作的终止条件:当遍历到哨兵时,说明找到插入位置。

所有叶子节点的 leftright 均指向哨兵。


函数返回值

  • void
    • 无需返回值,所有操作通过指针直接修改红黑树结构。
    • 插入结果通过修改 tempnodesentinel 的关联关系体现。

以下是 ngx_str_rbtree_insert_value 函数的逐行详细解释,涵盖代码作用、背景、逻辑、意图及设计思想:


详解

ngx_str_node_t      *n, *t;
ngx_rbtree_node_t  **p;
  • nt 用于将通用红黑树节点(ngx_rbtree_node_t)转换为字符串节点(ngx_str_node_t),以便访问字符串数据(str 字段)。

  • p 是指向红黑树节点指针的指针,用于直接修改父节点的子节点指针(左或右)。

  • 通过类型转换扩展通用节点,支持自定义数据(字符串)。

  • 使用二级指针 p 简化插入逻辑,避免区分左/右子树。


for ( ;; ) {

循环遍历红黑树,逐层比较键值,直到找到插入位置。

通过迭代而非递归实现,减少函数调用开销,提升性能。


n = (ngx_str_node_t *) node;
t = (ngx_str_node_t *) temp;

node(待插入节点)和 temp(当前遍历节点)转换为 ngx_str_node_t 类型,以便访问字符串数据。
ngx_str_node_t 继承自 ngx_rbtree_node_t,添加了 ngx_str_t str 字段存储字符串。
ngx_str_node_t


比较键值(第一优先级:哈希值)
if (node->key != temp->key) {p = (node->key < temp->key) ? &temp->left : &temp->right;
  • 逻辑
    • nodetempkey(哈希值)不同,根据大小选择左或右子树。

    • p 指向 temp 的左或右子节点指针。

    • 优先比较整型 key(哈希值),速度快,减少字符串比较次数。

    • 哈希值不同直接决定插入方向,避免后续比较。


比较字符串长度(第二优先级)
} else if (n->str.len != t->str.len) {p = (n->str.len < t->str.len) ? &temp->left : &temp->right;
  • 逻辑:若 key 相同,比较字符串长度,不同则按长度排序。

  • 处理哈希冲突(不同字符串哈希值相同),通过长度快速区分。

  • 长度比较为整型操作,仍比逐字节比较高效。


比较字符串内容(第三优先级)
} else {p = (ngx_memcmp(n->str.data, t->str.data, n->str.len) < 0)? &temp->left : &temp->right;
}
  • 逻辑:若 key 和长度均相同,逐字节比较字符串内容,决定插入方向。

检查是否到达插入位置
if (*p == sentinel) {break;
}
temp = *p;
  • 逻辑
    • *p 指向哨兵(sentinel),说明找到插入位置,终止循环。

    • 否则,将 temp 更新为子节点,继续向下遍历。

    • 哨兵节点标记空子树,简化边界条件处理。

    • 通过迭代逐步深入树的底层。


插入节点并初始化
*p = node;          // 将节点插入到树中
node->parent = temp; // 设置父节点
node->left = sentinel; // 子节点初始化为哨兵
node->right = sentinel;
ngx_rbt_red(node);  // 标记为红色
  • 逻辑
    • *p = node:将新节点链接到父节点的左或右子节点。

    • 设置父节点、子节点为哨兵,标记颜色为红色。

    • 新节点初始化为红色,简化后续红黑树平衡调整(红黑树性质要求)。

    • 哨兵节点统一表示空子树,避免空指针判断。

ngx_rbt_red

#define ngx_rbt_red(node)               ((node)->color = 1)

  • 核心逻辑:通过多级比较(哈希值 → 长度 → 内容)确定插入位置,确保树的有序性。
  • 性能优化:优先使用整型比较(key 和长度),减少高开销的字符串内容比较。

http://www.ppmy.cn/devtools/164407.html

相关文章

PostgreSQL的基本使用

参考视频&#xff1a;零基础入门PostgreSQL教程 文章目录 一、PostgreSQL是什么&#xff1f;二、基本使用1.下载2.操作 一、PostgreSQL是什么&#xff1f; PostgreSQL 是一个免费的对象-关系数据库服务器&#xff0c;在灵活的BSD许可证下发行。 二、基本使用 1.下载 2.操作 …

在 Ubuntu 下通过 Docker 部署 Mastodon 服务器

引言 大家好&#xff0c;我是Hitch。今天咱们来聊聊如何在 Ubuntu 系统上通过 Docker 部署 Mastodon 服务器。Mastodon 是一个开源的社交网络平台&#xff0c;像 Twitter 但更自由。Docker 是一个强大的容器化工具&#xff0c;可以让我们轻松地打包和部署应用。接下来&#xf…

在已有的原生 App 里嵌入 Flutter 页面的方法

在原生 App 中嵌入 Flutter 页面&#xff0c;通常使用 Flutter 提供的**平台通道&#xff08;Platform Channels&#xff09;**来实现原生代码与 Flutter 之间的交互。具体实现方式依赖于原生 App 的平台&#xff08;如 Android 或 iOS&#xff09;&#xff0c;下面是两种常见的…

基于POI的Excel下拉框自动搜索,包括数据验证的单列删除

目录 目标 例子 1.搜索下拉框页 2.数据源页 3.效果 代码以及注意事项 1.代码 2.注意事项 1.基于Excel的话&#xff0c;相当于加入了一个【数据验证】 2.代码中的一些方法说明 目标 期望在Excel利用代码创建具备自动搜索功能的下拉框 例子 1.搜索下拉框页 2.数据源…

macOS 设置屏幕常亮 不休眠

Apple M1 Pro macOS Sonoma设置“永不”防止进入休眠 macOS Sonoma 设置“永不” 防止进入休眠

JAVA最新版本详细安装教程(附安装包)

目录 文章自述 一、JAVA下载 二、JAVA安装 1.首先在D盘创建【java/jdk-23】文件夹 2.把下载的压缩包移动到【jdk-23】文件夹内&#xff0c;右键点击【解压到当前文件夹】 3.如图解压会有【jdk-23.0.1】文件 4.右键桌面此电脑&#xff0c;点击【属性】 5.下滑滚动条&…

【算法系列】经典的堆排序算法

文章目录 堆排序算法什么是堆排序&#xff1f;二叉堆的概念 堆排序的基本步骤堆排序的详细流程构建最大堆维护最大堆排序过程Java代码实现 堆排序的图示步骤1. 初始的数组与堆2. 构建最大堆2.1. 检查节点9&#xff08;序号为3&#xff09;2.2. 检查节点6&#xff08;序号为2&am…

自动驾驶FSD技术的核心算法与软件实现

引言&#xff1a;FSD技术的定义与发展背景 在当今快速发展的科技领域中&#xff0c;自动驾驶技术已经成为全球关注的焦点之一。其中&#xff0c;“FSD”&#xff08;Full Self-Driving&#xff0c;全自动驾驶&#xff09;代表了这一领域的最高目标——让车辆在无需人类干预的情…