xref: /redis-3.2.3/src/t_zset.c (revision 6972f18c)
1 /*
2  * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
3  * Copyright (c) 2009-2012, Pieter Noordhuis <pcnoordhuis at gmail dot com>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  *   * Redistributions of source code must retain the above copyright notice,
10  *     this list of conditions and the following disclaimer.
11  *   * Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *   * Neither the name of Redis nor the names of its contributors may be used
15  *     to endorse or promote products derived from this software without
16  *     specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /*-----------------------------------------------------------------------------
32  * Sorted set API
33  *----------------------------------------------------------------------------*/
34 
35 /* ZSETs are ordered sets using two data structures to hold the same elements
36  * in order to get O(log(N)) INSERT and REMOVE operations into a sorted
37  * data structure.
38  *
39  * The elements are added to a hash table mapping Redis objects to scores.
40  * At the same time the elements are added to a skip list mapping scores
41  * to Redis objects (so objects are sorted by scores in this "view"). */
42 
43 /* This skiplist implementation is almost a C translation of the original
44  * algorithm described by William Pugh in "Skip Lists: A Probabilistic
45  * Alternative to Balanced Trees", modified in three ways:
46  * a) this implementation allows for repeated scores.
47  * b) the comparison is not just by key (our 'score') but by satellite data.
48  * c) there is a back pointer, so it's a doubly linked list with the back
49  * pointers being only at "level 1". This allows to traverse the list
50  * from tail to head, useful for ZREVRANGE. */
51 
52 #include "redis.h"
53 #include <math.h>
54 
55 zskiplistNode *zslCreateNode(int level, double score, robj *obj) {
56     zskiplistNode *zn = zmalloc(sizeof(*zn)+level*sizeof(struct zskiplistLevel));
57     zn->score = score;
58     zn->obj = obj;
59     return zn;
60 }
61 
62 zskiplist *zslCreate(void) {
63     int j;
64     zskiplist *zsl;
65 
66     zsl = zmalloc(sizeof(*zsl));
67     zsl->level = 1;
68     zsl->length = 0;
69     zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL);
70     for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) {
71         zsl->header->level[j].forward = NULL;
72         zsl->header->level[j].span = 0;
73     }
74     zsl->header->backward = NULL;
75     zsl->tail = NULL;
76     return zsl;
77 }
78 
79 void zslFreeNode(zskiplistNode *node) {
80     decrRefCount(node->obj);
81     zfree(node);
82 }
83 
84 void zslFree(zskiplist *zsl) {
85     zskiplistNode *node = zsl->header->level[0].forward, *next;
86 
87     zfree(zsl->header);
88     while(node) {
89         next = node->level[0].forward;
90         zslFreeNode(node);
91         node = next;
92     }
93     zfree(zsl);
94 }
95 
96 /* Returns a random level for the new skiplist node we are going to create.
97  * The return value of this function is between 1 and ZSKIPLIST_MAXLEVEL
98  * (both inclusive), with a powerlaw-alike distribution where higher
99  * levels are less likely to be returned. */
100 int zslRandomLevel(void) {
101     int level = 1;
102     while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
103         level += 1;
104     return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
105 }
106 
107 zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj) {
108     zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
109     unsigned int rank[ZSKIPLIST_MAXLEVEL];
110     int i, level;
111 
112     redisAssert(!isnan(score));
113     x = zsl->header;
114     for (i = zsl->level-1; i >= 0; i--) {
115         /* store rank that is crossed to reach the insert position */
116         rank[i] = i == (zsl->level-1) ? 0 : rank[i+1];
117         while (x->level[i].forward &&
118             (x->level[i].forward->score < score ||
119                 (x->level[i].forward->score == score &&
120                 compareStringObjects(x->level[i].forward->obj,obj) < 0))) {
121             rank[i] += x->level[i].span;
122             x = x->level[i].forward;
123         }
124         update[i] = x;
125     }
126     /* we assume the key is not already inside, since we allow duplicated
127      * scores, and the re-insertion of score and redis object should never
128      * happen since the caller of zslInsert() should test in the hash table
129      * if the element is already inside or not. */
130     level = zslRandomLevel();
131     if (level > zsl->level) {
132         for (i = zsl->level; i < level; i++) {
133             rank[i] = 0;
134             update[i] = zsl->header;
135             update[i]->level[i].span = zsl->length;
136         }
137         zsl->level = level;
138     }
139     x = zslCreateNode(level,score,obj);
140     for (i = 0; i < level; i++) {
141         x->level[i].forward = update[i]->level[i].forward;
142         update[i]->level[i].forward = x;
143 
144         /* update span covered by update[i] as x is inserted here */
145         x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]);
146         update[i]->level[i].span = (rank[0] - rank[i]) + 1;
147     }
148 
149     /* increment span for untouched levels */
150     for (i = level; i < zsl->level; i++) {
151         update[i]->level[i].span++;
152     }
153 
154     x->backward = (update[0] == zsl->header) ? NULL : update[0];
155     if (x->level[0].forward)
156         x->level[0].forward->backward = x;
157     else
158         zsl->tail = x;
159     zsl->length++;
160     return x;
161 }
162 
163 /* Internal function used by zslDelete, zslDeleteByScore and zslDeleteByRank */
164 void zslDeleteNode(zskiplist *zsl, zskiplistNode *x, zskiplistNode **update) {
165     int i;
166     for (i = 0; i < zsl->level; i++) {
167         if (update[i]->level[i].forward == x) {
168             update[i]->level[i].span += x->level[i].span - 1;
169             update[i]->level[i].forward = x->level[i].forward;
170         } else {
171             update[i]->level[i].span -= 1;
172         }
173     }
174     if (x->level[0].forward) {
175         x->level[0].forward->backward = x->backward;
176     } else {
177         zsl->tail = x->backward;
178     }
179     while(zsl->level > 1 && zsl->header->level[zsl->level-1].forward == NULL)
180         zsl->level--;
181     zsl->length--;
182 }
183 
184 /* Delete an element with matching score/object from the skiplist. */
185 int zslDelete(zskiplist *zsl, double score, robj *obj) {
186     zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
187     int i;
188 
189     x = zsl->header;
190     for (i = zsl->level-1; i >= 0; i--) {
191         while (x->level[i].forward &&
192             (x->level[i].forward->score < score ||
193                 (x->level[i].forward->score == score &&
194                 compareStringObjects(x->level[i].forward->obj,obj) < 0)))
195             x = x->level[i].forward;
196         update[i] = x;
197     }
198     /* We may have multiple elements with the same score, what we need
199      * is to find the element with both the right score and object. */
200     x = x->level[0].forward;
201     if (x && score == x->score && equalStringObjects(x->obj,obj)) {
202         zslDeleteNode(zsl, x, update);
203         zslFreeNode(x);
204         return 1;
205     } else {
206         return 0; /* not found */
207     }
208     return 0; /* not found */
209 }
210 
211 static int zslValueGteMin(double value, zrangespec *spec) {
212     return spec->minex ? (value > spec->min) : (value >= spec->min);
213 }
214 
215 static int zslValueLteMax(double value, zrangespec *spec) {
216     return spec->maxex ? (value < spec->max) : (value <= spec->max);
217 }
218 
219 /* Returns if there is a part of the zset is in range. */
220 int zslIsInRange(zskiplist *zsl, zrangespec *range) {
221     zskiplistNode *x;
222 
223     /* Test for ranges that will always be empty. */
224     if (range->min > range->max ||
225             (range->min == range->max && (range->minex || range->maxex)))
226         return 0;
227     x = zsl->tail;
228     if (x == NULL || !zslValueGteMin(x->score,range))
229         return 0;
230     x = zsl->header->level[0].forward;
231     if (x == NULL || !zslValueLteMax(x->score,range))
232         return 0;
233     return 1;
234 }
235 
236 /* Find the first node that is contained in the specified range.
237  * Returns NULL when no element is contained in the range. */
238 zskiplistNode *zslFirstInRange(zskiplist *zsl, zrangespec range) {
239     zskiplistNode *x;
240     int i;
241 
242     /* If everything is out of range, return early. */
243     if (!zslIsInRange(zsl,&range)) return NULL;
244 
245     x = zsl->header;
246     for (i = zsl->level-1; i >= 0; i--) {
247         /* Go forward while *OUT* of range. */
248         while (x->level[i].forward &&
249             !zslValueGteMin(x->level[i].forward->score,&range))
250                 x = x->level[i].forward;
251     }
252 
253     /* This is an inner range, so the next node cannot be NULL. */
254     x = x->level[0].forward;
255     redisAssert(x != NULL);
256 
257     /* Check if score <= max. */
258     if (!zslValueLteMax(x->score,&range)) return NULL;
259     return x;
260 }
261 
262 /* Find the last node that is contained in the specified range.
263  * Returns NULL when no element is contained in the range. */
264 zskiplistNode *zslLastInRange(zskiplist *zsl, zrangespec range) {
265     zskiplistNode *x;
266     int i;
267 
268     /* If everything is out of range, return early. */
269     if (!zslIsInRange(zsl,&range)) return NULL;
270 
271     x = zsl->header;
272     for (i = zsl->level-1; i >= 0; i--) {
273         /* Go forward while *IN* range. */
274         while (x->level[i].forward &&
275             zslValueLteMax(x->level[i].forward->score,&range))
276                 x = x->level[i].forward;
277     }
278 
279     /* This is an inner range, so this node cannot be NULL. */
280     redisAssert(x != NULL);
281 
282     /* Check if score >= min. */
283     if (!zslValueGteMin(x->score,&range)) return NULL;
284     return x;
285 }
286 
287 /* Delete all the elements with score between min and max from the skiplist.
288  * Min and max are inclusive, so a score >= min || score <= max is deleted.
289  * Note that this function takes the reference to the hash table view of the
290  * sorted set, in order to remove the elements from the hash table too. */
291 unsigned long zslDeleteRangeByScore(zskiplist *zsl, zrangespec range, dict *dict) {
292     zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
293     unsigned long removed = 0;
294     int i;
295 
296     x = zsl->header;
297     for (i = zsl->level-1; i >= 0; i--) {
298         while (x->level[i].forward && (range.minex ?
299             x->level[i].forward->score <= range.min :
300             x->level[i].forward->score < range.min))
301                 x = x->level[i].forward;
302         update[i] = x;
303     }
304 
305     /* Current node is the last with score < or <= min. */
306     x = x->level[0].forward;
307 
308     /* Delete nodes while in range. */
309     while (x && (range.maxex ? x->score < range.max : x->score <= range.max)) {
310         zskiplistNode *next = x->level[0].forward;
311         zslDeleteNode(zsl,x,update);
312         dictDelete(dict,x->obj);
313         zslFreeNode(x);
314         removed++;
315         x = next;
316     }
317     return removed;
318 }
319 
320 /* Delete all the elements with rank between start and end from the skiplist.
321  * Start and end are inclusive. Note that start and end need to be 1-based */
322 unsigned long zslDeleteRangeByRank(zskiplist *zsl, unsigned int start, unsigned int end, dict *dict) {
323     zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
324     unsigned long traversed = 0, removed = 0;
325     int i;
326 
327     x = zsl->header;
328     for (i = zsl->level-1; i >= 0; i--) {
329         while (x->level[i].forward && (traversed + x->level[i].span) < start) {
330             traversed += x->level[i].span;
331             x = x->level[i].forward;
332         }
333         update[i] = x;
334     }
335 
336     traversed++;
337     x = x->level[0].forward;
338     while (x && traversed <= end) {
339         zskiplistNode *next = x->level[0].forward;
340         zslDeleteNode(zsl,x,update);
341         dictDelete(dict,x->obj);
342         zslFreeNode(x);
343         removed++;
344         traversed++;
345         x = next;
346     }
347     return removed;
348 }
349 
350 /* Find the rank for an element by both score and key.
351  * Returns 0 when the element cannot be found, rank otherwise.
352  * Note that the rank is 1-based due to the span of zsl->header to the
353  * first element. */
354 unsigned long zslGetRank(zskiplist *zsl, double score, robj *o) {
355     zskiplistNode *x;
356     unsigned long rank = 0;
357     int i;
358 
359     x = zsl->header;
360     for (i = zsl->level-1; i >= 0; i--) {
361         while (x->level[i].forward &&
362             (x->level[i].forward->score < score ||
363                 (x->level[i].forward->score == score &&
364                 compareStringObjects(x->level[i].forward->obj,o) <= 0))) {
365             rank += x->level[i].span;
366             x = x->level[i].forward;
367         }
368 
369         /* x might be equal to zsl->header, so test if obj is non-NULL */
370         if (x->obj && equalStringObjects(x->obj,o)) {
371             return rank;
372         }
373     }
374     return 0;
375 }
376 
377 /* Finds an element by its rank. The rank argument needs to be 1-based. */
378 zskiplistNode* zslGetElementByRank(zskiplist *zsl, unsigned long rank) {
379     zskiplistNode *x;
380     unsigned long traversed = 0;
381     int i;
382 
383     x = zsl->header;
384     for (i = zsl->level-1; i >= 0; i--) {
385         while (x->level[i].forward && (traversed + x->level[i].span) <= rank)
386         {
387             traversed += x->level[i].span;
388             x = x->level[i].forward;
389         }
390         if (traversed == rank) {
391             return x;
392         }
393     }
394     return NULL;
395 }
396 
397 /* Populate the rangespec according to the objects min and max. */
398 static int zslParseRange(robj *min, robj *max, zrangespec *spec) {
399     char *eptr;
400     spec->minex = spec->maxex = 0;
401 
402     /* Parse the min-max interval. If one of the values is prefixed
403      * by the "(" character, it's considered "open". For instance
404      * ZRANGEBYSCORE zset (1.5 (2.5 will match min < x < max
405      * ZRANGEBYSCORE zset 1.5 2.5 will instead match min <= x <= max */
406     if (min->encoding == REDIS_ENCODING_INT) {
407         spec->min = (long)min->ptr;
408     } else {
409         if (((char*)min->ptr)[0] == '(') {
410             spec->min = strtod((char*)min->ptr+1,&eptr);
411             if (eptr[0] != '\0' || isnan(spec->min)) return REDIS_ERR;
412             spec->minex = 1;
413         } else {
414             spec->min = strtod((char*)min->ptr,&eptr);
415             if (eptr[0] != '\0' || isnan(spec->min)) return REDIS_ERR;
416         }
417     }
418     if (max->encoding == REDIS_ENCODING_INT) {
419         spec->max = (long)max->ptr;
420     } else {
421         if (((char*)max->ptr)[0] == '(') {
422             spec->max = strtod((char*)max->ptr+1,&eptr);
423             if (eptr[0] != '\0' || isnan(spec->max)) return REDIS_ERR;
424             spec->maxex = 1;
425         } else {
426             spec->max = strtod((char*)max->ptr,&eptr);
427             if (eptr[0] != '\0' || isnan(spec->max)) return REDIS_ERR;
428         }
429     }
430 
431     return REDIS_OK;
432 }
433 
434 /*-----------------------------------------------------------------------------
435  * Ziplist-backed sorted set API
436  *----------------------------------------------------------------------------*/
437 
438 double zzlGetScore(unsigned char *sptr) {
439     unsigned char *vstr;
440     unsigned int vlen;
441     long long vlong;
442     char buf[128];
443     double score;
444 
445     redisAssert(sptr != NULL);
446     redisAssert(ziplistGet(sptr,&vstr,&vlen,&vlong));
447 
448     if (vstr) {
449         memcpy(buf,vstr,vlen);
450         buf[vlen] = '\0';
451         score = strtod(buf,NULL);
452     } else {
453         score = vlong;
454     }
455 
456     return score;
457 }
458 
459 /* Compare element in sorted set with given element. */
460 int zzlCompareElements(unsigned char *eptr, unsigned char *cstr, unsigned int clen) {
461     unsigned char *vstr;
462     unsigned int vlen;
463     long long vlong;
464     unsigned char vbuf[32];
465     int minlen, cmp;
466 
467     redisAssert(ziplistGet(eptr,&vstr,&vlen,&vlong));
468     if (vstr == NULL) {
469         /* Store string representation of long long in buf. */
470         vlen = ll2string((char*)vbuf,sizeof(vbuf),vlong);
471         vstr = vbuf;
472     }
473 
474     minlen = (vlen < clen) ? vlen : clen;
475     cmp = memcmp(vstr,cstr,minlen);
476     if (cmp == 0) return vlen-clen;
477     return cmp;
478 }
479 
480 unsigned int zzlLength(unsigned char *zl) {
481     return ziplistLen(zl)/2;
482 }
483 
484 /* Move to next entry based on the values in eptr and sptr. Both are set to
485  * NULL when there is no next entry. */
486 void zzlNext(unsigned char *zl, unsigned char **eptr, unsigned char **sptr) {
487     unsigned char *_eptr, *_sptr;
488     redisAssert(*eptr != NULL && *sptr != NULL);
489 
490     _eptr = ziplistNext(zl,*sptr);
491     if (_eptr != NULL) {
492         _sptr = ziplistNext(zl,_eptr);
493         redisAssert(_sptr != NULL);
494     } else {
495         /* No next entry. */
496         _sptr = NULL;
497     }
498 
499     *eptr = _eptr;
500     *sptr = _sptr;
501 }
502 
503 /* Move to the previous entry based on the values in eptr and sptr. Both are
504  * set to NULL when there is no next entry. */
505 void zzlPrev(unsigned char *zl, unsigned char **eptr, unsigned char **sptr) {
506     unsigned char *_eptr, *_sptr;
507     redisAssert(*eptr != NULL && *sptr != NULL);
508 
509     _sptr = ziplistPrev(zl,*eptr);
510     if (_sptr != NULL) {
511         _eptr = ziplistPrev(zl,_sptr);
512         redisAssert(_eptr != NULL);
513     } else {
514         /* No previous entry. */
515         _eptr = NULL;
516     }
517 
518     *eptr = _eptr;
519     *sptr = _sptr;
520 }
521 
522 /* Returns if there is a part of the zset is in range. Should only be used
523  * internally by zzlFirstInRange and zzlLastInRange. */
524 int zzlIsInRange(unsigned char *zl, zrangespec *range) {
525     unsigned char *p;
526     double score;
527 
528     /* Test for ranges that will always be empty. */
529     if (range->min > range->max ||
530             (range->min == range->max && (range->minex || range->maxex)))
531         return 0;
532 
533     p = ziplistIndex(zl,-1); /* Last score. */
534     if (p == NULL) return 0; /* Empty sorted set */
535     score = zzlGetScore(p);
536     if (!zslValueGteMin(score,range))
537         return 0;
538 
539     p = ziplistIndex(zl,1); /* First score. */
540     redisAssert(p != NULL);
541     score = zzlGetScore(p);
542     if (!zslValueLteMax(score,range))
543         return 0;
544 
545     return 1;
546 }
547 
548 /* Find pointer to the first element contained in the specified range.
549  * Returns NULL when no element is contained in the range. */
550 unsigned char *zzlFirstInRange(unsigned char *zl, zrangespec range) {
551     unsigned char *eptr = ziplistIndex(zl,0), *sptr;
552     double score;
553 
554     /* If everything is out of range, return early. */
555     if (!zzlIsInRange(zl,&range)) return NULL;
556 
557     while (eptr != NULL) {
558         sptr = ziplistNext(zl,eptr);
559         redisAssert(sptr != NULL);
560 
561         score = zzlGetScore(sptr);
562         if (zslValueGteMin(score,&range)) {
563             /* Check if score <= max. */
564             if (zslValueLteMax(score,&range))
565                 return eptr;
566             return NULL;
567         }
568 
569         /* Move to next element. */
570         eptr = ziplistNext(zl,sptr);
571     }
572 
573     return NULL;
574 }
575 
576 /* Find pointer to the last element contained in the specified range.
577  * Returns NULL when no element is contained in the range. */
578 unsigned char *zzlLastInRange(unsigned char *zl, zrangespec range) {
579     unsigned char *eptr = ziplistIndex(zl,-2), *sptr;
580     double score;
581 
582     /* If everything is out of range, return early. */
583     if (!zzlIsInRange(zl,&range)) return NULL;
584 
585     while (eptr != NULL) {
586         sptr = ziplistNext(zl,eptr);
587         redisAssert(sptr != NULL);
588 
589         score = zzlGetScore(sptr);
590         if (zslValueLteMax(score,&range)) {
591             /* Check if score >= min. */
592             if (zslValueGteMin(score,&range))
593                 return eptr;
594             return NULL;
595         }
596 
597         /* Move to previous element by moving to the score of previous element.
598          * When this returns NULL, we know there also is no element. */
599         sptr = ziplistPrev(zl,eptr);
600         if (sptr != NULL)
601             redisAssert((eptr = ziplistPrev(zl,sptr)) != NULL);
602         else
603             eptr = NULL;
604     }
605 
606     return NULL;
607 }
608 
609 unsigned char *zzlFind(unsigned char *zl, robj *ele, double *score) {
610     unsigned char *eptr = ziplistIndex(zl,0), *sptr;
611 
612     ele = getDecodedObject(ele);
613     while (eptr != NULL) {
614         sptr = ziplistNext(zl,eptr);
615         redisAssertWithInfo(NULL,ele,sptr != NULL);
616 
617         if (ziplistCompare(eptr,ele->ptr,sdslen(ele->ptr))) {
618             /* Matching element, pull out score. */
619             if (score != NULL) *score = zzlGetScore(sptr);
620             decrRefCount(ele);
621             return eptr;
622         }
623 
624         /* Move to next element. */
625         eptr = ziplistNext(zl,sptr);
626     }
627 
628     decrRefCount(ele);
629     return NULL;
630 }
631 
632 /* Delete (element,score) pair from ziplist. Use local copy of eptr because we
633  * don't want to modify the one given as argument. */
634 unsigned char *zzlDelete(unsigned char *zl, unsigned char *eptr) {
635     unsigned char *p = eptr;
636 
637     /* TODO: add function to ziplist API to delete N elements from offset. */
638     zl = ziplistDelete(zl,&p);
639     zl = ziplistDelete(zl,&p);
640     return zl;
641 }
642 
643 unsigned char *zzlInsertAt(unsigned char *zl, unsigned char *eptr, robj *ele, double score) {
644     unsigned char *sptr;
645     char scorebuf[128];
646     int scorelen;
647     size_t offset;
648 
649     redisAssertWithInfo(NULL,ele,sdsEncodedObject(ele));
650     scorelen = d2string(scorebuf,sizeof(scorebuf),score);
651     if (eptr == NULL) {
652         zl = ziplistPush(zl,ele->ptr,sdslen(ele->ptr),ZIPLIST_TAIL);
653         zl = ziplistPush(zl,(unsigned char*)scorebuf,scorelen,ZIPLIST_TAIL);
654     } else {
655         /* Keep offset relative to zl, as it might be re-allocated. */
656         offset = eptr-zl;
657         zl = ziplistInsert(zl,eptr,ele->ptr,sdslen(ele->ptr));
658         eptr = zl+offset;
659 
660         /* Insert score after the element. */
661         redisAssertWithInfo(NULL,ele,(sptr = ziplistNext(zl,eptr)) != NULL);
662         zl = ziplistInsert(zl,sptr,(unsigned char*)scorebuf,scorelen);
663     }
664 
665     return zl;
666 }
667 
668 /* Insert (element,score) pair in ziplist. This function assumes the element is
669  * not yet present in the list. */
670 unsigned char *zzlInsert(unsigned char *zl, robj *ele, double score) {
671     unsigned char *eptr = ziplistIndex(zl,0), *sptr;
672     double s;
673 
674     ele = getDecodedObject(ele);
675     while (eptr != NULL) {
676         sptr = ziplistNext(zl,eptr);
677         redisAssertWithInfo(NULL,ele,sptr != NULL);
678         s = zzlGetScore(sptr);
679 
680         if (s > score) {
681             /* First element with score larger than score for element to be
682              * inserted. This means we should take its spot in the list to
683              * maintain ordering. */
684             zl = zzlInsertAt(zl,eptr,ele,score);
685             break;
686         } else if (s == score) {
687             /* Ensure lexicographical ordering for elements. */
688             if (zzlCompareElements(eptr,ele->ptr,sdslen(ele->ptr)) > 0) {
689                 zl = zzlInsertAt(zl,eptr,ele,score);
690                 break;
691             }
692         }
693 
694         /* Move to next element. */
695         eptr = ziplistNext(zl,sptr);
696     }
697 
698     /* Push on tail of list when it was not yet inserted. */
699     if (eptr == NULL)
700         zl = zzlInsertAt(zl,NULL,ele,score);
701 
702     decrRefCount(ele);
703     return zl;
704 }
705 
706 unsigned char *zzlDeleteRangeByScore(unsigned char *zl, zrangespec range, unsigned long *deleted) {
707     unsigned char *eptr, *sptr;
708     double score;
709     unsigned long num = 0;
710 
711     if (deleted != NULL) *deleted = 0;
712 
713     eptr = zzlFirstInRange(zl,range);
714     if (eptr == NULL) return zl;
715 
716     /* When the tail of the ziplist is deleted, eptr will point to the sentinel
717      * byte and ziplistNext will return NULL. */
718     while ((sptr = ziplistNext(zl,eptr)) != NULL) {
719         score = zzlGetScore(sptr);
720         if (zslValueLteMax(score,&range)) {
721             /* Delete both the element and the score. */
722             zl = ziplistDelete(zl,&eptr);
723             zl = ziplistDelete(zl,&eptr);
724             num++;
725         } else {
726             /* No longer in range. */
727             break;
728         }
729     }
730 
731     if (deleted != NULL) *deleted = num;
732     return zl;
733 }
734 
735 /* Delete all the elements with rank between start and end from the skiplist.
736  * Start and end are inclusive. Note that start and end need to be 1-based */
737 unsigned char *zzlDeleteRangeByRank(unsigned char *zl, unsigned int start, unsigned int end, unsigned long *deleted) {
738     unsigned int num = (end-start)+1;
739     if (deleted) *deleted = num;
740     zl = ziplistDeleteRange(zl,2*(start-1),2*num);
741     return zl;
742 }
743 
744 /*-----------------------------------------------------------------------------
745  * Common sorted set API
746  *----------------------------------------------------------------------------*/
747 
748 unsigned int zsetLength(robj *zobj) {
749     int length = -1;
750     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
751         length = zzlLength(zobj->ptr);
752     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
753         length = ((zset*)zobj->ptr)->zsl->length;
754     } else {
755         redisPanic("Unknown sorted set encoding");
756     }
757     return length;
758 }
759 
760 void zsetConvert(robj *zobj, int encoding) {
761     zset *zs;
762     zskiplistNode *node, *next;
763     robj *ele;
764     double score;
765 
766     if (zobj->encoding == encoding) return;
767     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
768         unsigned char *zl = zobj->ptr;
769         unsigned char *eptr, *sptr;
770         unsigned char *vstr;
771         unsigned int vlen;
772         long long vlong;
773 
774         if (encoding != REDIS_ENCODING_SKIPLIST)
775             redisPanic("Unknown target encoding");
776 
777         zs = zmalloc(sizeof(*zs));
778         zs->dict = dictCreate(&zsetDictType,NULL);
779         zs->zsl = zslCreate();
780 
781         eptr = ziplistIndex(zl,0);
782         redisAssertWithInfo(NULL,zobj,eptr != NULL);
783         sptr = ziplistNext(zl,eptr);
784         redisAssertWithInfo(NULL,zobj,sptr != NULL);
785 
786         while (eptr != NULL) {
787             score = zzlGetScore(sptr);
788             redisAssertWithInfo(NULL,zobj,ziplistGet(eptr,&vstr,&vlen,&vlong));
789             if (vstr == NULL)
790                 ele = createStringObjectFromLongLong(vlong);
791             else
792                 ele = createStringObject((char*)vstr,vlen);
793 
794             /* Has incremented refcount since it was just created. */
795             node = zslInsert(zs->zsl,score,ele);
796             redisAssertWithInfo(NULL,zobj,dictAdd(zs->dict,ele,&node->score) == DICT_OK);
797             incrRefCount(ele); /* Added to dictionary. */
798             zzlNext(zl,&eptr,&sptr);
799         }
800 
801         zfree(zobj->ptr);
802         zobj->ptr = zs;
803         zobj->encoding = REDIS_ENCODING_SKIPLIST;
804     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
805         unsigned char *zl = ziplistNew();
806 
807         if (encoding != REDIS_ENCODING_ZIPLIST)
808             redisPanic("Unknown target encoding");
809 
810         /* Approach similar to zslFree(), since we want to free the skiplist at
811          * the same time as creating the ziplist. */
812         zs = zobj->ptr;
813         dictRelease(zs->dict);
814         node = zs->zsl->header->level[0].forward;
815         zfree(zs->zsl->header);
816         zfree(zs->zsl);
817 
818         while (node) {
819             ele = getDecodedObject(node->obj);
820             zl = zzlInsertAt(zl,NULL,ele,node->score);
821             decrRefCount(ele);
822 
823             next = node->level[0].forward;
824             zslFreeNode(node);
825             node = next;
826         }
827 
828         zfree(zs);
829         zobj->ptr = zl;
830         zobj->encoding = REDIS_ENCODING_ZIPLIST;
831     } else {
832         redisPanic("Unknown sorted set encoding");
833     }
834 }
835 
836 /*-----------------------------------------------------------------------------
837  * Sorted set commands
838  *----------------------------------------------------------------------------*/
839 
840 /* This generic command implements both ZADD and ZINCRBY. */
841 void zaddGenericCommand(redisClient *c, int incr) {
842     static char *nanerr = "resulting score is not a number (NaN)";
843     robj *key = c->argv[1];
844     robj *ele;
845     robj *zobj;
846     robj *curobj;
847     double score = 0, *scores = NULL, curscore = 0.0;
848     int j, elements = (c->argc-2)/2;
849     int added = 0, updated = 0;
850 
851     if (c->argc % 2) {
852         addReply(c,shared.syntaxerr);
853         return;
854     }
855 
856     /* Start parsing all the scores, we need to emit any syntax error
857      * before executing additions to the sorted set, as the command should
858      * either execute fully or nothing at all. */
859     scores = zmalloc(sizeof(double)*elements);
860     for (j = 0; j < elements; j++) {
861         if (getDoubleFromObjectOrReply(c,c->argv[2+j*2],&scores[j],NULL)
862             != REDIS_OK) goto cleanup;
863     }
864 
865     /* Lookup the key and create the sorted set if does not exist. */
866     zobj = lookupKeyWrite(c->db,key);
867     if (zobj == NULL) {
868         if (server.zset_max_ziplist_entries == 0 ||
869             server.zset_max_ziplist_value < sdslen(c->argv[3]->ptr))
870         {
871             zobj = createZsetObject();
872         } else {
873             zobj = createZsetZiplistObject();
874         }
875         dbAdd(c->db,key,zobj);
876     } else {
877         if (zobj->type != REDIS_ZSET) {
878             addReply(c,shared.wrongtypeerr);
879             goto cleanup;
880         }
881     }
882 
883     for (j = 0; j < elements; j++) {
884         score = scores[j];
885 
886         if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
887             unsigned char *eptr;
888 
889             /* Prefer non-encoded element when dealing with ziplists. */
890             ele = c->argv[3+j*2];
891             if ((eptr = zzlFind(zobj->ptr,ele,&curscore)) != NULL) {
892                 if (incr) {
893                     score += curscore;
894                     if (isnan(score)) {
895                         addReplyError(c,nanerr);
896                         goto cleanup;
897                     }
898                 }
899 
900                 /* Remove and re-insert when score changed. */
901                 if (score != curscore) {
902                     zobj->ptr = zzlDelete(zobj->ptr,eptr);
903                     zobj->ptr = zzlInsert(zobj->ptr,ele,score);
904                     server.dirty++;
905                     updated++;
906                 }
907             } else {
908                 /* Optimize: check if the element is too large or the list
909                  * becomes too long *before* executing zzlInsert. */
910                 zobj->ptr = zzlInsert(zobj->ptr,ele,score);
911                 if (zzlLength(zobj->ptr) > server.zset_max_ziplist_entries)
912                     zsetConvert(zobj,REDIS_ENCODING_SKIPLIST);
913                 if (sdslen(ele->ptr) > server.zset_max_ziplist_value)
914                     zsetConvert(zobj,REDIS_ENCODING_SKIPLIST);
915                 server.dirty++;
916                 added++;
917             }
918         } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
919             zset *zs = zobj->ptr;
920             zskiplistNode *znode;
921             dictEntry *de;
922 
923             ele = c->argv[3+j*2] = tryObjectEncoding(c->argv[3+j*2]);
924             de = dictFind(zs->dict,ele);
925             if (de != NULL) {
926                 curobj = dictGetKey(de);
927                 curscore = *(double*)dictGetVal(de);
928 
929                 if (incr) {
930                     score += curscore;
931                     if (isnan(score)) {
932                         addReplyError(c,nanerr);
933                         /* Don't need to check if the sorted set is empty
934                          * because we know it has at least one element. */
935                         goto cleanup;
936                     }
937                 }
938 
939                 /* Remove and re-insert when score changed. We can safely
940                  * delete the key object from the skiplist, since the
941                  * dictionary still has a reference to it. */
942                 if (score != curscore) {
943                     redisAssertWithInfo(c,curobj,zslDelete(zs->zsl,curscore,curobj));
944                     znode = zslInsert(zs->zsl,score,curobj);
945                     incrRefCount(curobj); /* Re-inserted in skiplist. */
946                     dictGetVal(de) = &znode->score; /* Update score ptr. */
947                     server.dirty++;
948                     updated++;
949                 }
950             } else {
951                 znode = zslInsert(zs->zsl,score,ele);
952                 incrRefCount(ele); /* Inserted in skiplist. */
953                 redisAssertWithInfo(c,NULL,dictAdd(zs->dict,ele,&znode->score) == DICT_OK);
954                 incrRefCount(ele); /* Added to dictionary. */
955                 server.dirty++;
956                 added++;
957             }
958         } else {
959             redisPanic("Unknown sorted set encoding");
960         }
961     }
962     if (incr) /* ZINCRBY */
963         addReplyDouble(c,score);
964     else /* ZADD */
965         addReplyLongLong(c,added);
966 
967 cleanup:
968     zfree(scores);
969     if (added || updated) {
970         signalModifiedKey(c->db,key);
971         notifyKeyspaceEvent(REDIS_NOTIFY_ZSET,
972             incr ? "zincr" : "zadd", key, c->db->id);
973     }
974 }
975 
976 void zaddCommand(redisClient *c) {
977     zaddGenericCommand(c,0);
978 }
979 
980 void zincrbyCommand(redisClient *c) {
981     zaddGenericCommand(c,1);
982 }
983 
984 void zremCommand(redisClient *c) {
985     robj *key = c->argv[1];
986     robj *zobj;
987     int deleted = 0, keyremoved = 0, j;
988 
989     if ((zobj = lookupKeyWriteOrReply(c,key,shared.czero)) == NULL ||
990         checkType(c,zobj,REDIS_ZSET)) return;
991 
992     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
993         unsigned char *eptr;
994 
995         for (j = 2; j < c->argc; j++) {
996             if ((eptr = zzlFind(zobj->ptr,c->argv[j],NULL)) != NULL) {
997                 deleted++;
998                 zobj->ptr = zzlDelete(zobj->ptr,eptr);
999                 if (zzlLength(zobj->ptr) == 0) {
1000                     dbDelete(c->db,key);
1001                     break;
1002                 }
1003             }
1004         }
1005     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
1006         zset *zs = zobj->ptr;
1007         dictEntry *de;
1008         double score;
1009 
1010         for (j = 2; j < c->argc; j++) {
1011             de = dictFind(zs->dict,c->argv[j]);
1012             if (de != NULL) {
1013                 deleted++;
1014 
1015                 /* Delete from the skiplist */
1016                 score = *(double*)dictGetVal(de);
1017                 redisAssertWithInfo(c,c->argv[j],zslDelete(zs->zsl,score,c->argv[j]));
1018 
1019                 /* Delete from the hash table */
1020                 dictDelete(zs->dict,c->argv[j]);
1021                 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
1022                 if (dictSize(zs->dict) == 0) {
1023                     dbDelete(c->db,key);
1024                     break;
1025                 }
1026             }
1027         }
1028     } else {
1029         redisPanic("Unknown sorted set encoding");
1030     }
1031 
1032     if (deleted) {
1033         notifyKeyspaceEvent(REDIS_NOTIFY_ZSET,"zrem",key,c->db->id);
1034         if (keyremoved)
1035             notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",key,c->db->id);
1036         signalModifiedKey(c->db,key);
1037         server.dirty += deleted;
1038     }
1039     addReplyLongLong(c,deleted);
1040 }
1041 
1042 void zremrangebyscoreCommand(redisClient *c) {
1043     robj *key = c->argv[1];
1044     robj *zobj;
1045     zrangespec range;
1046     int keyremoved = 0;
1047     unsigned long deleted;
1048 
1049     /* Parse the range arguments. */
1050     if (zslParseRange(c->argv[2],c->argv[3],&range) != REDIS_OK) {
1051         addReplyError(c,"min or max is not a float");
1052         return;
1053     }
1054 
1055     if ((zobj = lookupKeyWriteOrReply(c,key,shared.czero)) == NULL ||
1056         checkType(c,zobj,REDIS_ZSET)) return;
1057 
1058     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
1059         zobj->ptr = zzlDeleteRangeByScore(zobj->ptr,range,&deleted);
1060         if (zzlLength(zobj->ptr) == 0) {
1061             dbDelete(c->db,key);
1062             keyremoved = 1;
1063         }
1064     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
1065         zset *zs = zobj->ptr;
1066         deleted = zslDeleteRangeByScore(zs->zsl,range,zs->dict);
1067         if (htNeedsResize(zs->dict)) dictResize(zs->dict);
1068         if (dictSize(zs->dict) == 0) {
1069             dbDelete(c->db,key);
1070             keyremoved = 1;
1071         }
1072     } else {
1073         redisPanic("Unknown sorted set encoding");
1074     }
1075 
1076     if (deleted) {
1077         signalModifiedKey(c->db,key);
1078         notifyKeyspaceEvent(REDIS_NOTIFY_ZSET,"zrembyscore",key,c->db->id);
1079         if (keyremoved)
1080             notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",key,c->db->id);
1081     }
1082     server.dirty += deleted;
1083     addReplyLongLong(c,deleted);
1084 }
1085 
1086 void zremrangebyrankCommand(redisClient *c) {
1087     robj *key = c->argv[1];
1088     robj *zobj;
1089     long start;
1090     long end;
1091     int llen;
1092     unsigned long deleted;
1093     int keyremoved = 0;
1094 
1095     if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != REDIS_OK) ||
1096         (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != REDIS_OK)) return;
1097 
1098     if ((zobj = lookupKeyWriteOrReply(c,key,shared.czero)) == NULL ||
1099         checkType(c,zobj,REDIS_ZSET)) return;
1100 
1101     /* Sanitize indexes. */
1102     llen = zsetLength(zobj);
1103     if (start < 0) start = llen+start;
1104     if (end < 0) end = llen+end;
1105     if (start < 0) start = 0;
1106 
1107     /* Invariant: start >= 0, so this test will be true when end < 0.
1108      * The range is empty when start > end or start >= length. */
1109     if (start > end || start >= llen) {
1110         addReply(c,shared.czero);
1111         return;
1112     }
1113     if (end >= llen) end = llen-1;
1114 
1115     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
1116         /* Correct for 1-based rank. */
1117         zobj->ptr = zzlDeleteRangeByRank(zobj->ptr,start+1,end+1,&deleted);
1118         if (zzlLength(zobj->ptr) == 0) {
1119             dbDelete(c->db,key);
1120             keyremoved = 1;
1121         }
1122     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
1123         zset *zs = zobj->ptr;
1124 
1125         /* Correct for 1-based rank. */
1126         deleted = zslDeleteRangeByRank(zs->zsl,start+1,end+1,zs->dict);
1127         if (htNeedsResize(zs->dict)) dictResize(zs->dict);
1128         if (dictSize(zs->dict) == 0) {
1129             dbDelete(c->db,key);
1130             keyremoved = 1;
1131         }
1132     } else {
1133         redisPanic("Unknown sorted set encoding");
1134     }
1135 
1136     if (deleted) {
1137         signalModifiedKey(c->db,key);
1138         notifyKeyspaceEvent(REDIS_NOTIFY_ZSET,"zrembyrank",key,c->db->id);
1139         if (keyremoved)
1140             notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",key,c->db->id);
1141     }
1142     server.dirty += deleted;
1143     addReplyLongLong(c,deleted);
1144 }
1145 
1146 typedef struct {
1147     robj *subject;
1148     int type; /* Set, sorted set */
1149     int encoding;
1150     double weight;
1151 
1152     union {
1153         /* Set iterators. */
1154         union _iterset {
1155             struct {
1156                 intset *is;
1157                 int ii;
1158             } is;
1159             struct {
1160                 dict *dict;
1161                 dictIterator *di;
1162                 dictEntry *de;
1163             } ht;
1164         } set;
1165 
1166         /* Sorted set iterators. */
1167         union _iterzset {
1168             struct {
1169                 unsigned char *zl;
1170                 unsigned char *eptr, *sptr;
1171             } zl;
1172             struct {
1173                 zset *zs;
1174                 zskiplistNode *node;
1175             } sl;
1176         } zset;
1177     } iter;
1178 } zsetopsrc;
1179 
1180 
1181 /* Use dirty flags for pointers that need to be cleaned up in the next
1182  * iteration over the zsetopval. The dirty flag for the long long value is
1183  * special, since long long values don't need cleanup. Instead, it means that
1184  * we already checked that "ell" holds a long long, or tried to convert another
1185  * representation into a long long value. When this was successful,
1186  * OPVAL_VALID_LL is set as well. */
1187 #define OPVAL_DIRTY_ROBJ 1
1188 #define OPVAL_DIRTY_LL 2
1189 #define OPVAL_VALID_LL 4
1190 
1191 /* Store value retrieved from the iterator. */
1192 typedef struct {
1193     int flags;
1194     unsigned char _buf[32]; /* Private buffer. */
1195     robj *ele;
1196     unsigned char *estr;
1197     unsigned int elen;
1198     long long ell;
1199     double score;
1200 } zsetopval;
1201 
1202 typedef union _iterset iterset;
1203 typedef union _iterzset iterzset;
1204 
1205 void zuiInitIterator(zsetopsrc *op) {
1206     if (op->subject == NULL)
1207         return;
1208 
1209     if (op->type == REDIS_SET) {
1210         iterset *it = &op->iter.set;
1211         if (op->encoding == REDIS_ENCODING_INTSET) {
1212             it->is.is = op->subject->ptr;
1213             it->is.ii = 0;
1214         } else if (op->encoding == REDIS_ENCODING_HT) {
1215             it->ht.dict = op->subject->ptr;
1216             it->ht.di = dictGetIterator(op->subject->ptr);
1217             it->ht.de = dictNext(it->ht.di);
1218         } else {
1219             redisPanic("Unknown set encoding");
1220         }
1221     } else if (op->type == REDIS_ZSET) {
1222         iterzset *it = &op->iter.zset;
1223         if (op->encoding == REDIS_ENCODING_ZIPLIST) {
1224             it->zl.zl = op->subject->ptr;
1225             it->zl.eptr = ziplistIndex(it->zl.zl,0);
1226             if (it->zl.eptr != NULL) {
1227                 it->zl.sptr = ziplistNext(it->zl.zl,it->zl.eptr);
1228                 redisAssert(it->zl.sptr != NULL);
1229             }
1230         } else if (op->encoding == REDIS_ENCODING_SKIPLIST) {
1231             it->sl.zs = op->subject->ptr;
1232             it->sl.node = it->sl.zs->zsl->header->level[0].forward;
1233         } else {
1234             redisPanic("Unknown sorted set encoding");
1235         }
1236     } else {
1237         redisPanic("Unsupported type");
1238     }
1239 }
1240 
1241 void zuiClearIterator(zsetopsrc *op) {
1242     if (op->subject == NULL)
1243         return;
1244 
1245     if (op->type == REDIS_SET) {
1246         iterset *it = &op->iter.set;
1247         if (op->encoding == REDIS_ENCODING_INTSET) {
1248             REDIS_NOTUSED(it); /* skip */
1249         } else if (op->encoding == REDIS_ENCODING_HT) {
1250             dictReleaseIterator(it->ht.di);
1251         } else {
1252             redisPanic("Unknown set encoding");
1253         }
1254     } else if (op->type == REDIS_ZSET) {
1255         iterzset *it = &op->iter.zset;
1256         if (op->encoding == REDIS_ENCODING_ZIPLIST) {
1257             REDIS_NOTUSED(it); /* skip */
1258         } else if (op->encoding == REDIS_ENCODING_SKIPLIST) {
1259             REDIS_NOTUSED(it); /* skip */
1260         } else {
1261             redisPanic("Unknown sorted set encoding");
1262         }
1263     } else {
1264         redisPanic("Unsupported type");
1265     }
1266 }
1267 
1268 int zuiLength(zsetopsrc *op) {
1269     if (op->subject == NULL)
1270         return 0;
1271 
1272     if (op->type == REDIS_SET) {
1273         if (op->encoding == REDIS_ENCODING_INTSET) {
1274             return intsetLen(op->subject->ptr);
1275         } else if (op->encoding == REDIS_ENCODING_HT) {
1276             dict *ht = op->subject->ptr;
1277             return dictSize(ht);
1278         } else {
1279             redisPanic("Unknown set encoding");
1280         }
1281     } else if (op->type == REDIS_ZSET) {
1282         if (op->encoding == REDIS_ENCODING_ZIPLIST) {
1283             return zzlLength(op->subject->ptr);
1284         } else if (op->encoding == REDIS_ENCODING_SKIPLIST) {
1285             zset *zs = op->subject->ptr;
1286             return zs->zsl->length;
1287         } else {
1288             redisPanic("Unknown sorted set encoding");
1289         }
1290     } else {
1291         redisPanic("Unsupported type");
1292     }
1293 }
1294 
1295 /* Check if the current value is valid. If so, store it in the passed structure
1296  * and move to the next element. If not valid, this means we have reached the
1297  * end of the structure and can abort. */
1298 int zuiNext(zsetopsrc *op, zsetopval *val) {
1299     if (op->subject == NULL)
1300         return 0;
1301 
1302     if (val->flags & OPVAL_DIRTY_ROBJ)
1303         decrRefCount(val->ele);
1304 
1305     memset(val,0,sizeof(zsetopval));
1306 
1307     if (op->type == REDIS_SET) {
1308         iterset *it = &op->iter.set;
1309         if (op->encoding == REDIS_ENCODING_INTSET) {
1310             int64_t ell;
1311 
1312             if (!intsetGet(it->is.is,it->is.ii,&ell))
1313                 return 0;
1314             val->ell = ell;
1315             val->score = 1.0;
1316 
1317             /* Move to next element. */
1318             it->is.ii++;
1319         } else if (op->encoding == REDIS_ENCODING_HT) {
1320             if (it->ht.de == NULL)
1321                 return 0;
1322             val->ele = dictGetKey(it->ht.de);
1323             val->score = 1.0;
1324 
1325             /* Move to next element. */
1326             it->ht.de = dictNext(it->ht.di);
1327         } else {
1328             redisPanic("Unknown set encoding");
1329         }
1330     } else if (op->type == REDIS_ZSET) {
1331         iterzset *it = &op->iter.zset;
1332         if (op->encoding == REDIS_ENCODING_ZIPLIST) {
1333             /* No need to check both, but better be explicit. */
1334             if (it->zl.eptr == NULL || it->zl.sptr == NULL)
1335                 return 0;
1336             redisAssert(ziplistGet(it->zl.eptr,&val->estr,&val->elen,&val->ell));
1337             val->score = zzlGetScore(it->zl.sptr);
1338 
1339             /* Move to next element. */
1340             zzlNext(it->zl.zl,&it->zl.eptr,&it->zl.sptr);
1341         } else if (op->encoding == REDIS_ENCODING_SKIPLIST) {
1342             if (it->sl.node == NULL)
1343                 return 0;
1344             val->ele = it->sl.node->obj;
1345             val->score = it->sl.node->score;
1346 
1347             /* Move to next element. */
1348             it->sl.node = it->sl.node->level[0].forward;
1349         } else {
1350             redisPanic("Unknown sorted set encoding");
1351         }
1352     } else {
1353         redisPanic("Unsupported type");
1354     }
1355     return 1;
1356 }
1357 
1358 int zuiLongLongFromValue(zsetopval *val) {
1359     if (!(val->flags & OPVAL_DIRTY_LL)) {
1360         val->flags |= OPVAL_DIRTY_LL;
1361 
1362         if (val->ele != NULL) {
1363             if (val->ele->encoding == REDIS_ENCODING_INT) {
1364                 val->ell = (long)val->ele->ptr;
1365                 val->flags |= OPVAL_VALID_LL;
1366             } else if (sdsEncodedObject(val->ele)) {
1367                 if (string2ll(val->ele->ptr,sdslen(val->ele->ptr),&val->ell))
1368                     val->flags |= OPVAL_VALID_LL;
1369             } else {
1370                 redisPanic("Unsupported element encoding");
1371             }
1372         } else if (val->estr != NULL) {
1373             if (string2ll((char*)val->estr,val->elen,&val->ell))
1374                 val->flags |= OPVAL_VALID_LL;
1375         } else {
1376             /* The long long was already set, flag as valid. */
1377             val->flags |= OPVAL_VALID_LL;
1378         }
1379     }
1380     return val->flags & OPVAL_VALID_LL;
1381 }
1382 
1383 robj *zuiObjectFromValue(zsetopval *val) {
1384     if (val->ele == NULL) {
1385         if (val->estr != NULL) {
1386             val->ele = createStringObject((char*)val->estr,val->elen);
1387         } else {
1388             val->ele = createStringObjectFromLongLong(val->ell);
1389         }
1390         val->flags |= OPVAL_DIRTY_ROBJ;
1391     }
1392     return val->ele;
1393 }
1394 
1395 int zuiBufferFromValue(zsetopval *val) {
1396     if (val->estr == NULL) {
1397         if (val->ele != NULL) {
1398             if (val->ele->encoding == REDIS_ENCODING_INT) {
1399                 val->elen = ll2string((char*)val->_buf,sizeof(val->_buf),(long)val->ele->ptr);
1400                 val->estr = val->_buf;
1401             } else if (sdsEncodedObject(val->ele)) {
1402                 val->elen = sdslen(val->ele->ptr);
1403                 val->estr = val->ele->ptr;
1404             } else {
1405                 redisPanic("Unsupported element encoding");
1406             }
1407         } else {
1408             val->elen = ll2string((char*)val->_buf,sizeof(val->_buf),val->ell);
1409             val->estr = val->_buf;
1410         }
1411     }
1412     return 1;
1413 }
1414 
1415 /* Find value pointed to by val in the source pointer to by op. When found,
1416  * return 1 and store its score in target. Return 0 otherwise. */
1417 int zuiFind(zsetopsrc *op, zsetopval *val, double *score) {
1418     if (op->subject == NULL)
1419         return 0;
1420 
1421     if (op->type == REDIS_SET) {
1422         if (op->encoding == REDIS_ENCODING_INTSET) {
1423             if (zuiLongLongFromValue(val) &&
1424                 intsetFind(op->subject->ptr,val->ell))
1425             {
1426                 *score = 1.0;
1427                 return 1;
1428             } else {
1429                 return 0;
1430             }
1431         } else if (op->encoding == REDIS_ENCODING_HT) {
1432             dict *ht = op->subject->ptr;
1433             zuiObjectFromValue(val);
1434             if (dictFind(ht,val->ele) != NULL) {
1435                 *score = 1.0;
1436                 return 1;
1437             } else {
1438                 return 0;
1439             }
1440         } else {
1441             redisPanic("Unknown set encoding");
1442         }
1443     } else if (op->type == REDIS_ZSET) {
1444         zuiObjectFromValue(val);
1445 
1446         if (op->encoding == REDIS_ENCODING_ZIPLIST) {
1447             if (zzlFind(op->subject->ptr,val->ele,score) != NULL) {
1448                 /* Score is already set by zzlFind. */
1449                 return 1;
1450             } else {
1451                 return 0;
1452             }
1453         } else if (op->encoding == REDIS_ENCODING_SKIPLIST) {
1454             zset *zs = op->subject->ptr;
1455             dictEntry *de;
1456             if ((de = dictFind(zs->dict,val->ele)) != NULL) {
1457                 *score = *(double*)dictGetVal(de);
1458                 return 1;
1459             } else {
1460                 return 0;
1461             }
1462         } else {
1463             redisPanic("Unknown sorted set encoding");
1464         }
1465     } else {
1466         redisPanic("Unsupported type");
1467     }
1468 }
1469 
1470 int zuiCompareByCardinality(const void *s1, const void *s2) {
1471     return zuiLength((zsetopsrc*)s1) - zuiLength((zsetopsrc*)s2);
1472 }
1473 
1474 #define REDIS_AGGR_SUM 1
1475 #define REDIS_AGGR_MIN 2
1476 #define REDIS_AGGR_MAX 3
1477 #define zunionInterDictValue(_e) (dictGetVal(_e) == NULL ? 1.0 : *(double*)dictGetVal(_e))
1478 
1479 inline static void zunionInterAggregate(double *target, double val, int aggregate) {
1480     if (aggregate == REDIS_AGGR_SUM) {
1481         *target = *target + val;
1482         /* The result of adding two doubles is NaN when one variable
1483          * is +inf and the other is -inf. When these numbers are added,
1484          * we maintain the convention of the result being 0.0. */
1485         if (isnan(*target)) *target = 0.0;
1486     } else if (aggregate == REDIS_AGGR_MIN) {
1487         *target = val < *target ? val : *target;
1488     } else if (aggregate == REDIS_AGGR_MAX) {
1489         *target = val > *target ? val : *target;
1490     } else {
1491         /* safety net */
1492         redisPanic("Unknown ZUNION/INTER aggregate type");
1493     }
1494 }
1495 
1496 void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
1497     int i, j;
1498     long setnum;
1499     int aggregate = REDIS_AGGR_SUM;
1500     zsetopsrc *src;
1501     zsetopval zval;
1502     robj *tmp;
1503     unsigned int maxelelen = 0;
1504     robj *dstobj;
1505     zset *dstzset;
1506     zskiplistNode *znode;
1507     int touched = 0;
1508 
1509     /* expect setnum input keys to be given */
1510     if ((getLongFromObjectOrReply(c, c->argv[2], &setnum, NULL) != REDIS_OK))
1511         return;
1512 
1513     if (setnum < 1) {
1514         addReplyError(c,
1515             "at least 1 input key is needed for ZUNIONSTORE/ZINTERSTORE");
1516         return;
1517     }
1518 
1519     /* test if the expected number of keys would overflow */
1520     if (setnum > c->argc-3) {
1521         addReply(c,shared.syntaxerr);
1522         return;
1523     }
1524 
1525     /* read keys to be used for input */
1526     src = zcalloc(sizeof(zsetopsrc) * setnum);
1527     for (i = 0, j = 3; i < setnum; i++, j++) {
1528         robj *obj = lookupKeyWrite(c->db,c->argv[j]);
1529         if (obj != NULL) {
1530             if (obj->type != REDIS_ZSET && obj->type != REDIS_SET) {
1531                 zfree(src);
1532                 addReply(c,shared.wrongtypeerr);
1533                 return;
1534             }
1535 
1536             src[i].subject = obj;
1537             src[i].type = obj->type;
1538             src[i].encoding = obj->encoding;
1539         } else {
1540             src[i].subject = NULL;
1541         }
1542 
1543         /* Default all weights to 1. */
1544         src[i].weight = 1.0;
1545     }
1546 
1547     /* parse optional extra arguments */
1548     if (j < c->argc) {
1549         int remaining = c->argc - j;
1550 
1551         while (remaining) {
1552             if (remaining >= (setnum + 1) && !strcasecmp(c->argv[j]->ptr,"weights")) {
1553                 j++; remaining--;
1554                 for (i = 0; i < setnum; i++, j++, remaining--) {
1555                     if (getDoubleFromObjectOrReply(c,c->argv[j],&src[i].weight,
1556                             "weight value is not a float") != REDIS_OK)
1557                     {
1558                         zfree(src);
1559                         return;
1560                     }
1561                 }
1562             } else if (remaining >= 2 && !strcasecmp(c->argv[j]->ptr,"aggregate")) {
1563                 j++; remaining--;
1564                 if (!strcasecmp(c->argv[j]->ptr,"sum")) {
1565                     aggregate = REDIS_AGGR_SUM;
1566                 } else if (!strcasecmp(c->argv[j]->ptr,"min")) {
1567                     aggregate = REDIS_AGGR_MIN;
1568                 } else if (!strcasecmp(c->argv[j]->ptr,"max")) {
1569                     aggregate = REDIS_AGGR_MAX;
1570                 } else {
1571                     zfree(src);
1572                     addReply(c,shared.syntaxerr);
1573                     return;
1574                 }
1575                 j++; remaining--;
1576             } else {
1577                 zfree(src);
1578                 addReply(c,shared.syntaxerr);
1579                 return;
1580             }
1581         }
1582     }
1583 
1584     /* sort sets from the smallest to largest, this will improve our
1585      * algorithm's performance */
1586     qsort(src,setnum,sizeof(zsetopsrc),zuiCompareByCardinality);
1587 
1588     dstobj = createZsetObject();
1589     dstzset = dstobj->ptr;
1590     memset(&zval, 0, sizeof(zval));
1591 
1592     if (op == REDIS_OP_INTER) {
1593         /* Skip everything if the smallest input is empty. */
1594         if (zuiLength(&src[0]) > 0) {
1595             /* Precondition: as src[0] is non-empty and the inputs are ordered
1596              * by size, all src[i > 0] are non-empty too. */
1597             zuiInitIterator(&src[0]);
1598             while (zuiNext(&src[0],&zval)) {
1599                 double score, value;
1600 
1601                 score = src[0].weight * zval.score;
1602                 if (isnan(score)) score = 0;
1603 
1604                 for (j = 1; j < setnum; j++) {
1605                     /* It is not safe to access the zset we are
1606                      * iterating, so explicitly check for equal object. */
1607                     if (src[j].subject == src[0].subject) {
1608                         value = zval.score*src[j].weight;
1609                         zunionInterAggregate(&score,value,aggregate);
1610                     } else if (zuiFind(&src[j],&zval,&value)) {
1611                         value *= src[j].weight;
1612                         zunionInterAggregate(&score,value,aggregate);
1613                     } else {
1614                         break;
1615                     }
1616                 }
1617 
1618                 /* Only continue when present in every input. */
1619                 if (j == setnum) {
1620                     tmp = zuiObjectFromValue(&zval);
1621                     znode = zslInsert(dstzset->zsl,score,tmp);
1622                     incrRefCount(tmp); /* added to skiplist */
1623                     dictAdd(dstzset->dict,tmp,&znode->score);
1624                     incrRefCount(tmp); /* added to dictionary */
1625 
1626                     if (sdsEncodedObject(tmp)) {
1627                         if (sdslen(tmp->ptr) > maxelelen)
1628                             maxelelen = sdslen(tmp->ptr);
1629                     }
1630                 }
1631             }
1632             zuiClearIterator(&src[0]);
1633         }
1634     } else if (op == REDIS_OP_UNION) {
1635         for (i = 0; i < setnum; i++) {
1636             if (zuiLength(&src[i]) == 0)
1637                 continue;
1638 
1639             zuiInitIterator(&src[i]);
1640             while (zuiNext(&src[i],&zval)) {
1641                 double score, value;
1642 
1643                 /* Skip an element that when already processed */
1644                 if (dictFind(dstzset->dict,zuiObjectFromValue(&zval)) != NULL)
1645                     continue;
1646 
1647                 /* Initialize score */
1648                 score = src[i].weight * zval.score;
1649                 if (isnan(score)) score = 0;
1650 
1651                 /* We need to check only next sets to see if this element
1652                  * exists, since we process every element just one time so
1653                  * it can't exist in a previous set (otherwise it would be
1654                  * already processed). */
1655                 for (j = (i+1); j < setnum; j++) {
1656                     /* It is not safe to access the zset we are
1657                      * iterating, so explicitly check for equal object. */
1658                     if(src[j].subject == src[i].subject) {
1659                         value = zval.score*src[j].weight;
1660                         zunionInterAggregate(&score,value,aggregate);
1661                     } else if (zuiFind(&src[j],&zval,&value)) {
1662                         value *= src[j].weight;
1663                         zunionInterAggregate(&score,value,aggregate);
1664                     }
1665                 }
1666 
1667                 tmp = zuiObjectFromValue(&zval);
1668                 znode = zslInsert(dstzset->zsl,score,tmp);
1669                 incrRefCount(zval.ele); /* added to skiplist */
1670                 dictAdd(dstzset->dict,tmp,&znode->score);
1671                 incrRefCount(zval.ele); /* added to dictionary */
1672 
1673                 if (sdsEncodedObject(tmp)) {
1674                     if (sdslen(tmp->ptr) > maxelelen)
1675                         maxelelen = sdslen(tmp->ptr);
1676                 }
1677             }
1678             zuiClearIterator(&src[i]);
1679         }
1680     } else {
1681         redisPanic("Unknown operator");
1682     }
1683 
1684     if (dbDelete(c->db,dstkey)) {
1685         signalModifiedKey(c->db,dstkey);
1686         touched = 1;
1687         server.dirty++;
1688     }
1689     if (dstzset->zsl->length) {
1690         /* Convert to ziplist when in limits. */
1691         if (dstzset->zsl->length <= server.zset_max_ziplist_entries &&
1692             maxelelen <= server.zset_max_ziplist_value)
1693                 zsetConvert(dstobj,REDIS_ENCODING_ZIPLIST);
1694 
1695         dbAdd(c->db,dstkey,dstobj);
1696         addReplyLongLong(c,zsetLength(dstobj));
1697         if (!touched) signalModifiedKey(c->db,dstkey);
1698         notifyKeyspaceEvent(REDIS_NOTIFY_ZSET,
1699             (op == REDIS_OP_UNION) ? "zunionstore" : "zinterstore",
1700             dstkey,c->db->id);
1701         server.dirty++;
1702     } else {
1703         decrRefCount(dstobj);
1704         addReply(c,shared.czero);
1705         if (touched)
1706             notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",dstkey,c->db->id);
1707     }
1708     zfree(src);
1709 }
1710 
1711 void zunionstoreCommand(redisClient *c) {
1712     zunionInterGenericCommand(c,c->argv[1], REDIS_OP_UNION);
1713 }
1714 
1715 void zinterstoreCommand(redisClient *c) {
1716     zunionInterGenericCommand(c,c->argv[1], REDIS_OP_INTER);
1717 }
1718 
1719 void zrangeGenericCommand(redisClient *c, int reverse) {
1720     robj *key = c->argv[1];
1721     robj *zobj;
1722     int withscores = 0;
1723     long start;
1724     long end;
1725     int llen;
1726     int rangelen;
1727 
1728     if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != REDIS_OK) ||
1729         (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != REDIS_OK)) return;
1730 
1731     if (c->argc == 5 && !strcasecmp(c->argv[4]->ptr,"withscores")) {
1732         withscores = 1;
1733     } else if (c->argc >= 5) {
1734         addReply(c,shared.syntaxerr);
1735         return;
1736     }
1737 
1738     if ((zobj = lookupKeyReadOrReply(c,key,shared.emptymultibulk)) == NULL
1739          || checkType(c,zobj,REDIS_ZSET)) return;
1740 
1741     /* Sanitize indexes. */
1742     llen = zsetLength(zobj);
1743     if (start < 0) start = llen+start;
1744     if (end < 0) end = llen+end;
1745     if (start < 0) start = 0;
1746 
1747     /* Invariant: start >= 0, so this test will be true when end < 0.
1748      * The range is empty when start > end or start >= length. */
1749     if (start > end || start >= llen) {
1750         addReply(c,shared.emptymultibulk);
1751         return;
1752     }
1753     if (end >= llen) end = llen-1;
1754     rangelen = (end-start)+1;
1755 
1756     /* Return the result in form of a multi-bulk reply */
1757     addReplyMultiBulkLen(c, withscores ? (rangelen*2) : rangelen);
1758 
1759     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
1760         unsigned char *zl = zobj->ptr;
1761         unsigned char *eptr, *sptr;
1762         unsigned char *vstr;
1763         unsigned int vlen;
1764         long long vlong;
1765 
1766         if (reverse)
1767             eptr = ziplistIndex(zl,-2-(2*start));
1768         else
1769             eptr = ziplistIndex(zl,2*start);
1770 
1771         redisAssertWithInfo(c,zobj,eptr != NULL);
1772         sptr = ziplistNext(zl,eptr);
1773 
1774         while (rangelen--) {
1775             redisAssertWithInfo(c,zobj,eptr != NULL && sptr != NULL);
1776             redisAssertWithInfo(c,zobj,ziplistGet(eptr,&vstr,&vlen,&vlong));
1777             if (vstr == NULL)
1778                 addReplyBulkLongLong(c,vlong);
1779             else
1780                 addReplyBulkCBuffer(c,vstr,vlen);
1781 
1782             if (withscores)
1783                 addReplyDouble(c,zzlGetScore(sptr));
1784 
1785             if (reverse)
1786                 zzlPrev(zl,&eptr,&sptr);
1787             else
1788                 zzlNext(zl,&eptr,&sptr);
1789         }
1790 
1791     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
1792         zset *zs = zobj->ptr;
1793         zskiplist *zsl = zs->zsl;
1794         zskiplistNode *ln;
1795         robj *ele;
1796 
1797         /* Check if starting point is trivial, before doing log(N) lookup. */
1798         if (reverse) {
1799             ln = zsl->tail;
1800             if (start > 0)
1801                 ln = zslGetElementByRank(zsl,llen-start);
1802         } else {
1803             ln = zsl->header->level[0].forward;
1804             if (start > 0)
1805                 ln = zslGetElementByRank(zsl,start+1);
1806         }
1807 
1808         while(rangelen--) {
1809             redisAssertWithInfo(c,zobj,ln != NULL);
1810             ele = ln->obj;
1811             addReplyBulk(c,ele);
1812             if (withscores)
1813                 addReplyDouble(c,ln->score);
1814             ln = reverse ? ln->backward : ln->level[0].forward;
1815         }
1816     } else {
1817         redisPanic("Unknown sorted set encoding");
1818     }
1819 }
1820 
1821 void zrangeCommand(redisClient *c) {
1822     zrangeGenericCommand(c,0);
1823 }
1824 
1825 void zrevrangeCommand(redisClient *c) {
1826     zrangeGenericCommand(c,1);
1827 }
1828 
1829 /* This command implements ZRANGEBYSCORE, ZREVRANGEBYSCORE. */
1830 void genericZrangebyscoreCommand(redisClient *c, int reverse) {
1831     zrangespec range;
1832     robj *key = c->argv[1];
1833     robj *zobj;
1834     long offset = 0, limit = -1;
1835     int withscores = 0;
1836     unsigned long rangelen = 0;
1837     void *replylen = NULL;
1838     int minidx, maxidx;
1839 
1840     /* Parse the range arguments. */
1841     if (reverse) {
1842         /* Range is given as [max,min] */
1843         maxidx = 2; minidx = 3;
1844     } else {
1845         /* Range is given as [min,max] */
1846         minidx = 2; maxidx = 3;
1847     }
1848 
1849     if (zslParseRange(c->argv[minidx],c->argv[maxidx],&range) != REDIS_OK) {
1850         addReplyError(c,"min or max is not a float");
1851         return;
1852     }
1853 
1854     /* Parse optional extra arguments. Note that ZCOUNT will exactly have
1855      * 4 arguments, so we'll never enter the following code path. */
1856     if (c->argc > 4) {
1857         int remaining = c->argc - 4;
1858         int pos = 4;
1859 
1860         while (remaining) {
1861             if (remaining >= 1 && !strcasecmp(c->argv[pos]->ptr,"withscores")) {
1862                 pos++; remaining--;
1863                 withscores = 1;
1864             } else if (remaining >= 3 && !strcasecmp(c->argv[pos]->ptr,"limit")) {
1865                 if ((getLongFromObjectOrReply(c, c->argv[pos+1], &offset, NULL) != REDIS_OK) ||
1866                     (getLongFromObjectOrReply(c, c->argv[pos+2], &limit, NULL) != REDIS_OK)) return;
1867                 pos += 3; remaining -= 3;
1868             } else {
1869                 addReply(c,shared.syntaxerr);
1870                 return;
1871             }
1872         }
1873     }
1874 
1875     /* Ok, lookup the key and get the range */
1876     if ((zobj = lookupKeyReadOrReply(c,key,shared.emptymultibulk)) == NULL ||
1877         checkType(c,zobj,REDIS_ZSET)) return;
1878 
1879     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
1880         unsigned char *zl = zobj->ptr;
1881         unsigned char *eptr, *sptr;
1882         unsigned char *vstr;
1883         unsigned int vlen;
1884         long long vlong;
1885         double score;
1886 
1887         /* If reversed, get the last node in range as starting point. */
1888         if (reverse) {
1889             eptr = zzlLastInRange(zl,range);
1890         } else {
1891             eptr = zzlFirstInRange(zl,range);
1892         }
1893 
1894         /* No "first" element in the specified interval. */
1895         if (eptr == NULL) {
1896             addReply(c, shared.emptymultibulk);
1897             return;
1898         }
1899 
1900         /* Get score pointer for the first element. */
1901         redisAssertWithInfo(c,zobj,eptr != NULL);
1902         sptr = ziplistNext(zl,eptr);
1903 
1904         /* We don't know in advance how many matching elements there are in the
1905          * list, so we push this object that will represent the multi-bulk
1906          * length in the output buffer, and will "fix" it later */
1907         replylen = addDeferredMultiBulkLength(c);
1908 
1909         /* If there is an offset, just traverse the number of elements without
1910          * checking the score because that is done in the next loop. */
1911         while (eptr && offset--) {
1912             if (reverse) {
1913                 zzlPrev(zl,&eptr,&sptr);
1914             } else {
1915                 zzlNext(zl,&eptr,&sptr);
1916             }
1917         }
1918 
1919         while (eptr && limit--) {
1920             score = zzlGetScore(sptr);
1921 
1922             /* Abort when the node is no longer in range. */
1923             if (reverse) {
1924                 if (!zslValueGteMin(score,&range)) break;
1925             } else {
1926                 if (!zslValueLteMax(score,&range)) break;
1927             }
1928 
1929             /* We know the element exists, so ziplistGet should always succeed */
1930             redisAssertWithInfo(c,zobj,ziplistGet(eptr,&vstr,&vlen,&vlong));
1931 
1932             rangelen++;
1933             if (vstr == NULL) {
1934                 addReplyBulkLongLong(c,vlong);
1935             } else {
1936                 addReplyBulkCBuffer(c,vstr,vlen);
1937             }
1938 
1939             if (withscores) {
1940                 addReplyDouble(c,score);
1941             }
1942 
1943             /* Move to next node */
1944             if (reverse) {
1945                 zzlPrev(zl,&eptr,&sptr);
1946             } else {
1947                 zzlNext(zl,&eptr,&sptr);
1948             }
1949         }
1950     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
1951         zset *zs = zobj->ptr;
1952         zskiplist *zsl = zs->zsl;
1953         zskiplistNode *ln;
1954 
1955         /* If reversed, get the last node in range as starting point. */
1956         if (reverse) {
1957             ln = zslLastInRange(zsl,range);
1958         } else {
1959             ln = zslFirstInRange(zsl,range);
1960         }
1961 
1962         /* No "first" element in the specified interval. */
1963         if (ln == NULL) {
1964             addReply(c, shared.emptymultibulk);
1965             return;
1966         }
1967 
1968         /* We don't know in advance how many matching elements there are in the
1969          * list, so we push this object that will represent the multi-bulk
1970          * length in the output buffer, and will "fix" it later */
1971         replylen = addDeferredMultiBulkLength(c);
1972 
1973         /* If there is an offset, just traverse the number of elements without
1974          * checking the score because that is done in the next loop. */
1975         while (ln && offset--) {
1976             if (reverse) {
1977                 ln = ln->backward;
1978             } else {
1979                 ln = ln->level[0].forward;
1980             }
1981         }
1982 
1983         while (ln && limit--) {
1984             /* Abort when the node is no longer in range. */
1985             if (reverse) {
1986                 if (!zslValueGteMin(ln->score,&range)) break;
1987             } else {
1988                 if (!zslValueLteMax(ln->score,&range)) break;
1989             }
1990 
1991             rangelen++;
1992             addReplyBulk(c,ln->obj);
1993 
1994             if (withscores) {
1995                 addReplyDouble(c,ln->score);
1996             }
1997 
1998             /* Move to next node */
1999             if (reverse) {
2000                 ln = ln->backward;
2001             } else {
2002                 ln = ln->level[0].forward;
2003             }
2004         }
2005     } else {
2006         redisPanic("Unknown sorted set encoding");
2007     }
2008 
2009     if (withscores) {
2010         rangelen *= 2;
2011     }
2012 
2013     setDeferredMultiBulkLength(c, replylen, rangelen);
2014 }
2015 
2016 void zrangebyscoreCommand(redisClient *c) {
2017     genericZrangebyscoreCommand(c,0);
2018 }
2019 
2020 void zrevrangebyscoreCommand(redisClient *c) {
2021     genericZrangebyscoreCommand(c,1);
2022 }
2023 
2024 void zcountCommand(redisClient *c) {
2025     robj *key = c->argv[1];
2026     robj *zobj;
2027     zrangespec range;
2028     int count = 0;
2029 
2030     /* Parse the range arguments */
2031     if (zslParseRange(c->argv[2],c->argv[3],&range) != REDIS_OK) {
2032         addReplyError(c,"min or max is not a float");
2033         return;
2034     }
2035 
2036     /* Lookup the sorted set */
2037     if ((zobj = lookupKeyReadOrReply(c, key, shared.czero)) == NULL ||
2038         checkType(c, zobj, REDIS_ZSET)) return;
2039 
2040     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
2041         unsigned char *zl = zobj->ptr;
2042         unsigned char *eptr, *sptr;
2043         double score;
2044 
2045         /* Use the first element in range as the starting point */
2046         eptr = zzlFirstInRange(zl,range);
2047 
2048         /* No "first" element */
2049         if (eptr == NULL) {
2050             addReply(c, shared.czero);
2051             return;
2052         }
2053 
2054         /* First element is in range */
2055         sptr = ziplistNext(zl,eptr);
2056         score = zzlGetScore(sptr);
2057         redisAssertWithInfo(c,zobj,zslValueLteMax(score,&range));
2058 
2059         /* Iterate over elements in range */
2060         while (eptr) {
2061             score = zzlGetScore(sptr);
2062 
2063             /* Abort when the node is no longer in range. */
2064             if (!zslValueLteMax(score,&range)) {
2065                 break;
2066             } else {
2067                 count++;
2068                 zzlNext(zl,&eptr,&sptr);
2069             }
2070         }
2071     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
2072         zset *zs = zobj->ptr;
2073         zskiplist *zsl = zs->zsl;
2074         zskiplistNode *zn;
2075         unsigned long rank;
2076 
2077         /* Find first element in range */
2078         zn = zslFirstInRange(zsl, range);
2079 
2080         /* Use rank of first element, if any, to determine preliminary count */
2081         if (zn != NULL) {
2082             rank = zslGetRank(zsl, zn->score, zn->obj);
2083             count = (zsl->length - (rank - 1));
2084 
2085             /* Find last element in range */
2086             zn = zslLastInRange(zsl, range);
2087 
2088             /* Use rank of last element, if any, to determine the actual count */
2089             if (zn != NULL) {
2090                 rank = zslGetRank(zsl, zn->score, zn->obj);
2091                 count -= (zsl->length - rank);
2092             }
2093         }
2094     } else {
2095         redisPanic("Unknown sorted set encoding");
2096     }
2097 
2098     addReplyLongLong(c, count);
2099 }
2100 
2101 void zcardCommand(redisClient *c) {
2102     robj *key = c->argv[1];
2103     robj *zobj;
2104 
2105     if ((zobj = lookupKeyReadOrReply(c,key,shared.czero)) == NULL ||
2106         checkType(c,zobj,REDIS_ZSET)) return;
2107 
2108     addReplyLongLong(c,zsetLength(zobj));
2109 }
2110 
2111 void zscoreCommand(redisClient *c) {
2112     robj *key = c->argv[1];
2113     robj *zobj;
2114     double score;
2115 
2116     if ((zobj = lookupKeyReadOrReply(c,key,shared.nullbulk)) == NULL ||
2117         checkType(c,zobj,REDIS_ZSET)) return;
2118 
2119     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
2120         if (zzlFind(zobj->ptr,c->argv[2],&score) != NULL)
2121             addReplyDouble(c,score);
2122         else
2123             addReply(c,shared.nullbulk);
2124     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
2125         zset *zs = zobj->ptr;
2126         dictEntry *de;
2127 
2128         c->argv[2] = tryObjectEncoding(c->argv[2]);
2129         de = dictFind(zs->dict,c->argv[2]);
2130         if (de != NULL) {
2131             score = *(double*)dictGetVal(de);
2132             addReplyDouble(c,score);
2133         } else {
2134             addReply(c,shared.nullbulk);
2135         }
2136     } else {
2137         redisPanic("Unknown sorted set encoding");
2138     }
2139 }
2140 
2141 void zrankGenericCommand(redisClient *c, int reverse) {
2142     robj *key = c->argv[1];
2143     robj *ele = c->argv[2];
2144     robj *zobj;
2145     unsigned long llen;
2146     unsigned long rank;
2147 
2148     if ((zobj = lookupKeyReadOrReply(c,key,shared.nullbulk)) == NULL ||
2149         checkType(c,zobj,REDIS_ZSET)) return;
2150     llen = zsetLength(zobj);
2151 
2152     redisAssertWithInfo(c,ele,sdsEncodedObject(ele));
2153 
2154     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
2155         unsigned char *zl = zobj->ptr;
2156         unsigned char *eptr, *sptr;
2157 
2158         eptr = ziplistIndex(zl,0);
2159         redisAssertWithInfo(c,zobj,eptr != NULL);
2160         sptr = ziplistNext(zl,eptr);
2161         redisAssertWithInfo(c,zobj,sptr != NULL);
2162 
2163         rank = 1;
2164         while(eptr != NULL) {
2165             if (ziplistCompare(eptr,ele->ptr,sdslen(ele->ptr)))
2166                 break;
2167             rank++;
2168             zzlNext(zl,&eptr,&sptr);
2169         }
2170 
2171         if (eptr != NULL) {
2172             if (reverse)
2173                 addReplyLongLong(c,llen-rank);
2174             else
2175                 addReplyLongLong(c,rank-1);
2176         } else {
2177             addReply(c,shared.nullbulk);
2178         }
2179     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
2180         zset *zs = zobj->ptr;
2181         zskiplist *zsl = zs->zsl;
2182         dictEntry *de;
2183         double score;
2184 
2185         ele = c->argv[2] = tryObjectEncoding(c->argv[2]);
2186         de = dictFind(zs->dict,ele);
2187         if (de != NULL) {
2188             score = *(double*)dictGetVal(de);
2189             rank = zslGetRank(zsl,score,ele);
2190             redisAssertWithInfo(c,ele,rank); /* Existing elements always have a rank. */
2191             if (reverse)
2192                 addReplyLongLong(c,llen-rank);
2193             else
2194                 addReplyLongLong(c,rank-1);
2195         } else {
2196             addReply(c,shared.nullbulk);
2197         }
2198     } else {
2199         redisPanic("Unknown sorted set encoding");
2200     }
2201 }
2202 
2203 void zrankCommand(redisClient *c) {
2204     zrankGenericCommand(c, 0);
2205 }
2206 
2207 void zrevrankCommand(redisClient *c) {
2208     zrankGenericCommand(c, 1);
2209 }
2210 
2211 void zscanCommand(redisClient *c) {
2212     robj *o;
2213     unsigned long cursor;
2214 
2215     if (parseScanCursorOrReply(c,c->argv[2],&cursor) == REDIS_ERR) return;
2216     if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptyscan)) == NULL ||
2217         checkType(c,o,REDIS_ZSET)) return;
2218     scanGenericCommand(c,o,cursor);
2219 }
2220