Redis Source code Profiling (12) The implementation of an ordered set skip table

Source: Internet
Author: User
Tags goto redis

An ordered set is a part of the Redis object system, which is stored in the form of a skip table and a compression list, and in the previous article, it introduces the implementation of the jumping table, and the realization of the jumping table of the ordered set.

This article is mainly about the ordered collection to add the data command, you will see later, in the command of the underlying implementation, is actually called the Skip table interface storage structure

The ordered set is defined in the Server.h file, but in addition to the skip table, the ordered set preserves a dictionary that is used to find the corresponding score for a particular data. According to the implementation of the jump table, we can see that the inside of the jump table is sorted by the score, through the score to find the data is OK, but if you want to find the score through the data, it seems to be inadequate, so Redis maintained a dictionary, to complete the task of finding the score by data

Server.h/
* ordered set */
typedef struct ZSET {
    dict *dict;/* Storage < data, score > key pair, used to find points by data
    */zskiplist * Zsl /* Skip table, save < score, data, internal through the score sort */
} zset;
ordered collection Operations Add Data

The command Zadd enables you to add an ordered collection to the database, which is implemented by the Zaddgenericcommand function. The function will first parse the command options, command arguments, and then depending on whether the underlying is implemented by a skip table or a compression list implementation, is the interface that calls both

