Redis Jumping Table Source code Analysis

Source: Internet
Author: User
Tags comments comparison redis

The jump table is an ordered data structure that supports the average O (logn) and worst O (N) complexity of node lookups. Jumping tables are applied to the scene of an ordered set key and a cluster node. This article refers to the Redis3.0 version of the source code, the comments refer to the Huang Jianhong comments, and add their own understanding. The definition of jumping tables and nodes is in redis.h, and the implementation of common APIs is in t_zset.c.

Defined:

 /* * Skip Table *
/typedef struct ZSKIPLIST {

    //Table head node and footer node
    struct zskiplistnode *header, *tail;

    The number of nodes in the table, not including the head node
    unsigned long length;

    The number of layers of the largest node of the table, not including the head node
    int level;

} zskiplist;
/* Zsets use a specialized version of Skiplists
*
 /* * Skip Table node *
/typedef struct ZSKIPLISTNODE {

    / /Member Object
    robj *obj;

    Score
    double score;

    Back pointer
    struct Zskiplistnode *backward;

    Layer
    struct Zskiplistlevel {

        //forward pointer
        struct Zskiplistnode *forward;

        span
        unsigned int span;

    } level[];

} Zskiplistnode;


The following is a possible example of a jump:


NEW: Zslcreate

 /* * Create and return a new skip table
 *
 * T = O (1) */
zskiplist *zslcreate (void) {
    int J;
    Zskiplist *ZSL;

    Allocation space
    ZSL = zmalloc (sizeof (*ZSL));

    Set height and start layer
    zsl->level = 1;
    zsl->length = 0;

    Initialize header node
    //T = O (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;

    Set footer
    zsl->tail = NULL;

    return ZSL;
}
/*
 Create a jump table node with a level of layer,
 * and set the node's member object to obj, with the score set to score. * *
 return value for newly created jump table node
 *
 * T = O (1) *
 /
zskiplistnode *zslcreatenode (int level, double score, RobJ *obj) {
    
    //Allocated space
    Zskiplistnode *ZN = zmalloc (sizeof (*ZN) +level*sizeof (struct zskiplistlevel));

    Set Property
    Zn->score = score;
    Zn->obj = obj;

    return Zn;
}

Insert: The most core API

/* Create a new node with a member of obj with a score of score, * and insert the new node into the Jump table ZSL.
 * * The return value of the function is the new node. */Zskiplistnode *zslinsert (Zskiplist *ZSL, double score, RobJ *obj) {//This update is ingenious, recording the node closest to the insertion position, saving the LEVEL[I].FORW
    ARD//If the record track is tracked on the jump table, it is a vertical shape. Zskiplistnode *update[zskiplist_maxlevel], *x;
    unsigned int rank[zskiplist_maxlevel];

    int I, level;

    Redisassert (!isnan (score));
    Find the insertion position of the node at each layer x = zsl->header;
        for (i = zsl->level-1; i >= 0; i--) {/* store rank that was crossed to reach the insert position */  Rank[i] is used to record the total number of nodes to which layer I reaches the insertion position, i.e. the level closest (less than) the rank of the given score//rank[0] is the rank of the node closest to the insertion position, which is the final cumulative value of each layer in front rank[i] = i = = (ZSL-&GT;LEVEL-1)?

        0:RANK[I+1]; Traverse the jumping table along the forward pointer while (X->level[i].forward && (X->level[i].forward->score < score |
                |
                Comparison score (X->level[i].forward->score = = score &&//ratio member, T = O (N) ComParestringobjects (X->level[i].forward->obj,obj) < 0)) {//record how many nodes are spanned along the way rank[i] + = X-&G

            T;level[i].span;
        Move to next pointer x = x->level[i].forward;
    }//Record the node that will be connected to the new node update[i] = x; }/* We assume the key is not already inside, since we allow duplicated * scores, and the re-insertion of score And Redis object should never * happen since the caller of Zslinsert () should test in the hash table * if the El 
     Ement is already inside or not.
     * * The caller of Zslinsert () will ensure that the same score and elements of the same member do not appear, so there is no need for further checking, so you can create new elements directly.

    *//Get a random value as the number of layers of the new node//T = O (N) level = Zslrandomlevel ();

        If the number of layers of the new node is larger than the number of other nodes in the table//Then initialize unused layers in the header node and record them in the update array//In the future also point to the new node if (Level > Zsl->level) {
            Initialize unused layer//T = O (1) for (i = zsl->level; i < level; i++) {rank[i] = 0;
     Initializing an untouched interval in the head node [zsl->level,level]       Update[i] = zsl->header; Update[i]->level[i].span = zsl->length;
    This is not clear.}//Update table in the maximum number of nodes zsl->level = level;

    }//Create new node x = Zslcreatenode (level,score,obj);
        Point the previously recorded pointer to the new node and make the appropriate settings//T = O (1) for (i = 0; I < level; i++) {//Set the forward pointer of the new node
        
        X->level[i].forward = update[i]->level[i].forward;
        
        Point the forward pointer of each node recorded along the way to the new node Update[i]->level[i].forward = x; /* update span covered by update[i] as x are inserted here *//Calculate the number of nodes spanned by the new node//not in the pre-Insertion order: Update[i]. UPDATE[0] Insert x Post order: Update[i]. Update[0].. X//Rank[0]-rank[i] represents the span between update[i] and update[0] Span//Update[i]->level[i].span represents update[i] and update[

        span X->level[i].span between I]->level[i]->forward = Update[i]->level[i].span-(rank[0]-rank[i]); After the new node has been inserted, the span value of the node along the way//+1 of which is the new node, represented by the Update[i]->level[i] to x span update[i]->level[i].span = (rank[0]-rank[i]) + 1; 
    }/* increment span for untouched levels *//If the level of the new node is less than the maximum number of tiers of the jump table, the span value of the untouched node also needs to be increased by one, as it spans above the new node and points directly from the table header to the new node
    T = O (1) for (i = level; I < zsl->level; i++) {update[i]->level[i].span++; }//Set the new node's back pointer//new node may be inserted directly behind the head node, in which case Update[0] is header X->backward = (update[0] = = Zsl->header)?
    NULL:UPDATE[0];
    Whether the insertion position is inserted into the tail node if (x->level[0].forward) X->level[0].forward->backward = x;

    else Zsl->tail = x;

    Jump table node count increased by one zsl->length++;
