结构差异

结构定义在server.h文件
方法实现在t_zset.c文件(ziplist是压缩)

  1. zskiplistNode

    1
    2
    3
    4
    5
    6
    7
    8
    9
    typedef struct zskiplistNode {
    sds ele; // 原本是 robj *obj,表示保存的成员对象
    double score; // 分值
    struct zskiplistNode *backward; // 后退指针
    struct zskiplistLevel {
    struct zskiplistNode *forward; // 前进指针
    unsigned long span; // 跨度
    } level[];
    } zskiplistNode;
  2. zskiplist

    1
    2
    3
    4
    5
    typedef struct zskiplist {
    struct zskiplistNode *header, *tail; // 表头和表尾
    unsigned long length; // 长度,即节点数()不含表头
    int level; // 跳跃表内层数最大的节点的层数
    } zskiplist;

一些常量

  • ZSKIPLIST_P = 0.25,随机level的概率
  • ZSKIPLIST_MAXLEVEL = 64,最大level

level的幂次定律

幂次定律: 越大的数出现的概率越小
level为 n的概率大概是 (3/4)^n

1
2
3
4
5
6
7
int zslRandomLevel(void) {
int level = 1;
// 每次1/4的概率往上加
while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
level += 1;
return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}

API

  1. zslCreate

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    zskiplist *zslCreate(void) {
    int j;
    zskiplist *zsl;

    zsl = zmalloc(sizeof(*zsl));
    zsl->level = 1;
    zsl->length = 0;
    // 所以头节点是不计算长度的,而且初始化了最大的level但不计算level(算1)
    zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL);
    for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) {
    zsl->header->level[j].forward = NULL;
    zsl->header->level[j].span = 0;
    }
    zsl->header->backward = NULL;
    zsl->tail = NULL;
    return zsl;
    }
  2. zslInsert

    前提保证了元素不存在
    看起来有点复杂的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele) {
// 更新数组,存储新node插入,各层需要修改的node,也就是新node在各层插入在哪个node之后
zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
// 排序数组,存着各层从header到update里面的node的跨度和
unsigned int rank[ZSKIPLIST_MAXLEVEL];
int i, level;
// 非数字断言
serverAssert(!isnan(score));
x = zsl->header;
for (i = zsl->level-1; i >= 0; i--) { // 进行最大level次的遍历
/* store rank that is crossed to reach the insert position */
rank[i] = i == (zsl->level-1) ? 0 : rank[i+1];
while (x->level[i].forward &&
(x->level[i].forward->score < score ||
(x->level[i].forward->score == score &&
sdscmp(x->level[i].forward->ele,ele) < 0)))
{
rank[i] += x->level[i].span;
x = x->level[i].forward;
}
update[i] = x;
}
/* we assume the element is not already inside, since we allow duplicated
* scores, reinserting the same element should never happen since the
* caller of zslInsert() should test in the hash table if the element is
* already inside or not. */
level = zslRandomLevel();
// 如果随机出来的level更大,要补充update
// update的值直接设置成header,跨度是length,因为是一步到达
if (level > zsl->level) {
for (i = zsl->level; i < level; i++) {
rank[i] = 0;
update[i] = zsl->header;
update[i]->level[i].span = zsl->length;
}
zsl->level = level;
}
x = zslCreateNode(level,score,ele);
for (i = 0; i < level; i++) {
// 每一层
// 把新node放在update[i]和它的forward之间
x->level[i].forward = update[i]->level[i].forward;
update[i]->level[i].forward = x;

/* update span covered by update[i] as x is inserted here */
// 因为之前的rank累积关系,新node和update之间的node跨度就是(rank[0] - rank[i])
// x->level[i].span而这个值很可能是1
// 在新加层里面,因为指向的是Null,所以span值没有关系
x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]);
update[i]->level[i].span = (rank[0] - rank[i]) + 1; // 因为新加了一个node,所以+1
}

/* increment span for untouched levels */

// 新层因为新节点的出现,是forward到新节点的,sapn+1
for (i = level; i < zsl->level; i++) {
update[i]->level[i].span++;
}
// 第一层是顺序完全的
x->backward = (update[0] == zsl->header) ? NULL : update[0];
if (x->level[0].forward)
x->level[0].forward->backward = x;
else
zsl->tail = x;
zsl->length++;
return x;
}
  1. zslDelete

  2. zslUpdateScore

    是先delete,在insert,不复用