Ubuntu 下 nginx-1.24.0 源码分析 - ngx_rbtree_init

ngx_rbtree_init


定义src\core\ngx_rbtree.h


c 复制代码
typedef ngx_uint_t  ngx_rbtree_key_t;
typedef ngx_int_t   ngx_rbtree_key_int_t;


typedef struct ngx_rbtree_node_s  ngx_rbtree_node_t;

struct ngx_rbtree_node_s {
    ngx_rbtree_key_t       key;
    ngx_rbtree_node_t     *left;
    ngx_rbtree_node_t     *right;
    ngx_rbtree_node_t     *parent;
    u_char                 color;
    u_char                 data;
};


typedef struct ngx_rbtree_s  ngx_rbtree_t;

typedef void (*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root,
    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);

struct ngx_rbtree_s {
    ngx_rbtree_node_t     *root;
    ngx_rbtree_node_t     *sentinel;
    ngx_rbtree_insert_pt   insert;
};


#define ngx_rbtree_init(tree, s, i)                                           \
    ngx_rbtree_sentinel_init(s);                                              \
    (tree)->root = s;                                                         \
    (tree)->sentinel = s;                                                     \
    (tree)->insert = i

c 复制代码
struct ngx_rbtree_s {
    ngx_rbtree_node_t     *root;
    ngx_rbtree_node_t     *sentinel;
    ngx_rbtree_insert_pt   insert;
};
1. ngx_rbtree_node_t *root
  • 作用:指向红黑树的根节点。

    • 根节点是红黑树的入口,所有操作(插入、查找、删除)都从根节点开始。

    • 初始时,根节点指向哨兵节点(表示空树);当插入第一个数据节点后,根节点会指向该节点。

    • 通过根节点动态管理树的结构变化(如旋转、颜色调整)。

    • 根节点与哨兵节点的绑定(初始化时 root = sentinel)简化了空树与非空树的逻辑统一性。


2. ngx_rbtree_node_t *sentinel
  • 作用:指向红黑树的哨兵节点(Sentinel Node)。

    • 哨兵节点是一个特殊的空节点,作为所有叶子节点和父节点的"占位符"。

    • 所有节点的 leftrightparent 指针在未分配时均指向哨兵。

    • 简化边界条件:避免空指针检查。例如,当遍历到叶子节点时,直接通过哨兵终止递归或循环。

    • 统一操作逻辑:无论是空树还是非空树,插入/删除操作的代码路径一致,无需额外分支判断。

    • 红黑树性质:哨兵节点颜色始终为黑色,确保红黑树性质(如根节点为黑色、叶子节点为黑色)。


3. ngx_rbtree_insert_pt insert
  • 作用:指向红黑树的插入策略函数。

    • 定义插入新节点时的键比较逻辑(如按数值大小、按时间戳排序)。

    • Nginx 提供了两种预定义策略:

      • ngx_rbtree_insert_value:按节点键的数值排序(升序)。
      • ngx_rbtree_insert_timer_value:按时间戳排序(用于定时器管理)。
    • 策略模式:通过函数指针注入不同的插入逻辑,使红黑树可复用于不同场景。

    • 解耦逻辑:将红黑树的通用操作(如旋转、颜色调整)与业务逻辑(键比较)分离,提高代码复用性。


c 复制代码
struct ngx_rbtree_node_s {
    ngx_rbtree_key_t       key;
    ngx_rbtree_node_t     *left;
    ngx_rbtree_node_t     *right;
    ngx_rbtree_node_t     *parent;
    u_char                 color;
    u_char                 data;
};
1. ngx_rbtree_key_t key
  • 作用:存储节点的键值,用于排序和查找。

    • 键值是红黑树的排序依据,决定了节点在树中的位置。

    • 通过键值快速定位节点

    • 支持自定义键比较逻辑


2. ngx_rbtree_node_t *left*right
  • 作用 :指向左、右子节点的指针。
    • 左子节点:键值小于当前节点(根据插入策略)。

    • 右子节点:键值大于当前节点(根据插入策略)。

    • 初始时,左右子节点均指向哨兵(表示空树)。

    • 维护二叉搜索树的有序性(左小右大)。

    • 支持快速遍历


3. ngx_rbtree_node_t *parent
  • 作用 :指向父节点的指针。
    • 记录当前节点的父节点位置,用于树的调整操作(如旋转、颜色翻转)。

    • 根节点的父节点指向哨兵。

    • 在插入/删除时,通过父节点链回溯调整树的平衡。

    • 例如:插入新节点后,从该节点向上检查红黑树性质是否被破坏。


4. u_char color
  • 作用 :标记节点颜色(0 表示黑色,1 表示红色)。

    • 颜色标记是红黑树平衡的核心机制。
    • 通过颜色调整和旋转操作,确保树的高度近似平衡(最坏情况下操作复杂度为 O(log n))。

5. u_char data
  • 作用:存储附加数据(可选)。
  • 意义
    • Nginx 中通常不直接使用此字段,而是通过继承或封装扩展节点功能。
    • 通过 data 字段实现节点与业务数据的关联,避免全局查找。
    • 保持红黑树结构的通用性(键值和颜色是核心,业务数据通过 data 扩展)。

