#define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^64 elements */// 跳跃表层数,最大为32层,理论上当数据达到2^64时,才会能达到最顶层,所以完全足够 #define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */// 用于计算上层被分配到的概率
/* Input flags. */ #define ZADD_NONE 0 #define ZADD_INCR (1<<0) /* Increment the score instead of setting it. */ #define ZADD_NX (1<<1) /* Don't touch elements not already existing. */ #define ZADD_XX (1<<2) /* Only touch elements already existing. */
/* Output flags. */ #define ZADD_NOP (1<<3) /* Operation not performed because of conditionals.*/ #define ZADD_NAN (1<<4) /* Only touch elements already existing. */ #define ZADD_ADDED (1<<5) /* The element was new and was added. */ #define ZADD_UPDATED (1<<6) /* The element already existed, score updated. */
/* Flags only used by the ZADD command but not by zsetAdd() API: */ #define ZADD_CH (1<<16) /* Return num of elements added or updated. */
/* Struct to hold a inclusive/exclusive range spec by score comparison. */ typedefstruct { double min, max; int minex, maxex; /* are min or max exclusive? */ } zrangespec;
/* Struct to hold an inclusive/exclusive range spec by lexicographic comparison. */ typedefstruct { sds min, max; /* May be set to shared.(minstring|maxstring) */ int minex, maxex; /* are min or max exclusive? */ } zlexrangespec;
/* 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){ zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x; // update数组用来记录新增节点的每一层的前驱节点指针 unsignedint rank[ZSKIPLIST_MAXLEVEL]; // rank数组用来记录从header的每一层到新增节点所经过的节点数 int i, level;
serverAssert(!isnan(score)); x = zsl->header; // 从最高层开始往下遍历 for (i = zsl->level-1; i >= 0; i--) { /* 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(); // 如果随机生成的层数比当前跳跃表的层数高,则初始化高于跳跃表的最高层数的所有层 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); // 根据update数组来进行新增节点的插入操作,根据rank数组来计算新增节点的跨度 for (i = 0; i < level; i++) { 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 */ x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]); update[i]->level[i].span = (rank[0] - rank[i]) + 1; }
/* increment span for untouched levels */ // 如果新增节点的层数低于跳跃表的层数,则高于新增节点的层数的跨度增加1 for (i = level; i < zsl->level; i++) { update[i]->level[i].span++; }
/* Delete an element with matching score/element from the skiplist. * The function returns 1 if the node was found and deleted, otherwise * 0 is returned. * * If 'node' is NULL the deleted node is freed by zslFreeNode(), otherwise * it is not freed (but just unlinked) and *node is set to the node pointer, * so that it is possible for the caller to reuse the node (including the * referenced SDS string at node->ele). */ intzslDelete(zskiplist *zsl, double score, sds ele, zskiplistNode **node){ zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x; int i;
x = zsl->header; // 从最高层开始遍历,查找所要删除节点在跳跃表中的位置 for (i = zsl->level-1; i >= 0; i--) { 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))) { x = x->level[i].forward; } update[i] = x; } /* We may have multiple elements with the same score, what we need * is to find the element with both the right score and object. */ x = x->level[0].forward; if (x && score == x->score && sdscmp(x->ele,ele) == 0) { // 删除节点 zslDeleteNode(zsl, x, update); if (!node) zslFreeNode(x); else *node = x; return1; } return0; /* not found */ }
/* Update the score of an elmenent inside the sorted set skiplist. * Note that the element must exist and must match 'score'. * This function does not update the score in the hash table side, the * caller should take care of it. * * Note that this function attempts to just update the node, in case after * the score update, the node would be exactly at the same position. * Otherwise the skiplist is modified by removing and re-adding a new * element, which is more costly. * * The function returns the updated element skiplist node pointer. */ zskiplistNode *zslUpdateScore(zskiplist *zsl, double curscore, sds ele, double newscore){ zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x; int i;
/* We need to seek to element to update to start: this is useful anyway, * we'll have to update or remove it. */ x = zsl->header; for (i = zsl->level-1; i >= 0; i--) { while (x->level[i].forward && (x->level[i].forward->score < curscore || (x->level[i].forward->score == curscore && sdscmp(x->level[i].forward->ele,ele) < 0))) { x = x->level[i].forward; } update[i] = x; }
/* Jump to our element: note that this function assumes that the * element with the matching score exists. */ x = x->level[0].forward; serverAssert(x && curscore == x->score && sdscmp(x->ele,ele) == 0);
/* If the node, after the score update, would be still exactly * at the same position, we can just update the score without * actually removing and re-inserting the element in the skiplist. */ if ((x->backward == NULL || x->backward->score < newscore) && (x->level[0].forward == NULL || x->level[0].forward->score > newscore)) { x->score = newscore; return x; }
/* No way to reuse the old node: we need to remove and insert a new * one at a different place. */ zslDeleteNode(zsl, x, update); zskiplistNode *newnode = zslInsert(zsl,newscore,x->ele); /* We reused the old node x->ele SDS string, free the node now * since zslInsert created a new one. */ x->ele = NULL; zslFreeNode(x); return newnode; }
1 2 3 4 5 6 7 8 9 10 11
// 随机层数算法 /* 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. */ intzslRandomLevel(void){ int level = 1; while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF)) level += 1; return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL; }
// 根据rank(排位)来查找跳跃表中指定的节点 /* Finds an element by its rank. The rank argument needs to be 1-based. */ zskiplistNode* zslGetElementByRank(zskiplist *zsl, unsignedlong rank){ zskiplistNode *x; unsignedlong traversed = 0; int i;
x = zsl->header; for (i = zsl->level-1; i >= 0; i--) { while (x->level[i].forward && (traversed + x->level[i].span) <= rank) { traversed += x->level[i].span; x = x->level[i].forward; } if (traversed == rank) { return x; } } returnNULL; }