Redis中的跳跃表,实现有序集合

2023-09-17 09:06:37 浏览数 (1)

建议先关注、点赞、收藏后再阅读。

Redis跳跃表的每个节点需要存储以下信息:

  1. 层级(level):节点当前所处的层级(Level),层级从0开始计数,0级是底层。
  2. 成员(member):节点所携带的成员数据。
  3. 后退指针(backward pointer):指向节点前一个节点在同一层级上的指针。
  4. 层级跨度(level span):当前节点到下一个节点的跨度,即当前层级上,节点与下一个节点之间的距离。
  5. 层级跳跃指针(forward pointers):一个指针数组,用于指向当前节点在不同层级上的下一个节点,即跳跃表的索引结构。

Redis的跳跃表中每个节点的前进指针(pointer)

Redis跳跃表的每个节点都有一个前进指针,用于在跳跃表中快速定位下一个节点。前进指针有两种类型,分别是levelspan

  • level指针是一个数组,用于存储节点的向前移动的步数。数组的长度即为跳跃表的最大层数。每个索引位置上的值表示当前节点在该层中向前移动的步数。例如,level[0]表示节点在第一层中向前移动的步数。
  • span指针是一个数组,用于存储节点的跨越度(即相邻节点之间的节点数量)。数组的长度和level指针一样,每个索引位置上的值表示当前节点到它的下一个节点的距离(即跨度)。例如,span[0]表示当前节点到它的下一个节点在第一层上的距离。

通过使用这两个指针,Redis可以通过特定层数上的步数确定向前移动的位置,并通过跨度计算出下一个节点的位置,实现快速地访问、插入和删除节点的功能。这种设计可以大大提高查找效率,使得Redis跳跃表成为一种高效的数据结构。

确定节点在每个层级上的跳跃层数(level)需要根据以下算法:

  1. 初始化最大层数为1,并将每个层级的跳跃概率设为0.5。
  2. 生成一个随机数r,且r的范围为[0,1)。
  3. 如果r小于跳跃概率,将最大层数加1,并将跳跃概率设为0.5。
  4. 重复步骤2和3,直到r大于等于跳跃概率。
  5. 返回最大层数作为节点在每个层级上的跳跃层数。

具体示例:

假设最大层数为16,每个层级的跳跃概率为0.5,则节点在每个层级上的跳跃层数可以示例如下:

层级

跳跃概率

跳跃层数

1

0.5

2

2

0.5

3

3

0.5

4

4

0.5

5

5

0.5

6

6

0.5

7

7

0.5

8

8

0.5

9

9

0.5

10

10

0.5

11

11

0.5

12

12

0.5

13

13

0.5

14

14

0.5

15

15

0.5

16

16

1.0

17

根据以上算法,节点在每个层级上的跳跃层数可以根据跳跃概率来确定。

节点的分配内存操作如下:

  1. Redis会根据节点的类型(比如跳跃表节点、哈希表节点等)和节点的大小,选择合适的内存分配策略。
  2. 对于小于64字节的节点,Redis将使用jemalloc的jemalloc_malloc函数进行内存分配;对于大于或等于64字节的节点,Redis将使用jemalloc的jemalloc_calloc函数进行内存分配。
  3. 分配成功后,Redis会将分配的内存空间用于存储节点的数据。

节点的释放内存操作如下:

  1. 当节点不再被使用时,Redis会通过内存管理器来释放节点的内存。
  2. 对于小于64字节的节点,Redis将使用jemalloc的jemalloc_free函数将节点的内存释放回内存池;对于大于或等于64字节的节点,Redis将使用jemalloc的jemalloc_dalloc函数将节点的内存释放回内存池。
  3. 被释放的内存将返回给内存管理器,以便后续的内存分配使用。

通过使用内存管理器和jemalloc的分配和释放函数,Redis在跳跃表中的节点分配和释放内存的过程中能够高效地利用内存空间,并减少内存碎片的产生。

0 人点赞