Redis:https://github.com/zwjlpeng/redis_deep_read
This blog post closely follows the internal implementation of the Redis ordered set of principles analysis, in this Bovenrivan the source code is in the following src/version.h defined in the redis version of the main
#define Redis_version "2.9.11"
In the analysis of the internal implementation of the Redis ordered set, I analyzed when Redis started to support the sequential set, the principle of jumping table, the structure of the jumping table, the Find/insert/delete implementation of the jump table, understand the basic structure of the jumping table, understand the Redis The implementation of the ordered set is not difficult, because the implementation of the Redis ordered set is also based on the jumping table as the underlying data structure, choose this data structure, not only because of simple, more because of performance.
The basic data structure of a jump table in Redis is defined as follows, and the hop table implemented in Redis is characterized by a forward pointer, a back pointer, and a span in the structure of the forward pointer, as compared to the basic hop table data structures. span fields, where the presence of this span field helps to quickly calculate the ranking of elements throughout the collection
//define a basic data node for a skip tabletypedef struct ZSKIPLISTNODE {robj*obj;//Zset Value DoubleScore;//Zset scorestruct Zskiplistnode *backward;//the back pointerstruct Zskiplistlevel {//forward Pointerstruct Zskiplistnode *forward; unsignedintspan; } level[];} zskiplistnode;typedef struct Zskiplist {struct Zskiplistnode*header, *tail; unsignedLonglength; intLevel ;} Zskiplist;//ordered set data structuretypedef struct ZSET {dict*dict;//dictionary holds value, with value as keyZskiplist *ZSL;} Zset;
Convert the above data structure into a more formalized graphical representation, as shown in
In, you can see that the header pointer is pointing to a table header node with a fixed level (32 layer ), why it is defined as a, because it is defined as a layer in theory for 2^32-1 an element of the query is optimal, and 2^32=4294967296 elements, for the vast majority of applications, is enough, so it is defined as a layer, to why the query is optimal, you can think of it as a a complete binary sorting tree of layers that calculates the number of nodes in the tree
Another notable point in Redis 's ordered set is how it is stored when the score is the same, and when the score of the two values in the collection is the same, the store in the Skip table compares the two values. The two values are sorted by dictionary stored in the Skip table structure
With the above-mentioned data structure related to the basic knowledge, to see the Redis on zskiplist/zskiplistnode related operations, the source code is as follows (source code is from t_zset.c)
Create the source of the skip table structure
//#define ZSKIPLIST_MAXLEVEL */should be enough for 2^32 elements * /Zskiplist *zslcreate (void) { intJ; Zskiplist*ZSL; //Allocating MemoryZSL = Zmalloc (sizeof(*ZSL)); ZSL->level =1;//The default level is 1Zsl->length =0;//Jump table length is set to 0Zsl->header = Zslcreatenode (Zskiplist_maxlevel,0, NULL); for(j =0; J < Zskiplist_maxlevel; J + +) { //because there are no elements, the forward pointer of the header node is set to 0Zsl->header->level[j].forward =NULL; //set the Span field in the forward pointer structure of the header node to 0Zsl->header->level[j].span =0; } //table header back pointer set to 0Zsl->header->backward =NULL; //footer node set to nullZsl->tail =NULL; returnZSL;}
In the above code called the zslcreatenode function, the source code of the function is as follows =
Zskiplistnode *zslcreatenode (intdouble score, RobJ *obj) { *zn = zmalloc (sizeof (*ZN) +level*sizeof(struct zskiplistlevel)); Zn->score = score; Zn->obj = obj; return Zn;}
After executing the above code, you will create a skip table structure as shown
The basic structure of the jump table is created, the following is the insert operation, the source code inRedis is as follows
Zskiplistnode *zslinsert (Zskiplist *ZSL,DoubleScore, RobJ *obj) {Zskiplistnode*update[zskiplist_maxlevel], *x;//Update[32]UnsignedintRank[zskiplist_maxlevel];//Rank[32] intI, level; Redisassert (!isNaN (score)); X= zsl->header; //find where an element is inserted for(i = zsl->level-1; I >=0; i--) { /*store rank that's 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 | |//The following is the case of scoring the same, comparing the dictionary sort of value(X->level[i].forward->score = = Score &&comparestringobjects (x->level[i].forward->obj,obj) <0)) {Rank[i]+ = X->Level[i].span; X= x->Level[i].forward; } Update[i]=x; } //generate a random number of layersLevel =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; } //record maximum number of layersZsl->level =Level ; } //Generating a skip table nodex =Zslcreatenode (level,score,obj); for(i =0; I < level; i++) {x->level[i].forward = update[i]->Level[i].forward; Update[i]->level[i].forward =x; //Update spanX->level[i].span = Update[i]->level[i].span-(rank[0] -Rank[i]); Update[i]->level[i].span = (rank[0]-rank[i]) +1; }//This situation only occurs when the number of layers that are randomly out is less than the maximum number of layers 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; ElseZSL->tail =x; ZSL->length++; returnx;}
In the source code above, there is a function to generate a random number of layers, as follows:
int zslrandomlevel (void int level = 1 ; // #define ZSKIPLIST_P 0.25 while ((Random () &0xffff ) < (zskiplist_p * 0XFFFF + = 1 ; // #ZSKIPLIST_MAXLEVEL return (level<zskiplist_maxlevel)? Level:zskiplist_maxlevel;}
The graphical form description is as follows:
Understand the insert operation, the other query, delete, the scope operation is basically similar, ignored here ...
Analysis of internal implementation principle of Redis ordered set (II.)