c 复制代码
typedef void (*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root,
    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
1. 定义插入策略的回调函数
  • 作用
    该函数指针类型定义了红黑树插入操作的通用接口,用于指定如何将新节点插入到红黑树中
  • 意义
    • 将红黑树的通用操作 (如平衡调整)与业务逻辑(如键值比较规则)分离。
    • 允许用户自定义插入策略,适应不同场景(如按数值排序、按时间排序)。

2. 参数解析
  • ngx_rbtree_node_t *root
    红黑树的根节点,插入操作从根节点开始遍历,找到新节点的合适位置。
  • ngx_rbtree_node_t *node
    待插入的新节点,其 key 字段已初始化,用于决定插入位置。
  • ngx_rbtree_node_t *sentinel
    哨兵节点,用于标记空子节点和树的边界。

3. 典型插入策略示例

Nginx 内置了两种常用插入策略,通过函数指针动态绑定:

策略 1:按键值升序插入(ngx_rbtree_insert_value
  • 逻辑
    根据节点的 key 字段从小到大排序,确保左子树键值 ≤ 父节点键值 ≤ 右子树键值。
  • 应用场景
    通用键值管理(如内存块大小索引)。
策略 2:按时间戳插入(ngx_rbtree_insert_timer_value
  • 逻辑
    根据节点的 key 字段表示的时间戳排序,最近超时的事件位于最左侧。
  • 应用场景
    Nginx 定时器模块(管理 HTTP 超时、缓存过期等事件)。

设计思想

1. 策略模式(Strategy Pattern)
  • 核心思想
    将算法(插入逻辑)与数据结构(红黑树)解耦,通过函数指针动态切换策略。
  • 优势
    • 复用性:同一红黑树结构可服务于不同业务(如内存管理、定时器)。
    • 可扩展性:用户可自定义插入逻辑(如按字符串、IP 地址排序),无需修改红黑树核心代码。
2. 分层设计
  • 通用层
    红黑树负责平衡操作(旋转、颜色调整),与键值无关。
  • 业务层
    插入策略函数实现具体的键值比较逻辑

c 复制代码
#define ngx_rbtree_init(tree, s, i)                                           \
    ngx_rbtree_sentinel_init(s);                                              \
    (tree)->root = s;                                                         \
    (tree)->sentinel = s;                                                     \
    (tree)->insert = i

ngx_rbtree_init 是 Nginx 中用于初始化红黑树的宏


1. ngx_rbtree_sentinel_init(s);

  • 作用 :初始化哨兵节点 s
    ngx_rbtree_sentinel_init
  • 逻辑
    红黑树使用哨兵节点(sentinel)作为所有叶子节点和根节点的"空"占位符。此行将哨兵节点 s 的左右子节点、父节点均指向自身,并设置颜色为黑色(红黑树性质要求哨兵为黑色)。
  • 意图
    哨兵节点简化了边界条件处理(如空树或叶子节点的操作),避免频繁的空指针检查,提升代码效率和可维护性。

2. (tree)->root = s;

  • 作用:将红黑树的根节点初始化为哨兵。
  • 逻辑
    初始时树为空,根节点指向哨兵,表示树中无有效数据节点。
  • 意图
    统一空树与非空树的处理逻辑。后续插入节点时,根节点会动态更新为实际节点,但始终通过哨兵节点维护树的结构完整性。

3. (tree)->sentinel = s;

  • 作用 :将红黑树的哨兵指针指向 s
  • 逻辑
    红黑树结构体中需保存哨兵节点的引用,以便在插入、删除等操作中快速访问哨兵。
  • 意图
    确保所有操作(如旋转、颜色调整)能正确识别和操作哨兵节点,维持红黑树的平衡性质。

4. (tree)->insert = i;

  • 作用 :设置红黑树的插入策略函数为 i
  • 逻辑
    i 是一个函数指针,指向具体的插入逻辑(如 ngx_rbtree_insert_value 或自定义函数)。不同场景下,红黑树的键比较方式可能不同(如按时间、按字符串等),通过注入插入策略实现灵活性。
  • 意图
    支持多种插入策略,使红黑树可复用于不同场景(如定时器管理、缓存索引),提升代码复用性。

相关推荐
clever1014 小时前
在ubuntu系统上离线安装jenkins的做法
ubuntu·servlet·jenkins
炫友呀7 小时前
Centos 更新/修改宝塔版本
linux·运维·centos
花小璇学linux11 小时前
imx6ull-驱动开发篇24——Linux 中断API函数
linux·驱动开发·嵌入式软件
林开落L11 小时前
库制作与原理(下)
linux·开发语言·centos·库制作与原理
HYI11 小时前
小公司前端多分支测试太痛苦?我自己写了个轻量 CLI
nginx·vite
wxy31911 小时前
嵌入式LINUX——————TCP并发服务器
java·linux·网络
Castamere12 小时前
配置 Linux 终端 (zsh)
linux
小韩博13 小时前
metasploit 框架安装更新遇到无法下载问题如何解决
linux·网络安全·公钥·下载失败
长臂人猿13 小时前
JVM常用工具:jstat、jmap、jstack
linux·运维·jvm
轻松Ai享生活14 小时前
揭秘 linux:一张图看懂系统配置的核心
linux