/* Add data to an ordered collection */void Zaddgenericcommand (client *c, int flags) {static char *nanerr = "resulting score is not a numbe
    R (NaN) ";
    /* Get key */robj *key = c->argv[1];
    RobJ *ele;
    RobJ *zobj;
    RobJ *curobj;
    Double score = 0, *scores = NULL, curscore = 0.0;
    Int J, elements;
    int scoreidx = 0;
    ... scoreidx = 2; /* Get the parameter options, the parameter options are immediately after the key */.../* Convert the parameter options to a numeric variable */*/* ARGC Save all parameters, Scoreidx save the score position of the first data * argc-s
    COREIDX calculates all the scores, the number of data */elements = c->argc-scoreidx;
        /* As the score and data are in pairs, the number of inputs is judged to be valid */if (elements% 2) {addreply (c,shared.syntaxerr);
    Return 

    }/* Divide by 2 to calculate different < scores, number of data > pairs */elements/= 2;
    /* Check several options */... */* Assign memory for SCORE */scores = Zmalloc (sizeof (double) *elements); for (j = 0; J < elements; J + +) {/* Convert string type to double */if (getdoublefromobjectorreply (c,c->argv[score
    Idx+j*2],&scores[j],null)! = C_OK) goto cleanup;
}    /* Find in the database if there is a key key, the value corresponding to the return key */zobj = Lookupkeywrite (C->db,key); 
        if (zobj = = NULL) {/* If not present, create value */if (xx) goto reply_to_client;/* No key + xx option:nothing to do. */ /* Based on the parameter configuration select the underlying compression dictionary or skip table */* If the data length is greater than the specified value, then use the Skip table, otherwise select the compression list */if (server.zset_max_ziplist_entries =
            = 0 | |
            Server.zset_max_ziplist_value < Sdslen (c->argv[scoreidx+1]->ptr)) {/* Create an ordered collection of skip table encodings */
        Zobj = Createzsetobject ();
        } else {/* Creates an ordered set of compressed list encodings */zobj = Createzsetziplistobject ();
    }/* Adds a key-value pair to the database, where the value is empty */Dbadd (c->db,key,zobj); } else {/* exists key key to determine if the original value was stored with an ordered set of */if (zobj->type! = obj_zset) {addreply (C,shared.wro
            NGTYPEERR);
        Goto cleanup;  }/* For each < score, data > pair, add it to zobj */for (j = 0; J < elements; J + +) {/* J scores */score
        = Scores[j]; /* API with a compressed list to perform the additionAdd Operation */if (zobj->encoding = = obj_encoding_ziplist) {...} else if (zobj->encoding = = OB
            J_encoding_skiplist) {/* Add data using the Skip Table API */Zset *zs = zobj->ptr;
            Zskiplistnode *znode;

            Dictentry *de; /* Try to convert the data to the appropriate encoding to save memory */ele = c->argv[scoreidx+1+j*2] = tryobjectencoding (c->argv[score
            IDX+1+J*2]);
            /* A dictionary is saved in an ordered collection implemented with a tab, the key is the data, the value is the score */de = Dictfind (Zs->dict,ele);
                /* Data to be added in an ordered collection */if (de! = NULL) {if (NX) continue;
                /* Get data and scores for key nodes */curobj = Dictgetkey (DE);

                Curscore = * (double*) dictgetval (DE);
                    /* INCR option if the data is present, add the corresponding score to it */if (INCR) {score + = Curscore;

                ...
                } /* Update data, score */if (score! = Curscore) {/* First delete, then add */Serverassertwithinfo (C,curobj,zsldelete (zs->zsl,curscore,curobj));
                    /* Skip Table Insert operation */Znode = Zslinsert (zs->zsl,score,curobj); 
                    /* Increase the reference count for the data */Incrrefcount (curobj); 
                    /* Update the score in the dictionary */dictgetval (DE) = &znode->score;
                    server.dirty++;
                updated++;
            } processed++;
                } else if (!XX) {/* does not have data to add, insert directly */Znode = Zslinsert (Zs->zsl,score,ele); Incrrefcount (ele); /* Inserted in Skiplist.
                */Serverassertwithinfo (C,null,dictadd (zs->dict,ele,&znode->score) = = DICT_OK); Incrrefcount (ele); /* Added to Dictionary.
                */server.dirty++;
                added++;
            processed++; }} else {serverpanic ("Unknown sorted set encoding"); }
    }
    ...
}

In order not to allow the function to be too long, we have removed some judgments and executions of the command options, but it is still very long ... Get Rank

In the jump table, see the Jump table can quickly calculate < score, data > ranking. Ranking is done by the Zrank command, and the underlying is implemented by the Zrankgnericcommand function

T_ZSET.C/* Returns the rank of the specified data under a key */void Zrankgenericcommand (client *c, int reverse) {/* first parameter is key */robj *key = C-&gt
    ; argv[1];
    /* The second parameter is a value */robj *ele = c->argv[2];
    RobJ *zobj;
    unsigned long llen;

    unsigned long rank;
        /* Find the key in the database if it exists, if present, and then determine if the value is stored by an ordered collection of */if ((Zobj = lookupkeyreadorreply (c,key,shared.nullbulk)) = = NULL | |
    Checktype (C,zobj,obj_zset)) return;

    /* Get the number of data in an ordered collection */Llen = Zsetlength (zobj);

    Serverassertwithinfo (C,ele,sdsencodedobject (ele));  /* Depending on the underlying implementation, choose a different interface */if (zobj->encoding = = obj_encoding_ziplist) {...} else if (zobj->encoding = =
        Obj_encoding_skiplist) {/* If the underlying is implemented with a hop table, call the Skip table interface */* to get the ordered set of key keys */Zset *zs = zobj->ptr;
        Zskiplist *ZSL = zs->zsl;
        Dictentry *de;

        Double score;
        Ele = c->argv[2];
  /* Because the jump table through the data to find the score is slow * so redis with dictionary saving < data, score > pair, can be quickly found by the data corresponding score */de = Dictfind (Zs->dict,ele);      if (de! = NULL) {/* If the data to find is present in an ordered collection, the score for the data is obtained */score = * (double*) dictgetval (DE);
            /* Call the Jump table interface to calculate the score score Rank */rank = Zslgetrank (Zsl,score,ele); 
            Serverassertwithinfo (C,ele,rank);
            /* Calculates whether to rank in a forward or reverse position depending on the options */if (reverse) Addreplylonglong (C,llen-rank);
        else Addreplylonglong (c,rank-1);
        } else {addreply (c,shared.nullbulk);
    }} else {serverpanic ("Unknown sorted set encoding"); }
}
calculate the number of data

The Zsetlength function is used to calculate the number of data in an ordered set, as well as an interface that calls a skip table or a compressed list

T_ZSET.C
/* Calculates the number of data in an ordered set *
/unsigned int zsetlength (robj *zobj) {
    int length =-1;
    /* Different interfaces are called depending on the underlying implementation *
    /if (zobj->encoding = = obj_encoding_ziplist) {
        ...
    } else if (zobj->encoding = = OBJ _encoding_skiplist) {/
        * The number of data is saved directly in the Skip table *
        /length = ((zset*) zobj->ptr)->zsl->length;
    } else {
        serverpanic ("Unknown sorted set Encoding");
    }
    return length;
}
Summary

The data stored in an ordered set is orderly, the bottom layer in the object system can be implemented by the jump table and the ordered list, and the implementation of the table is relatively simple, and the compression list implementation is more difficult to understand some

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.