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 或自定义函数)。不同场景下,红黑树的键比较方式可能不同(如按时间、按字符串等),通过注入插入策略实现灵活性。
  • 意图
    支持多种插入策略,使红黑树可复用于不同场景(如定时器管理、缓存索引),提升代码复用性。

相关推荐
迷雾骑士38 分钟前
CentOS 7.6上安装Docker(1)
linux·docker·centos
Htht1111 小时前
【Linux】之【Bug】VMware 虚拟机开机 一直卡在黑屏左上角下划线闪烁界面
linux·运维·bug
溟洵1 小时前
Linux下学【MySQL】表的连接(inner join、left join、right join)(简单试题理解版)
linux·运维·mysql
健康平安的活着1 小时前
性能调优-cpu的性能指标【经典篇】
linux·运维·服务器
努力努力再努力wz1 小时前
【Linux实践系列】:用c语言实现一个shell外壳程序
linux·运维·服务器·c语言·c++·redis
JANGHIGH1 小时前
Ubuntu 20.04下配置VSCode以支持Eigen库开发
linux·vscode·ubuntu
Watink Cpper2 小时前
[MySQL初阶]MySQL(1)MySQL的理解、库的操作、表的操作
linux·运维·服务器·数据库·c++·后端·mysql
赵民勇2 小时前
debian/control中的包关系
linux·debian
赵民勇2 小时前
debian/control 文件中的${misc:Depends}
linux·运维·debian
Dragon--Z2 小时前
本地部署大数据集群前置准备
大数据·linux·服务器