点击(此处)折叠或打开
- typedef struct zset {
- dict *dict;
- zskiplist *zsl;
- } zset;
由于dict当中只有在注册了keyDestructor的时候才会释放空间,zset为了释放元素的时候更加容易管理,这边只是在zslFreeNode()当中释放空间。删除的时候是从dict里rem,后在skiplist中删除。
这里的转换提供了双向转换,从ziplist到common zset和common zset到ziplist的转换都有,前者的转换基本就是没法满足在redis.conf当中设置的两个条件,具体如下:
点击(此处)折叠或打开
- # Similarly to hashes and lists, sorted sets are also specially encoded in
- # order to save a lot of space. This encoding is only used when the length and
- # elements of a sorted set are below the following limits:
- zset-max-ziplist-entries 128
- zset-max-ziplist-value 64
点击(此处)折叠或打开
- int zsetAdd(robj *zobj, double score, sds ele, int *flags, double *newscore) {
- /* Turn options into simple to check vars. */
- int incr = (*flags & ZADD_INCR) != 0;
- int nx = (*flags & ZADD_NX) != 0;
- int xx = (*flags & ZADD_XX) != 0;
- *flags = 0; /* We'll return our response flags. */
- double curscore;
- ...
- zobj->ptr = zzlInsert(zobj->ptr,ele,score);
- if (zzlLength(zobj->ptr) > server.zset_max_ziplist_entries)
- zsetConvert(zobj,OBJ_ENCODING_SKIPLIST);
- if (sdslen(ele) > server.zset_max_ziplist_value)
- zsetConvert(zobj,OBJ_ENCODING_SKIPLIST);
- if (newscore) *newscore = score;
- *flags |= ZADD_ADDED;
- return 1;
- ...
- return 0; /* Never reached. */
- }
点击(此处)折叠或打开
- void zsetConvertToZiplistIfNeeded(robj *zobj, size_t maxelelen) {
- if (zobj->encoding == OBJ_ENCODING_ZIPLIST) return;
- zset *zset = zobj->ptr;
- if (zset->zsl->length <= server.zset_max_ziplist_entries &&
- maxelelen <= server.zset_max_ziplist_value)
- zsetConvert(zobj,OBJ_ENCODING_ZIPLIST);
- }
点击(此处)折叠或打开
- void zunionInterGenericCommand(client *c, robj *dstkey, int op) {
- ...
- /* parse optional extra arguments */
- ...
- /* sort sets from the smallest to largest, this will improve our
- * algorithm's performance */
- ...
- /* Step 1: Create a dictionary of elements -> aggregated-scores
- * by iterating one sorted set after the other. */
- ...
- /* Step 2: convert the dictionary into the final sorted set. */
- ...
- if (dbDelete(c->db,dstkey))
- touched = 1;
- if (dstzset->zsl->length) {
- zsetConvertToZiplistIfNeeded(dstobj,maxelelen);
- dbAdd(c->db,dstkey,dstobj);
- addReplyLongLong(c,zsetLength(dstobj));
- signalModifiedKey(c->db,dstkey);
- notifyKeyspaceEvent(NOTIFY_ZSET,
- (op == SET_OP_UNION) ? "zunionstore" : "zinterstore",
- dstkey,c->db->id);
- server.dirty++;
- } else {
- decrRefCount(dstobj);
- addReply(c,shared.czero);
- if (touched) {
- signalModifiedKey(c->db,dstkey);
- notifyKeyspaceEvent(NOTIFY_GENERIC,"del",dstkey,c->db->id);
- server.dirty++;
- }
- }
- zfree(src);
- }
真正执行转换的代码如下:
点击(此处)折叠或打开
- void zsetConvert(robj *zobj, int encoding) {
- zset *zs;
- zskiplistNode *node, *next;
- sds ele;
- double score;
- if (zobj->encoding == encoding) return;
- if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
- unsigned char *zl = zobj->ptr;
- unsigned char *eptr, *sptr;
- unsigned char *vstr;
- unsigned int vlen;
- long long vlong;
- if (encoding != OBJ_ENCODING_SKIPLIST)
- serverPanic("Unknown target encoding");
- zs = zmalloc(sizeof(*zs));
- zs->dict = dictCreate(&zsetDictType,NULL);
- zs->zsl = zslCreate();
- eptr = ziplistIndex(zl,0);
- serverAssertWithInfo(NULL,zobj,eptr != NULL);
- sptr = ziplistNext(zl,eptr);
- serverAssertWithInfo(NULL,zobj,sptr != NULL);
- while (eptr != NULL) {
- score = zzlGetScore(sptr);
- serverAssertWithInfo(NULL,zobj,ziplistGet(eptr,&vstr,&vlen,&vlong));
- if (vstr == NULL)
- ele = sdsfromlonglong(vlong);
- else
- ele = sdsnewlen((char*)vstr,vlen);
- node = zslInsert(zs->zsl,score,ele);
- serverAssert(dictAdd(zs->dict,ele,&node->score) == DICT_OK);
- zzlNext(zl,&eptr,&sptr);
- }
- zfree(zobj->ptr);
- zobj->ptr = zs;
- zobj->encoding = OBJ_ENCODING_SKIPLIST;
- } else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
- unsigned char *zl = ziplistNew();
- if (encoding != OBJ_ENCODING_ZIPLIST)
- serverPanic("Unknown target encoding");
- /* Approach similar to zslFree(), since we want to free the skiplist at
- * the same time as creating the ziplist. */
- zs = zobj->ptr;
- dictRelease(zs->dict);
- node = zs->zsl->header->level[0].forward;
- zfree(zs->zsl->header);
- zfree(zs->zsl);
- while (node) {
- zl = zzlInsertAt(zl,NULL,node->ele,node->score);
- next = node->level[0].forward;
- zslFreeNode(node);
- node = next;
- }
- zfree(zs);
- zobj->ptr = zl;
- zobj->encoding = OBJ_ENCODING_ZIPLIST;
- } else {
- serverPanic("Unknown sorted set encoding");
- }
- }
点击(此处)折叠或打开
- void zremCommand(client *c) {
- robj *key = c->argv[1];
- robj *zobj;
- int deleted = 0, keyremoved = 0, j;
- if ((zobj = lookupKeyWriteOrReply(c,key,shared.czero)) == NULL ||
- checkType(c,zobj,OBJ_ZSET)) return;
- for (j = 2; j < c->argc; j++) {
- if (zsetDel(zobj,c->argv[j]->ptr)) deleted++;
- if (zsetLength(zobj) == 0) {
- dbDelete(c->db,key);
- keyremoved = 1;
- break;
- }
- }
- if (deleted) {
- notifyKeyspaceEvent(NOTIFY_ZSET,"zrem",key,c->db->id);
- if (keyremoved)
- notifyKeyspaceEvent(NOTIFY_GENERIC,"del",key,c->db->id);
- signalModifiedKey(c->db,key);
- server.dirty += deleted;
- }
- addReplyLongLong(c,deleted);
- }
还请各位多提宝贵意见~~~