IDEA2023.1.3破解,IDEA破解,IDEA 2023.1破解,最新IDEA激活码

二十、Redis 跳跃表的实现

IDEA2023.1.3破解,IDEA破解,IDEA 2023.1破解,最新IDEA激活码

Redis 的跳跃表由 redis.h/zskiplistNoderedis.h/zskiplist 两个结构定义, 其中 zskiplistNode 结构用于表示跳跃表节点, 而 zskiplist结构则用于保存跳跃表节点的相关信息, 比如节点的数量, 以及指向表头节点和表尾节点的指针, 等等。

43_1.png

图 5-1 展示了一个跳跃表示例, 位于图片最左边的是 zskiplist 结构, 该结构包含以下属性:

  • header :指向跳跃表的表头节点。
  • tail :指向跳跃表的表尾节点。
  • level :记录目前跳跃表内,层数最大的那个节点的层数(表头节点的层数不计算在内)。
  • length :记录跳跃表的长度,也即是,跳跃表目前包含节点的数量(表头节点不计算在内)。

位于 zskiplist 结构右方的是四个 zskiplistNode 结构, 该结构包含以下属性:

  • 层(level):节点中用 L1L2L3 等字样标记节点的各个层, L1 代表第一层, L2 代表第二层,以此类推。每个层都带有两个属性:前进指针和跨度。前进指针用于访问位于表尾方向的其他节点,而跨度则记录了前进指针所指向节点和当前节点的距离。在上面的图片中,连线上带有数字的箭头就代表前进指针,而那个数字就是跨度。当程序从表头向表尾进行遍历时,访问会沿着层的前进指针进行。
  • 后退(backward)指针:节点中用 BW 字样标记节点的后退指针,它指向位于当前节点的前一个节点。后退指针在程序从表尾向表头遍历时使用。
  • 分值(score):各个节点中的 1.02.03.0 是节点所保存的分值。在跳跃表中,节点按各自所保存的分值从小到大排列。
  • 成员对象(obj):各个节点中的 o1o2o3 是节点所保存的成员对象。

注意表头节点和其他节点的构造是一样的: 表头节点也有后退指针、分值和成员对象, 不过表头节点的这些属性都不会被用到, 所以图中省略了这些部分, 只显示了表头节点的各个层。

本节接下来的内容将对 zskiplistNodezskiplist 两个结构进行更详细的介绍。

跳跃表节点

跳跃表节点的实现由 redis.h/zskiplistNode 结构定义:

typedef struct zskiplistNode {

    // 后退指针
    struct zskiplistNode *backward;

    // 分值
    double score;

    // 成员对象
    robj *obj;

    // 层
    struct zskiplistLevel {

        // 前进指针
        struct zskiplistNode *forward;

        // 跨度
        unsigned int span;

    } level[];

} zskiplistNode;

跳跃表节点的 level 数组可以包含多个元素, 每个元素都包含一个指向其他节点的指针, 程序可以通过这些层来加快访问其他节点的速度, 一般来说, 层的数量越多, 访问其他节点的速度就越快。

每次创建一个新跳跃表节点的时候, 程序都根据幂次定律 (power law,越大的数出现的概率越小) 随机生成一个介于 132 之间的值作为 level 数组的大小, 这个大小就是层的“高度”。

图 5-2 分别展示了三个高度为 1 层、 3 层和 5 层的节点, 因为 C 语言的数组索引总是从 0 开始的, 所以节点的第一层是 level[0] , 而第二层是 level[1] , 以此类推。

43_2.png

前进指针

每个层都有一个指向表尾方向的前进指针(level[i].forward 属性), 用于从表头向表尾方向访问节点。

图 5-3 用虚线表示出了程序从表头向表尾方向, 遍历跳跃表中所有节点的路径:

1、 迭代程序首先访问跳跃表的第一个节点(表头), 然后从第四层的前进指针移动到表中的第二个节点。
2、 在第二个节点时, 程序沿着第二层的前进指针移动到表中的第三个节点。
3、 在第三个节点时, 程序同样沿着第二层的前进指针移动到表中的第四个节点。
4、 当程序再次沿着第四个节点的前进指针移动时, 它碰到一个 NULL , 程序知道这时已经到达了跳跃表的表尾, 于是结束这次遍历。

43_3.png

跨度

层的跨度(level[i].span 属性)用于记录两个节点之间的距离:

  • 两个节点之间的跨度越大, 它们相距得就越远。
  • 指向 NULL 的所有前进指针的跨度都为 0 , 因为它们没有连向任何节点。

初看上去, 很容易以为跨度和遍历操作有关, 但实际上并不是这样 —— 遍历操作只使用前进指针就可以完成了, 跨度实际上是用来计算排位(rank)的: 在查找某个节点的过程中, 将沿途访问过的所有层的跨度累计起来, 得到的结果就是目标节点在跳跃表中的排位。

举个例子, 图 5-4 用虚线标记了在跳跃表中查找分值为 3.0 、 成员对象为 o3 的节点时, 沿途经历的层: 查找的过程只经过了一个层, 并且层的跨度为 3 , 所以目标节点在跳跃表中的排位为 3

干货推荐

文章永久链接:https://tech.souyunku.com/?p=11347


Warning: A non-numeric value encountered in /data/wangzhan/tech.souyunku.com.wp/wp-content/themes/dux/functions-theme.php on line 1154
赞(71) 打赏



未经允许不得转载:搜云库技术团队 » 二十、Redis 跳跃表的实现

IDEA2023.1.3破解,IDEA破解,IDEA 2023.1破解,最新IDEA激活码
IDEA2023.1.3破解,IDEA破解,IDEA 2023.1破解,最新IDEA激活码

评论 抢沙发

大前端WP主题 更专业 更方便

联系我们联系我们

觉得文章有用就打赏一下文章作者

微信扫一扫打赏

微信扫一扫打赏


Fatal error: Uncaught Exception: Cache directory not writable. Comet Cache needs this directory please: `/data/wangzhan/tech.souyunku.com.wp/wp-content/cache/comet-cache/cache/https/tech-souyunku-com/index.q`. Set permissions to `755` or higher; `777` might be needed in some cases. in /data/wangzhan/tech.souyunku.com.wp/wp-content/plugins/comet-cache/src/includes/traits/Ac/ObUtils.php:367 Stack trace: #0 [internal function]: WebSharks\CometCache\Classes\AdvancedCache->outputBufferCallbackHandler() #1 /data/wangzhan/tech.souyunku.com.wp/wp-includes/functions.php(5109): ob_end_flush() #2 /data/wangzhan/tech.souyunku.com.wp/wp-includes/class-wp-hook.php(303): wp_ob_end_flush_all() #3 /data/wangzhan/tech.souyunku.com.wp/wp-includes/class-wp-hook.php(327): WP_Hook->apply_filters() #4 /data/wangzhan/tech.souyunku.com.wp/wp-includes/plugin.php(470): WP_Hook->do_action() #5 /data/wangzhan/tech.souyunku.com.wp/wp-includes/load.php(1097): do_action() #6 [internal function]: shutdown_action_hook() #7 {main} thrown in /data/wangzhan/tech.souyunku.com.wp/wp-content/plugins/comet-cache/src/includes/traits/Ac/ObUtils.php on line 367