return x; }
/* Returns a random level for the new Skiplist node we is going to create.
 *
 * Returns a random value that is used as the number of layers for the new hop table node.
 *
 * The return value of this function was between 1 and Zskiplist_maxlevel
 * (both inclusive), with a Powerlaw -alike distribution where higher
 * levels is less likely to be returned. 
 *
 * The return value is between 1 and zskiplist_maxlevel (including zskiplist_maxlevel),
 * The higher the probability of generating a larger value according to the power law used by the stochastic algorithm.
 *
 * T = O (N)
 */
int zslrandomlevel (void) {
    int level = 1;

    while ((random () &0xffff) < (zskiplist_p * 0xFFFF)), level
        + = 1;

    Return (level<zskiplist_maxlevel)? Level:zskiplist_maxlevel;
}

It is particularly important to note that this layer is created at random to generate a value between 1-32 according to the law of power. The specific algorithm is described in the stochastic algorithm.

Delete

/* Delete an element with matching score/object from the skiplist.
 * * Removes the node containing the given node score with the specified object, obj, from the Jump table ZSL. * * T_wrost = O (n^2), t_avg = O (n log n) */int Zsldelete (Zskiplist *ZSL, double score, RobJ *obj) {Zskiplistnode *
    Update[zskiplist_maxlevel], *x;

    int i;
    Traverse the jump table, find the target node, and record all the nodes along the way//T_wrost = O (n^2), t_avg = O (n log n) x = zsl->header; for (i = zsl->level-1; i >= 0; i--) {//Traversal jump table complexity is T_wrost = O (N), t_avg = O (log N) while (x->l
                Evel[i].forward && (X->level[i].forward->score < score | |
                Comparison score (X->level[i].forward->score = = Score &&//comparison object, T = O (N) Comparestringobjects (X->level[i].forward->obj,obj) < 0))//move along the forward pointer x = X->lev

        El[i].forward;
    Record nodes along the way update[i] = x; }/* We may have multiple elements with the same score and what we are need * isTo find the element with both, right score and object.
     * * Check the found element x, only if its score and object are the same, it will be deleted.
    */x = x->level[0].forward; if (x && score = = X->score && equalstringobjects (x->obj,obj)) {//T = O (1) zsldelet
        Enode (ZSL, x, update);
        T = O (1) zslfreenode (x);
    return 1; } else {return 0;/* not found */} return 0; /* Not found */}

Internal deletion:

/* Internal function used by Zsldelete, Zsldeletebyscore and Zsldeletebyrank * * Internal delete functions, * zsldelete, Zsldeleteran
 function calls such as Gebyscore and Zsldeletebyrank. * * T = O (1) * Input update is an array of predecessor nodes associated with the deletion of node x, similar to the update in the insert operation */void Zsldeletenode (Zskiplist *zsl, Zskiplistnode *x, ZSKIPL

    Istnode **update) {int i; Update all and deleted node X-related pointers to the nodes, remove the relationship between them//two cases://(1) Directly connected to delete node x: Add minus 1//(2) Across delete node: direct minus 1//T = O (1) for (i = 0; i < zsl->level; i++)
            {if (Update[i]->level[i].forward = = x) {Update[i]->level[i].span + = x->level[i].span-1;
        Update[i]->level[i].forward = x->level[i].forward;
        } else {Update[i]->level[i].span-= 1; }}//update the forward and backward pointers for deleted node x: Non-tailed and tail nodes are processed separately if (X->level[0].forward) {x->level[0].forward->backw
    ard = x->backward;
    } else {zsl->tail = x->backward; }//Update jump table maximum number of layers (only executed if the node being deleted is the highest node in the Jump table)//T = O (1)//Traverse the level array of the head node until the first forward pointer is found to be not null while (Zsl->level > 1 && zsl->header->level[zsl->level-1].

    Forward = = NULL) zsl->level--;
