xref: /redis-3.2.3/src/t_zset.c (revision 40f822da)
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 an 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,ele->encoding == REDIS_ENCODING_RAW);
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(incr ? "zincr" : "zadd", key, c->db->id);
972     }
973 }
974 
975 void zaddCommand(redisClient *c) {
976     zaddGenericCommand(c,0);
977 }
978 
979 void zincrbyCommand(redisClient *c) {
980     zaddGenericCommand(c,1);
981 }
982 
983 void zremCommand(redisClient *c) {
984     robj *key = c->argv[1];
985     robj *zobj;
986     int deleted = 0, keyremoved = 0, j;
987 
988     if ((zobj = lookupKeyWriteOrReply(c,key,shared.czero)) == NULL ||
989         checkType(c,zobj,REDIS_ZSET)) return;
990 
991     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
992         unsigned char *eptr;
993 
994         for (j = 2; j < c->argc; j++) {
995             if ((eptr = zzlFind(zobj->ptr,c->argv[j],NULL)) != NULL) {
996                 deleted++;
997                 zobj->ptr = zzlDelete(zobj->ptr,eptr);
998                 if (zzlLength(zobj->ptr) == 0) {
999                     dbDelete(c->db,key);
1000                     break;
1001                 }
1002             }
1003         }
1004     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
1005         zset *zs = zobj->ptr;
1006         dictEntry *de;
1007         double score;
1008 
1009         for (j = 2; j < c->argc; j++) {
1010             de = dictFind(zs->dict,c->argv[j]);
1011             if (de != NULL) {
1012                 deleted++;
1013 
1014                 /* Delete from the skiplist */
1015                 score = *(double*)dictGetVal(de);
1016                 redisAssertWithInfo(c,c->argv[j],zslDelete(zs->zsl,score,c->argv[j]));
1017 
1018                 /* Delete from the hash table */
1019                 dictDelete(zs->dict,c->argv[j]);
1020                 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
1021                 if (dictSize(zs->dict) == 0) {
1022                     dbDelete(c->db,key);
1023                     break;
1024                 }
1025             }
1026         }
1027     } else {
1028         redisPanic("Unknown sorted set encoding");
1029     }
1030 
1031     if (deleted) {
1032         notifyKeyspaceEvent("zrem",key,c->db->id);
1033         if (keyremoved) notifyKeyspaceEvent("del",key,c->db->id);
1034         signalModifiedKey(c->db,key);
1035         server.dirty += deleted;
1036     }
1037     addReplyLongLong(c,deleted);
1038 }
1039 
1040 void zremrangebyscoreCommand(redisClient *c) {
1041     robj *key = c->argv[1];
1042     robj *zobj;
1043     zrangespec range;
1044     int keyremoved = 0;
1045     unsigned long deleted;
1046 
1047     /* Parse the range arguments. */
1048     if (zslParseRange(c->argv[2],c->argv[3],&range) != REDIS_OK) {
1049         addReplyError(c,"min or max is not a float");
1050         return;
1051     }
1052 
1053     if ((zobj = lookupKeyWriteOrReply(c,key,shared.czero)) == NULL ||
1054         checkType(c,zobj,REDIS_ZSET)) return;
1055 
1056     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
1057         zobj->ptr = zzlDeleteRangeByScore(zobj->ptr,range,&deleted);
1058         if (zzlLength(zobj->ptr) == 0) {
1059             dbDelete(c->db,key);
1060             keyremoved = 1;
1061         }
1062     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
1063         zset *zs = zobj->ptr;
1064         deleted = zslDeleteRangeByScore(zs->zsl,range,zs->dict);
1065         if (htNeedsResize(zs->dict)) dictResize(zs->dict);
1066         if (dictSize(zs->dict) == 0) {
1067             dbDelete(c->db,key);
1068             keyremoved = 1;
1069         }
1070     } else {
1071         redisPanic("Unknown sorted set encoding");
1072     }
1073 
1074     if (deleted) {
1075         signalModifiedKey(c->db,key);
1076         notifyKeyspaceEvent("zrembyscore",key,c->db->id);
1077         if (keyremoved) notifyKeyspaceEvent("del",key,c->db->id);
1078     }
1079     server.dirty += deleted;
1080     addReplyLongLong(c,deleted);
1081 }
1082 
1083 void zremrangebyrankCommand(redisClient *c) {
1084     robj *key = c->argv[1];
1085     robj *zobj;
1086     long start;
1087     long end;
1088     int llen;
1089     unsigned long deleted;
1090     int keyremoved = 0;
1091 
1092     if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != REDIS_OK) ||
1093         (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != REDIS_OK)) return;
1094 
1095     if ((zobj = lookupKeyWriteOrReply(c,key,shared.czero)) == NULL ||
1096         checkType(c,zobj,REDIS_ZSET)) return;
1097 
1098     /* Sanitize indexes. */
1099     llen = zsetLength(zobj);
1100     if (start < 0) start = llen+start;
1101     if (end < 0) end = llen+end;
1102     if (start < 0) start = 0;
1103 
1104     /* Invariant: start >= 0, so this test will be true when end < 0.
1105      * The range is empty when start > end or start >= length. */
1106     if (start > end || start >= llen) {
1107         addReply(c,shared.czero);
1108         return;
1109     }
1110     if (end >= llen) end = llen-1;
1111 
1112     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
1113         /* Correct for 1-based rank. */
1114         zobj->ptr = zzlDeleteRangeByRank(zobj->ptr,start+1,end+1,&deleted);
1115         if (zzlLength(zobj->ptr) == 0) {
1116             dbDelete(c->db,key);
1117             keyremoved = 1;
1118         }
1119     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
1120         zset *zs = zobj->ptr;
1121 
1122         /* Correct for 1-based rank. */
1123         deleted = zslDeleteRangeByRank(zs->zsl,start+1,end+1,zs->dict);
1124         if (htNeedsResize(zs->dict)) dictResize(zs->dict);
1125         if (dictSize(zs->dict) == 0) {
1126             dbDelete(c->db,key);
1127             keyremoved = 1;
1128         }
1129     } else {
1130         redisPanic("Unknown sorted set encoding");
1131     }
1132 
1133     if (deleted) {
1134         signalModifiedKey(c->db,key);
1135         notifyKeyspaceEvent("zrembyrank",key,c->db->id);
1136         if (keyremoved) notifyKeyspaceEvent("del",key,c->db->id);
1137     }
1138     server.dirty += deleted;
1139     addReplyLongLong(c,deleted);
1140 }
1141 
1142 typedef struct {
1143     robj *subject;
1144     int type; /* Set, sorted set */
1145     int encoding;
1146     double weight;
1147 
1148     union {
1149         /* Set iterators. */
1150         union _iterset {
1151             struct {
1152                 intset *is;
1153                 int ii;
1154             } is;
1155             struct {
1156                 dict *dict;
1157                 dictIterator *di;
1158                 dictEntry *de;
1159             } ht;
1160         } set;
1161 
1162         /* Sorted set iterators. */
1163         union _iterzset {
1164             struct {
1165                 unsigned char *zl;
1166                 unsigned char *eptr, *sptr;
1167             } zl;
1168             struct {
1169                 zset *zs;
1170                 zskiplistNode *node;
1171             } sl;
1172         } zset;
1173     } iter;
1174 } zsetopsrc;
1175 
1176 
1177 /* Use dirty flags for pointers that need to be cleaned up in the next
1178  * iteration over the zsetopval. The dirty flag for the long long value is
1179  * special, since long long values don't need cleanup. Instead, it means that
1180  * we already checked that "ell" holds a long long, or tried to convert another
1181  * representation into a long long value. When this was successful,
1182  * OPVAL_VALID_LL is set as well. */
1183 #define OPVAL_DIRTY_ROBJ 1
1184 #define OPVAL_DIRTY_LL 2
1185 #define OPVAL_VALID_LL 4
1186 
1187 /* Store value retrieved from the iterator. */
1188 typedef struct {
1189     int flags;
1190     unsigned char _buf[32]; /* Private buffer. */
1191     robj *ele;
1192     unsigned char *estr;
1193     unsigned int elen;
1194     long long ell;
1195     double score;
1196 } zsetopval;
1197 
1198 typedef union _iterset iterset;
1199 typedef union _iterzset iterzset;
1200 
1201 void zuiInitIterator(zsetopsrc *op) {
1202     if (op->subject == NULL)
1203         return;
1204 
1205     if (op->type == REDIS_SET) {
1206         iterset *it = &op->iter.set;
1207         if (op->encoding == REDIS_ENCODING_INTSET) {
1208             it->is.is = op->subject->ptr;
1209             it->is.ii = 0;
1210         } else if (op->encoding == REDIS_ENCODING_HT) {
1211             it->ht.dict = op->subject->ptr;
1212             it->ht.di = dictGetIterator(op->subject->ptr);
1213             it->ht.de = dictNext(it->ht.di);
1214         } else {
1215             redisPanic("Unknown set encoding");
1216         }
1217     } else if (op->type == REDIS_ZSET) {
1218         iterzset *it = &op->iter.zset;
1219         if (op->encoding == REDIS_ENCODING_ZIPLIST) {
1220             it->zl.zl = op->subject->ptr;
1221             it->zl.eptr = ziplistIndex(it->zl.zl,0);
1222             if (it->zl.eptr != NULL) {
1223                 it->zl.sptr = ziplistNext(it->zl.zl,it->zl.eptr);
1224                 redisAssert(it->zl.sptr != NULL);
1225             }
1226         } else if (op->encoding == REDIS_ENCODING_SKIPLIST) {
1227             it->sl.zs = op->subject->ptr;
1228             it->sl.node = it->sl.zs->zsl->header->level[0].forward;
1229         } else {
1230             redisPanic("Unknown sorted set encoding");
1231         }
1232     } else {
1233         redisPanic("Unsupported type");
1234     }
1235 }
1236 
1237 void zuiClearIterator(zsetopsrc *op) {
1238     if (op->subject == NULL)
1239         return;
1240 
1241     if (op->type == REDIS_SET) {
1242         iterset *it = &op->iter.set;
1243         if (op->encoding == REDIS_ENCODING_INTSET) {
1244             REDIS_NOTUSED(it); /* skip */
1245         } else if (op->encoding == REDIS_ENCODING_HT) {
1246             dictReleaseIterator(it->ht.di);
1247         } else {
1248             redisPanic("Unknown set encoding");
1249         }
1250     } else if (op->type == REDIS_ZSET) {
1251         iterzset *it = &op->iter.zset;
1252         if (op->encoding == REDIS_ENCODING_ZIPLIST) {
1253             REDIS_NOTUSED(it); /* skip */
1254         } else if (op->encoding == REDIS_ENCODING_SKIPLIST) {
1255             REDIS_NOTUSED(it); /* skip */
1256         } else {
1257             redisPanic("Unknown sorted set encoding");
1258         }
1259     } else {
1260         redisPanic("Unsupported type");
1261     }
1262 }
1263 
1264 int zuiLength(zsetopsrc *op) {
1265     if (op->subject == NULL)
1266         return 0;
1267 
1268     if (op->type == REDIS_SET) {
1269         iterset *it = &op->iter.set;
1270         if (op->encoding == REDIS_ENCODING_INTSET) {
1271             return intsetLen(it->is.is);
1272         } else if (op->encoding == REDIS_ENCODING_HT) {
1273             return dictSize(it->ht.dict);
1274         } else {
1275             redisPanic("Unknown set encoding");
1276         }
1277     } else if (op->type == REDIS_ZSET) {
1278         iterzset *it = &op->iter.zset;
1279         if (op->encoding == REDIS_ENCODING_ZIPLIST) {
1280             return zzlLength(it->zl.zl);
1281         } else if (op->encoding == REDIS_ENCODING_SKIPLIST) {
1282             return it->sl.zs->zsl->length;
1283         } else {
1284             redisPanic("Unknown sorted set encoding");
1285         }
1286     } else {
1287         redisPanic("Unsupported type");
1288     }
1289 }
1290 
1291 /* Check if the current value is valid. If so, store it in the passed structure
1292  * and move to the next element. If not valid, this means we have reached the
1293  * end of the structure and can abort. */
1294 int zuiNext(zsetopsrc *op, zsetopval *val) {
1295     if (op->subject == NULL)
1296         return 0;
1297 
1298     if (val->flags & OPVAL_DIRTY_ROBJ)
1299         decrRefCount(val->ele);
1300 
1301     memset(val,0,sizeof(zsetopval));
1302 
1303     if (op->type == REDIS_SET) {
1304         iterset *it = &op->iter.set;
1305         if (op->encoding == REDIS_ENCODING_INTSET) {
1306             int64_t ell;
1307 
1308             if (!intsetGet(it->is.is,it->is.ii,&ell))
1309                 return 0;
1310             val->ell = ell;
1311             val->score = 1.0;
1312 
1313             /* Move to next element. */
1314             it->is.ii++;
1315         } else if (op->encoding == REDIS_ENCODING_HT) {
1316             if (it->ht.de == NULL)
1317                 return 0;
1318             val->ele = dictGetKey(it->ht.de);
1319             val->score = 1.0;
1320 
1321             /* Move to next element. */
1322             it->ht.de = dictNext(it->ht.di);
1323         } else {
1324             redisPanic("Unknown set encoding");
1325         }
1326     } else if (op->type == REDIS_ZSET) {
1327         iterzset *it = &op->iter.zset;
1328         if (op->encoding == REDIS_ENCODING_ZIPLIST) {
1329             /* No need to check both, but better be explicit. */
1330             if (it->zl.eptr == NULL || it->zl.sptr == NULL)
1331                 return 0;
1332             redisAssert(ziplistGet(it->zl.eptr,&val->estr,&val->elen,&val->ell));
1333             val->score = zzlGetScore(it->zl.sptr);
1334 
1335             /* Move to next element. */
1336             zzlNext(it->zl.zl,&it->zl.eptr,&it->zl.sptr);
1337         } else if (op->encoding == REDIS_ENCODING_SKIPLIST) {
1338             if (it->sl.node == NULL)
1339                 return 0;
1340             val->ele = it->sl.node->obj;
1341             val->score = it->sl.node->score;
1342 
1343             /* Move to next element. */
1344             it->sl.node = it->sl.node->level[0].forward;
1345         } else {
1346             redisPanic("Unknown sorted set encoding");
1347         }
1348     } else {
1349         redisPanic("Unsupported type");
1350     }
1351     return 1;
1352 }
1353 
1354 int zuiLongLongFromValue(zsetopval *val) {
1355     if (!(val->flags & OPVAL_DIRTY_LL)) {
1356         val->flags |= OPVAL_DIRTY_LL;
1357 
1358         if (val->ele != NULL) {
1359             if (val->ele->encoding == REDIS_ENCODING_INT) {
1360                 val->ell = (long)val->ele->ptr;
1361                 val->flags |= OPVAL_VALID_LL;
1362             } else if (val->ele->encoding == REDIS_ENCODING_RAW) {
1363                 if (string2ll(val->ele->ptr,sdslen(val->ele->ptr),&val->ell))
1364                     val->flags |= OPVAL_VALID_LL;
1365             } else {
1366                 redisPanic("Unsupported element encoding");
1367             }
1368         } else if (val->estr != NULL) {
1369             if (string2ll((char*)val->estr,val->elen,&val->ell))
1370                 val->flags |= OPVAL_VALID_LL;
1371         } else {
1372             /* The long long was already set, flag as valid. */
1373             val->flags |= OPVAL_VALID_LL;
1374         }
1375     }
1376     return val->flags & OPVAL_VALID_LL;
1377 }
1378 
1379 robj *zuiObjectFromValue(zsetopval *val) {
1380     if (val->ele == NULL) {
1381         if (val->estr != NULL) {
1382             val->ele = createStringObject((char*)val->estr,val->elen);
1383         } else {
1384             val->ele = createStringObjectFromLongLong(val->ell);
1385         }
1386         val->flags |= OPVAL_DIRTY_ROBJ;
1387     }
1388     return val->ele;
1389 }
1390 
1391 int zuiBufferFromValue(zsetopval *val) {
1392     if (val->estr == NULL) {
1393         if (val->ele != NULL) {
1394             if (val->ele->encoding == REDIS_ENCODING_INT) {
1395                 val->elen = ll2string((char*)val->_buf,sizeof(val->_buf),(long)val->ele->ptr);
1396                 val->estr = val->_buf;
1397             } else if (val->ele->encoding == REDIS_ENCODING_RAW) {
1398                 val->elen = sdslen(val->ele->ptr);
1399                 val->estr = val->ele->ptr;
1400             } else {
1401                 redisPanic("Unsupported element encoding");
1402             }
1403         } else {
1404             val->elen = ll2string((char*)val->_buf,sizeof(val->_buf),val->ell);
1405             val->estr = val->_buf;
1406         }
1407     }
1408     return 1;
1409 }
1410 
1411 /* Find value pointed to by val in the source pointer to by op. When found,
1412  * return 1 and store its score in target. Return 0 otherwise. */
1413 int zuiFind(zsetopsrc *op, zsetopval *val, double *score) {
1414     if (op->subject == NULL)
1415         return 0;
1416 
1417     if (op->type == REDIS_SET) {
1418         iterset *it = &op->iter.set;
1419 
1420         if (op->encoding == REDIS_ENCODING_INTSET) {
1421             if (zuiLongLongFromValue(val) && intsetFind(it->is.is,val->ell)) {
1422                 *score = 1.0;
1423                 return 1;
1424             } else {
1425                 return 0;
1426             }
1427         } else if (op->encoding == REDIS_ENCODING_HT) {
1428             zuiObjectFromValue(val);
1429             if (dictFind(it->ht.dict,val->ele) != NULL) {
1430                 *score = 1.0;
1431                 return 1;
1432             } else {
1433                 return 0;
1434             }
1435         } else {
1436             redisPanic("Unknown set encoding");
1437         }
1438     } else if (op->type == REDIS_ZSET) {
1439         iterzset *it = &op->iter.zset;
1440         zuiObjectFromValue(val);
1441 
1442         if (op->encoding == REDIS_ENCODING_ZIPLIST) {
1443             if (zzlFind(it->zl.zl,val->ele,score) != NULL) {
1444                 /* Score is already set by zzlFind. */
1445                 return 1;
1446             } else {
1447                 return 0;
1448             }
1449         } else if (op->encoding == REDIS_ENCODING_SKIPLIST) {
1450             dictEntry *de;
1451             if ((de = dictFind(it->sl.zs->dict,val->ele)) != NULL) {
1452                 *score = *(double*)dictGetVal(de);
1453                 return 1;
1454             } else {
1455                 return 0;
1456             }
1457         } else {
1458             redisPanic("Unknown sorted set encoding");
1459         }
1460     } else {
1461         redisPanic("Unsupported type");
1462     }
1463 }
1464 
1465 int zuiCompareByCardinality(const void *s1, const void *s2) {
1466     return zuiLength((zsetopsrc*)s1) - zuiLength((zsetopsrc*)s2);
1467 }
1468 
1469 #define REDIS_AGGR_SUM 1
1470 #define REDIS_AGGR_MIN 2
1471 #define REDIS_AGGR_MAX 3
1472 #define zunionInterDictValue(_e) (dictGetVal(_e) == NULL ? 1.0 : *(double*)dictGetVal(_e))
1473 
1474 inline static void zunionInterAggregate(double *target, double val, int aggregate) {
1475     if (aggregate == REDIS_AGGR_SUM) {
1476         *target = *target + val;
1477         /* The result of adding two doubles is NaN when one variable
1478          * is +inf and the other is -inf. When these numbers are added,
1479          * we maintain the convention of the result being 0.0. */
1480         if (isnan(*target)) *target = 0.0;
1481     } else if (aggregate == REDIS_AGGR_MIN) {
1482         *target = val < *target ? val : *target;
1483     } else if (aggregate == REDIS_AGGR_MAX) {
1484         *target = val > *target ? val : *target;
1485     } else {
1486         /* safety net */
1487         redisPanic("Unknown ZUNION/INTER aggregate type");
1488     }
1489 }
1490 
1491 void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
1492     int i, j;
1493     long setnum;
1494     int aggregate = REDIS_AGGR_SUM;
1495     zsetopsrc *src;
1496     zsetopval zval;
1497     robj *tmp;
1498     unsigned int maxelelen = 0;
1499     robj *dstobj;
1500     zset *dstzset;
1501     zskiplistNode *znode;
1502     int touched = 0;
1503 
1504     /* expect setnum input keys to be given */
1505     if ((getLongFromObjectOrReply(c, c->argv[2], &setnum, NULL) != REDIS_OK))
1506         return;
1507 
1508     if (setnum < 1) {
1509         addReplyError(c,
1510             "at least 1 input key is needed for ZUNIONSTORE/ZINTERSTORE");
1511         return;
1512     }
1513 
1514     /* test if the expected number of keys would overflow */
1515     if (setnum > c->argc-3) {
1516         addReply(c,shared.syntaxerr);
1517         return;
1518     }
1519 
1520     /* read keys to be used for input */
1521     src = zcalloc(sizeof(zsetopsrc) * setnum);
1522     for (i = 0, j = 3; i < setnum; i++, j++) {
1523         robj *obj = lookupKeyWrite(c->db,c->argv[j]);
1524         if (obj != NULL) {
1525             if (obj->type != REDIS_ZSET && obj->type != REDIS_SET) {
1526                 zfree(src);
1527                 addReply(c,shared.wrongtypeerr);
1528                 return;
1529             }
1530 
1531             src[i].subject = obj;
1532             src[i].type = obj->type;
1533             src[i].encoding = obj->encoding;
1534         } else {
1535             src[i].subject = NULL;
1536         }
1537 
1538         /* Default all weights to 1. */
1539         src[i].weight = 1.0;
1540     }
1541 
1542     /* parse optional extra arguments */
1543     if (j < c->argc) {
1544         int remaining = c->argc - j;
1545 
1546         while (remaining) {
1547             if (remaining >= (setnum + 1) && !strcasecmp(c->argv[j]->ptr,"weights")) {
1548                 j++; remaining--;
1549                 for (i = 0; i < setnum; i++, j++, remaining--) {
1550                     if (getDoubleFromObjectOrReply(c,c->argv[j],&src[i].weight,
1551                             "weight value is not a float") != REDIS_OK)
1552                     {
1553                         zfree(src);
1554                         return;
1555                     }
1556                 }
1557             } else if (remaining >= 2 && !strcasecmp(c->argv[j]->ptr,"aggregate")) {
1558                 j++; remaining--;
1559                 if (!strcasecmp(c->argv[j]->ptr,"sum")) {
1560                     aggregate = REDIS_AGGR_SUM;
1561                 } else if (!strcasecmp(c->argv[j]->ptr,"min")) {
1562                     aggregate = REDIS_AGGR_MIN;
1563                 } else if (!strcasecmp(c->argv[j]->ptr,"max")) {
1564                     aggregate = REDIS_AGGR_MAX;
1565                 } else {
1566                     zfree(src);
1567                     addReply(c,shared.syntaxerr);
1568                     return;
1569                 }
1570                 j++; remaining--;
1571             } else {
1572                 zfree(src);
1573                 addReply(c,shared.syntaxerr);
1574                 return;
1575             }
1576         }
1577     }
1578 
1579     for (i = 0; i < setnum; i++)
1580         zuiInitIterator(&src[i]);
1581 
1582     /* sort sets from the smallest to largest, this will improve our
1583      * algorithm's performance */
1584     qsort(src,setnum,sizeof(zsetopsrc),zuiCompareByCardinality);
1585 
1586     dstobj = createZsetObject();
1587     dstzset = dstobj->ptr;
1588     memset(&zval, 0, sizeof(zval));
1589 
1590     if (op == REDIS_OP_INTER) {
1591         /* Skip everything if the smallest input is empty. */
1592         if (zuiLength(&src[0]) > 0) {
1593             /* Precondition: as src[0] is non-empty and the inputs are ordered
1594              * by size, all src[i > 0] are non-empty too. */
1595             while (zuiNext(&src[0],&zval)) {
1596                 double score, value;
1597 
1598                 score = src[0].weight * zval.score;
1599                 if (isnan(score)) score = 0;
1600 
1601                 for (j = 1; j < setnum; j++) {
1602                     /* It is not safe to access the zset we are
1603                      * iterating, so explicitly check for equal object. */
1604                     if (src[j].subject == src[0].subject) {
1605                         value = zval.score*src[j].weight;
1606                         zunionInterAggregate(&score,value,aggregate);
1607                     } else if (zuiFind(&src[j],&zval,&value)) {
1608                         value *= src[j].weight;
1609                         zunionInterAggregate(&score,value,aggregate);
1610                     } else {
1611                         break;
1612                     }
1613                 }
1614 
1615                 /* Only continue when present in every input. */
1616                 if (j == setnum) {
1617                     tmp = zuiObjectFromValue(&zval);
1618                     znode = zslInsert(dstzset->zsl,score,tmp);
1619                     incrRefCount(tmp); /* added to skiplist */
1620                     dictAdd(dstzset->dict,tmp,&znode->score);
1621                     incrRefCount(tmp); /* added to dictionary */
1622 
1623                     if (tmp->encoding == REDIS_ENCODING_RAW)
1624                         if (sdslen(tmp->ptr) > maxelelen)
1625                             maxelelen = sdslen(tmp->ptr);
1626                 }
1627             }
1628         }
1629     } else if (op == REDIS_OP_UNION) {
1630         for (i = 0; i < setnum; i++) {
1631             if (zuiLength(&src[i]) == 0)
1632                 continue;
1633 
1634             while (zuiNext(&src[i],&zval)) {
1635                 double score, value;
1636 
1637                 /* Skip key when already processed */
1638                 if (dictFind(dstzset->dict,zuiObjectFromValue(&zval)) != NULL)
1639                     continue;
1640 
1641                 /* Initialize score */
1642                 score = src[i].weight * zval.score;
1643                 if (isnan(score)) score = 0;
1644 
1645                 /* Because the inputs are sorted by size, it's only possible
1646                  * for sets at larger indices to hold this element. */
1647                 for (j = (i+1); j < setnum; j++) {
1648                     /* It is not safe to access the zset we are
1649                      * iterating, so explicitly check for equal object. */
1650                     if(src[j].subject == src[i].subject) {
1651                         value = zval.score*src[j].weight;
1652                         zunionInterAggregate(&score,value,aggregate);
1653                     } else if (zuiFind(&src[j],&zval,&value)) {
1654                         value *= src[j].weight;
1655                         zunionInterAggregate(&score,value,aggregate);
1656                     }
1657                 }
1658 
1659                 tmp = zuiObjectFromValue(&zval);
1660                 znode = zslInsert(dstzset->zsl,score,tmp);
1661                 incrRefCount(zval.ele); /* added to skiplist */
1662                 dictAdd(dstzset->dict,tmp,&znode->score);
1663                 incrRefCount(zval.ele); /* added to dictionary */
1664 
1665                 if (tmp->encoding == REDIS_ENCODING_RAW)
1666                     if (sdslen(tmp->ptr) > maxelelen)
1667                         maxelelen = sdslen(tmp->ptr);
1668             }
1669         }
1670     } else {
1671         redisPanic("Unknown operator");
1672     }
1673 
1674     for (i = 0; i < setnum; i++)
1675         zuiClearIterator(&src[i]);
1676 
1677     if (dbDelete(c->db,dstkey)) {
1678         signalModifiedKey(c->db,dstkey);
1679         notifyKeyspaceEvent("del",dstkey,c->db->id);
1680         touched = 1;
1681         server.dirty++;
1682     }
1683     if (dstzset->zsl->length) {
1684         /* Convert to ziplist when in limits. */
1685         if (dstzset->zsl->length <= server.zset_max_ziplist_entries &&
1686             maxelelen <= server.zset_max_ziplist_value)
1687                 zsetConvert(dstobj,REDIS_ENCODING_ZIPLIST);
1688 
1689         dbAdd(c->db,dstkey,dstobj);
1690         addReplyLongLong(c,zsetLength(dstobj));
1691         if (!touched) signalModifiedKey(c->db,dstkey);
1692         notifyKeyspaceEvent(
1693             (op == REDIS_OP_UNION) ? "zunionstore" : "zinterstore",
1694             dstkey,c->db->id);
1695         server.dirty++;
1696     } else {
1697         decrRefCount(dstobj);
1698         addReply(c,shared.czero);
1699     }
1700     zfree(src);
1701 }
1702 
1703 void zunionstoreCommand(redisClient *c) {
1704     zunionInterGenericCommand(c,c->argv[1], REDIS_OP_UNION);
1705 }
1706 
1707 void zinterstoreCommand(redisClient *c) {
1708     zunionInterGenericCommand(c,c->argv[1], REDIS_OP_INTER);
1709 }
1710 
1711 void zrangeGenericCommand(redisClient *c, int reverse) {
1712     robj *key = c->argv[1];
1713     robj *zobj;
1714     int withscores = 0;
1715     long start;
1716     long end;
1717     int llen;
1718     int rangelen;
1719 
1720     if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != REDIS_OK) ||
1721         (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != REDIS_OK)) return;
1722 
1723     if (c->argc == 5 && !strcasecmp(c->argv[4]->ptr,"withscores")) {
1724         withscores = 1;
1725     } else if (c->argc >= 5) {
1726         addReply(c,shared.syntaxerr);
1727         return;
1728     }
1729 
1730     if ((zobj = lookupKeyReadOrReply(c,key,shared.emptymultibulk)) == NULL
1731          || checkType(c,zobj,REDIS_ZSET)) return;
1732 
1733     /* Sanitize indexes. */
1734     llen = zsetLength(zobj);
1735     if (start < 0) start = llen+start;
1736     if (end < 0) end = llen+end;
1737     if (start < 0) start = 0;
1738 
1739     /* Invariant: start >= 0, so this test will be true when end < 0.
1740      * The range is empty when start > end or start >= length. */
1741     if (start > end || start >= llen) {
1742         addReply(c,shared.emptymultibulk);
1743         return;
1744     }
1745     if (end >= llen) end = llen-1;
1746     rangelen = (end-start)+1;
1747 
1748     /* Return the result in form of a multi-bulk reply */
1749     addReplyMultiBulkLen(c, withscores ? (rangelen*2) : rangelen);
1750 
1751     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
1752         unsigned char *zl = zobj->ptr;
1753         unsigned char *eptr, *sptr;
1754         unsigned char *vstr;
1755         unsigned int vlen;
1756         long long vlong;
1757 
1758         if (reverse)
1759             eptr = ziplistIndex(zl,-2-(2*start));
1760         else
1761             eptr = ziplistIndex(zl,2*start);
1762 
1763         redisAssertWithInfo(c,zobj,eptr != NULL);
1764         sptr = ziplistNext(zl,eptr);
1765 
1766         while (rangelen--) {
1767             redisAssertWithInfo(c,zobj,eptr != NULL && sptr != NULL);
1768             redisAssertWithInfo(c,zobj,ziplistGet(eptr,&vstr,&vlen,&vlong));
1769             if (vstr == NULL)
1770                 addReplyBulkLongLong(c,vlong);
1771             else
1772                 addReplyBulkCBuffer(c,vstr,vlen);
1773 
1774             if (withscores)
1775                 addReplyDouble(c,zzlGetScore(sptr));
1776 
1777             if (reverse)
1778                 zzlPrev(zl,&eptr,&sptr);
1779             else
1780                 zzlNext(zl,&eptr,&sptr);
1781         }
1782 
1783     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
1784         zset *zs = zobj->ptr;
1785         zskiplist *zsl = zs->zsl;
1786         zskiplistNode *ln;
1787         robj *ele;
1788 
1789         /* Check if starting point is trivial, before doing log(N) lookup. */
1790         if (reverse) {
1791             ln = zsl->tail;
1792             if (start > 0)
1793                 ln = zslGetElementByRank(zsl,llen-start);
1794         } else {
1795             ln = zsl->header->level[0].forward;
1796             if (start > 0)
1797                 ln = zslGetElementByRank(zsl,start+1);
1798         }
1799 
1800         while(rangelen--) {
1801             redisAssertWithInfo(c,zobj,ln != NULL);
1802             ele = ln->obj;
1803             addReplyBulk(c,ele);
1804             if (withscores)
1805                 addReplyDouble(c,ln->score);
1806             ln = reverse ? ln->backward : ln->level[0].forward;
1807         }
1808     } else {
1809         redisPanic("Unknown sorted set encoding");
1810     }
1811 }
1812 
1813 void zrangeCommand(redisClient *c) {
1814     zrangeGenericCommand(c,0);
1815 }
1816 
1817 void zrevrangeCommand(redisClient *c) {
1818     zrangeGenericCommand(c,1);
1819 }
1820 
1821 /* This command implements ZRANGEBYSCORE, ZREVRANGEBYSCORE. */
1822 void genericZrangebyscoreCommand(redisClient *c, int reverse) {
1823     zrangespec range;
1824     robj *key = c->argv[1];
1825     robj *zobj;
1826     long offset = 0, limit = -1;
1827     int withscores = 0;
1828     unsigned long rangelen = 0;
1829     void *replylen = NULL;
1830     int minidx, maxidx;
1831 
1832     /* Parse the range arguments. */
1833     if (reverse) {
1834         /* Range is given as [max,min] */
1835         maxidx = 2; minidx = 3;
1836     } else {
1837         /* Range is given as [min,max] */
1838         minidx = 2; maxidx = 3;
1839     }
1840 
1841     if (zslParseRange(c->argv[minidx],c->argv[maxidx],&range) != REDIS_OK) {
1842         addReplyError(c,"min or max is not a float");
1843         return;
1844     }
1845 
1846     /* Parse optional extra arguments. Note that ZCOUNT will exactly have
1847      * 4 arguments, so we'll never enter the following code path. */
1848     if (c->argc > 4) {
1849         int remaining = c->argc - 4;
1850         int pos = 4;
1851 
1852         while (remaining) {
1853             if (remaining >= 1 && !strcasecmp(c->argv[pos]->ptr,"withscores")) {
1854                 pos++; remaining--;
1855                 withscores = 1;
1856             } else if (remaining >= 3 && !strcasecmp(c->argv[pos]->ptr,"limit")) {
1857                 if ((getLongFromObjectOrReply(c, c->argv[pos+1], &offset, NULL) != REDIS_OK) ||
1858                     (getLongFromObjectOrReply(c, c->argv[pos+2], &limit, NULL) != REDIS_OK)) return;
1859                 pos += 3; remaining -= 3;
1860             } else {
1861                 addReply(c,shared.syntaxerr);
1862                 return;
1863             }
1864         }
1865     }
1866 
1867     /* Ok, lookup the key and get the range */
1868     if ((zobj = lookupKeyReadOrReply(c,key,shared.emptymultibulk)) == NULL ||
1869         checkType(c,zobj,REDIS_ZSET)) return;
1870 
1871     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
1872         unsigned char *zl = zobj->ptr;
1873         unsigned char *eptr, *sptr;
1874         unsigned char *vstr;
1875         unsigned int vlen;
1876         long long vlong;
1877         double score;
1878 
1879         /* If reversed, get the last node in range as starting point. */
1880         if (reverse) {
1881             eptr = zzlLastInRange(zl,range);
1882         } else {
1883             eptr = zzlFirstInRange(zl,range);
1884         }
1885 
1886         /* No "first" element in the specified interval. */
1887         if (eptr == NULL) {
1888             addReply(c, shared.emptymultibulk);
1889             return;
1890         }
1891 
1892         /* Get score pointer for the first element. */
1893         redisAssertWithInfo(c,zobj,eptr != NULL);
1894         sptr = ziplistNext(zl,eptr);
1895 
1896         /* We don't know in advance how many matching elements there are in the
1897          * list, so we push this object that will represent the multi-bulk
1898          * length in the output buffer, and will "fix" it later */
1899         replylen = addDeferredMultiBulkLength(c);
1900 
1901         /* If there is an offset, just traverse the number of elements without
1902          * checking the score because that is done in the next loop. */
1903         while (eptr && offset--) {
1904             if (reverse) {
1905                 zzlPrev(zl,&eptr,&sptr);
1906             } else {
1907                 zzlNext(zl,&eptr,&sptr);
1908             }
1909         }
1910 
1911         while (eptr && limit--) {
1912             score = zzlGetScore(sptr);
1913 
1914             /* Abort when the node is no longer in range. */
1915             if (reverse) {
1916                 if (!zslValueGteMin(score,&range)) break;
1917             } else {
1918                 if (!zslValueLteMax(score,&range)) break;
1919             }
1920 
1921             /* We know the element exists, so ziplistGet should always succeed */
1922             redisAssertWithInfo(c,zobj,ziplistGet(eptr,&vstr,&vlen,&vlong));
1923 
1924             rangelen++;
1925             if (vstr == NULL) {
1926                 addReplyBulkLongLong(c,vlong);
1927             } else {
1928                 addReplyBulkCBuffer(c,vstr,vlen);
1929             }
1930 
1931             if (withscores) {
1932                 addReplyDouble(c,score);
1933             }
1934 
1935             /* Move to next node */
1936             if (reverse) {
1937                 zzlPrev(zl,&eptr,&sptr);
1938             } else {
1939                 zzlNext(zl,&eptr,&sptr);
1940             }
1941         }
1942     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
1943         zset *zs = zobj->ptr;
1944         zskiplist *zsl = zs->zsl;
1945         zskiplistNode *ln;
1946 
1947         /* If reversed, get the last node in range as starting point. */
1948         if (reverse) {
1949             ln = zslLastInRange(zsl,range);
1950         } else {
1951             ln = zslFirstInRange(zsl,range);
1952         }
1953 
1954         /* No "first" element in the specified interval. */
1955         if (ln == NULL) {
1956             addReply(c, shared.emptymultibulk);
1957             return;
1958         }
1959 
1960         /* We don't know in advance how many matching elements there are in the
1961          * list, so we push this object that will represent the multi-bulk
1962          * length in the output buffer, and will "fix" it later */
1963         replylen = addDeferredMultiBulkLength(c);
1964 
1965         /* If there is an offset, just traverse the number of elements without
1966          * checking the score because that is done in the next loop. */
1967         while (ln && offset--) {
1968             if (reverse) {
1969                 ln = ln->backward;
1970             } else {
1971                 ln = ln->level[0].forward;
1972             }
1973         }
1974 
1975         while (ln && limit--) {
1976             /* Abort when the node is no longer in range. */
1977             if (reverse) {
1978                 if (!zslValueGteMin(ln->score,&range)) break;
1979             } else {
1980                 if (!zslValueLteMax(ln->score,&range)) break;
1981             }
1982 
1983             rangelen++;
1984             addReplyBulk(c,ln->obj);
1985 
1986             if (withscores) {
1987                 addReplyDouble(c,ln->score);
1988             }
1989 
1990             /* Move to next node */
1991             if (reverse) {
1992                 ln = ln->backward;
1993             } else {
1994                 ln = ln->level[0].forward;
1995             }
1996         }
1997     } else {
1998         redisPanic("Unknown sorted set encoding");
1999     }
2000 
2001     if (withscores) {
2002         rangelen *= 2;
2003     }
2004 
2005     setDeferredMultiBulkLength(c, replylen, rangelen);
2006 }
2007 
2008 void zrangebyscoreCommand(redisClient *c) {
2009     genericZrangebyscoreCommand(c,0);
2010 }
2011 
2012 void zrevrangebyscoreCommand(redisClient *c) {
2013     genericZrangebyscoreCommand(c,1);
2014 }
2015 
2016 void zcountCommand(redisClient *c) {
2017     robj *key = c->argv[1];
2018     robj *zobj;
2019     zrangespec range;
2020     int count = 0;
2021 
2022     /* Parse the range arguments */
2023     if (zslParseRange(c->argv[2],c->argv[3],&range) != REDIS_OK) {
2024         addReplyError(c,"min or max is not a float");
2025         return;
2026     }
2027 
2028     /* Lookup the sorted set */
2029     if ((zobj = lookupKeyReadOrReply(c, key, shared.czero)) == NULL ||
2030         checkType(c, zobj, REDIS_ZSET)) return;
2031 
2032     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
2033         unsigned char *zl = zobj->ptr;
2034         unsigned char *eptr, *sptr;
2035         double score;
2036 
2037         /* Use the first element in range as the starting point */
2038         eptr = zzlFirstInRange(zl,range);
2039 
2040         /* No "first" element */
2041         if (eptr == NULL) {
2042             addReply(c, shared.czero);
2043             return;
2044         }
2045 
2046         /* First element is in range */
2047         sptr = ziplistNext(zl,eptr);
2048         score = zzlGetScore(sptr);
2049         redisAssertWithInfo(c,zobj,zslValueLteMax(score,&range));
2050 
2051         /* Iterate over elements in range */
2052         while (eptr) {
2053             score = zzlGetScore(sptr);
2054 
2055             /* Abort when the node is no longer in range. */
2056             if (!zslValueLteMax(score,&range)) {
2057                 break;
2058             } else {
2059                 count++;
2060                 zzlNext(zl,&eptr,&sptr);
2061             }
2062         }
2063     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
2064         zset *zs = zobj->ptr;
2065         zskiplist *zsl = zs->zsl;
2066         zskiplistNode *zn;
2067         unsigned long rank;
2068 
2069         /* Find first element in range */
2070         zn = zslFirstInRange(zsl, range);
2071 
2072         /* Use rank of first element, if any, to determine preliminary count */
2073         if (zn != NULL) {
2074             rank = zslGetRank(zsl, zn->score, zn->obj);
2075             count = (zsl->length - (rank - 1));
2076 
2077             /* Find last element in range */
2078             zn = zslLastInRange(zsl, range);
2079 
2080             /* Use rank of last element, if any, to determine the actual count */
2081             if (zn != NULL) {
2082                 rank = zslGetRank(zsl, zn->score, zn->obj);
2083                 count -= (zsl->length - rank);
2084             }
2085         }
2086     } else {
2087         redisPanic("Unknown sorted set encoding");
2088     }
2089 
2090     addReplyLongLong(c, count);
2091 }
2092 
2093 void zcardCommand(redisClient *c) {
2094     robj *key = c->argv[1];
2095     robj *zobj;
2096 
2097     if ((zobj = lookupKeyReadOrReply(c,key,shared.czero)) == NULL ||
2098         checkType(c,zobj,REDIS_ZSET)) return;
2099 
2100     addReplyLongLong(c,zsetLength(zobj));
2101 }
2102 
2103 void zscoreCommand(redisClient *c) {
2104     robj *key = c->argv[1];
2105     robj *zobj;
2106     double score;
2107 
2108     if ((zobj = lookupKeyReadOrReply(c,key,shared.nullbulk)) == NULL ||
2109         checkType(c,zobj,REDIS_ZSET)) return;
2110 
2111     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
2112         if (zzlFind(zobj->ptr,c->argv[2],&score) != NULL)
2113             addReplyDouble(c,score);
2114         else
2115             addReply(c,shared.nullbulk);
2116     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
2117         zset *zs = zobj->ptr;
2118         dictEntry *de;
2119 
2120         c->argv[2] = tryObjectEncoding(c->argv[2]);
2121         de = dictFind(zs->dict,c->argv[2]);
2122         if (de != NULL) {
2123             score = *(double*)dictGetVal(de);
2124             addReplyDouble(c,score);
2125         } else {
2126             addReply(c,shared.nullbulk);
2127         }
2128     } else {
2129         redisPanic("Unknown sorted set encoding");
2130     }
2131 }
2132 
2133 void zrankGenericCommand(redisClient *c, int reverse) {
2134     robj *key = c->argv[1];
2135     robj *ele = c->argv[2];
2136     robj *zobj;
2137     unsigned long llen;
2138     unsigned long rank;
2139 
2140     if ((zobj = lookupKeyReadOrReply(c,key,shared.nullbulk)) == NULL ||
2141         checkType(c,zobj,REDIS_ZSET)) return;
2142     llen = zsetLength(zobj);
2143 
2144     redisAssertWithInfo(c,ele,ele->encoding == REDIS_ENCODING_RAW);
2145     if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
2146         unsigned char *zl = zobj->ptr;
2147         unsigned char *eptr, *sptr;
2148 
2149         eptr = ziplistIndex(zl,0);
2150         redisAssertWithInfo(c,zobj,eptr != NULL);
2151         sptr = ziplistNext(zl,eptr);
2152         redisAssertWithInfo(c,zobj,sptr != NULL);
2153 
2154         rank = 1;
2155         while(eptr != NULL) {
2156             if (ziplistCompare(eptr,ele->ptr,sdslen(ele->ptr)))
2157                 break;
2158             rank++;
2159             zzlNext(zl,&eptr,&sptr);
2160         }
2161 
2162         if (eptr != NULL) {
2163             if (reverse)
2164                 addReplyLongLong(c,llen-rank);
2165             else
2166                 addReplyLongLong(c,rank-1);
2167         } else {
2168             addReply(c,shared.nullbulk);
2169         }
2170     } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
2171         zset *zs = zobj->ptr;
2172         zskiplist *zsl = zs->zsl;
2173         dictEntry *de;
2174         double score;
2175 
2176         ele = c->argv[2] = tryObjectEncoding(c->argv[2]);
2177         de = dictFind(zs->dict,ele);
2178         if (de != NULL) {
2179             score = *(double*)dictGetVal(de);
2180             rank = zslGetRank(zsl,score,ele);
2181             redisAssertWithInfo(c,ele,rank); /* Existing elements always have a rank. */
2182             if (reverse)
2183                 addReplyLongLong(c,llen-rank);
2184             else
2185                 addReplyLongLong(c,rank-1);
2186         } else {
2187             addReply(c,shared.nullbulk);
2188         }
2189     } else {
2190         redisPanic("Unknown sorted set encoding");
2191     }
2192 }
2193 
2194 void zrankCommand(redisClient *c) {
2195     zrankGenericCommand(c, 0);
2196 }
2197 
2198 void zrevrankCommand(redisClient *c) {
2199     zrankGenericCommand(c, 1);
2200 }
2201