本篇日记将记录Redis中使用到的跳跃表结构,该结构是ZSET底层encoding之一。欢迎提出意见和建议,比如文章完善度方面的,文章布局结构方面的等都可以,笔者将会持续改进
源码中的结构声明如下:
/* ZSETs use a specialized version of Skiplists */
typedef struct zskiplistNode { // 跳表的节点
sds ele; // 元素是一个简单动态字符串
double score; // 分数,用来排序,区间查询
struct zskiplistNode *backward; // 指像前一个节点的指针
struct zskiplistLevel { // 层结构,一个节点可以有多层
struct zskiplistNode *forward; // 每层都有一个指向后一个节点的指针
unsigned int span; // 跨度
} level[];
} zskiplistNode;
typedef struct zskiplist { // 跳表
struct zskiplistNode *header, *tail; // 头、尾指针
unsigned long length; // 节点个数
int level; // 除了header节点外所有节点中层数的最大值
} zskiplist;
复制
/* Create a new skiplist. */
zskiplist *zslCreate(void) {
int j;
zskiplist *zsl;
zsl = zmalloc(sizeof(*zsl));
zsl->level = 1;
zsl->length = 0;
// header 头节点初始化开始
// 确定头节点有ZSKIPLIST_MAXLEVEL层
// ZSKIPLIST_MAXLEVEL = 32 可以在server.h中找到
// #define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */
zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL);
// 然后遍历层,将每层的后继节点置为null,span置为0
for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) {
zsl->header->level[j].forward = NULL;
zsl->header->level[j].span = 0;
}
// 将头节点的前躯节点置为null
zsl->header->backward = NULL;
// header 头节点初始化结束
zsl->tail = NULL;
return zsl;
}
复制
/* Insert a new node in the skiplist. Assumes the element does not already
* exist (up to the caller to enforce that). The skiplist takes ownership
* of the passed SDS string 'ele'. */
zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele) {
... 省略其他代码
level = zslRandomLevel();
... 省略其他代码
return x;
}
复制
/* Returns a random level for the new skiplist node we are going to create.
* The return value of this function is between 1 and ZSKIPLIST_MAXLEVEL
* (both inclusive), with a powerlaw-alike distribution where higher
* levels are less likely to be returned.
* 为即将创建的跳表节点返回一个随机的level
* 返回值将在1~ZSKIPLIST_MAXLEVEL之间(包含1和32)
* 该方法使用powerlaw-alike distribution(google翻译为:幂律分布)
* 这种概率的方式使level返回的尽量小
*/
int zslRandomLevel(void) {
int level = 1;
// ZSKIPLIST_P = 0.25 可以在server.h中找到
// #define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */
// level 有四分之一的概率往上进行l累加
while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
level += 1;
return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}
复制
文章转载自无限递归,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
国产非关系型数据库 Eloqkv 初体验
JiekeXu
80次阅读
2025-04-10 23:51:35
融合Redis缓存的PostgreSQL高可用架构
梧桐
68次阅读
2025-04-08 06:35:40
缓存监控治理在游戏业务的实践和探索
vivo互联网技术
47次阅读
2025-03-20 09:51:10
Redis 集群主备切换原因分析
wzf0072
41次阅读
2025-03-20 17:51:42
Redis 高可用方案
天翼云开发者社区
36次阅读
2025-03-24 17:09:54
Redis Cluster集群模式:构建大规模高性能分布式存储系统
老王两点中
34次阅读
2025-03-17 09:00:28
Redis概要
听溪
29次阅读
2025-04-11 10:23:10
高并发场景下的库存管理,理论与实战能否兼得?
京东云开发者
23次阅读
2025-03-24 16:54:56
安装与配置Redis
鲁鲁
22次阅读
2025-04-11 10:26:10
使用Jedis访问Redis数据库
怀念和想念
21次阅读
2025-04-11 15:08:30