Skip Table node counter minus one zsl->length--; }
Zslgetrank:
/* Find the rank for a element by both score and key.
 * * Find the rank of the node that contains the given score and member object in the Jump table.
 * * Returns 0 When the element cannot is found, rank otherwise.
 * * If there is no node with a given score and member object, returns 0, otherwise the row is returned. 
 * Note that the rank is 1-based due to the span of zsl->header to the first element.
 * Note that because the table header of the jump table is also counted, the returned row is given a starting value of 1. * * T_wrost = O (N), t_avg = O (log N) */unsigned long Zslgetrank (Zskiplist *ZSL, double score, RobJ *o) {ZSKIPLISTN
    Ode *x;
    unsigned long rank = 0;

    int i;
    Traversing the entire jump table x = zsl->header;
            for (i = zsl->level-1; i >= 0; i--) {//Traverse nodes and compare elements while (X->level[i].forward &&
                (X->level[i].forward->score < score | | Alignment score (X->level[i].forward->score = = score &&//ratio member Object Co Mparestringobjects (X->level[i].forward->obj,o) <= 0)) {//cumulative spanning node count rank + = X->leve

          L[i].span;  Traverse the Skip table along the forward pointer x = x->level[i].forward; }/* x might are equal to Zsl->header, so test if obj is non-null *///x may be empty nodes, requires non-null judgment.
            You must ensure that not only the scores are equal, but also that the member objects are equal//T = O (N) if (x->obj && equalstringobjects (x->obj,o)) {
        return rank;
}}//did not find return 0; }

Reference documents:

https://blog.csdn.net/men_wen/article/details/70040026

https://blog.csdn.net/kisimple/article/details/38706729

Http://makaidong.com/yongning99/1/88707_10585499.html

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.