/* This skiplist implementation is almost a C translation of the original
* algorithm described by William Pugh in "Skip Lists: A Probabilistic
* Alternative to Balanced Trees", modified in three ways:
- * a) this implementation allows for repeated values.
+ * a) this implementation allows for repeated scores.
* b) the comparison is not just by key (our 'score') but by satellite data.
* c) there is a back pointer, so it's a doubly linked list with the back
* pointers being only at "level 1". This allows to traverse the list
zfree(zsl);
}
+/* Returns a random level for the new skiplist node we are going to create.
+ * The return value of this function is between 1 and ZSKIPLIST_MAXLEVEL
+ * (both inclusive), with a powerlaw-alike distribution where higher
+ * levels are less likely to be returned. */
int zslRandomLevel(void) {
int level = 1;
while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
unsigned int rank[ZSKIPLIST_MAXLEVEL];
int i, level;
+ redisAssert(!isnan(score));
x = zsl->header;
for (i = zsl->level-1; i >= 0; i--) {
/* store rank that is crossed to reach the insert position */
return 0;
p = ziplistIndex(zl,-1); /* Last score. */
- redisAssert(p != NULL);
+ if (p == NULL) return 0; /* Empty sorted set */
score = zzlGetScore(p);
if (!zslValueGteMin(score,range))
return 0;
if (val->flags & OPVAL_DIRTY_ROBJ)
decrRefCount(val->ele);
- bzero(val,sizeof(zsetopval));
+ memset(val,0,sizeof(zsetopval));
if (op->type == REDIS_SET) {
iterset *it = &op->iter.set;
if (op->encoding == REDIS_ENCODING_INTSET) {
- if (!intsetGet(it->is.is,it->is.ii,(int64_t*)&val->ell))
+ int64_t ell = val->ell;
+
+ if (!intsetGet(it->is.is,it->is.ii,&ell))
return 0;
val->score = 1.0;
}
void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
- int i, j, setnum;
+ int i, j;
+ long setnum;
int aggregate = REDIS_AGGR_SUM;
zsetopsrc *src;
zsetopval zval;
int touched = 0;
/* expect setnum input keys to be given */
- setnum = atoi(c->argv[2]->ptr);
+ if ((getLongFromObjectOrReply(c, c->argv[2], &setnum, NULL) != REDIS_OK))
+ return;
+
if (setnum < 1) {
addReplyError(c,
"at least 1 input key is needed for ZUNIONSTORE/ZINTERSTORE");
double score, value;
score = src[0].weight * zval.score;
+ if (isnan(score)) score = 0;
+
for (j = 1; j < setnum; j++) {
/* It is not safe to access the zset we are
* iterating, so explicitly check for equal object. */
/* Initialize score */
score = src[i].weight * zval.score;
+ if (isnan(score)) score = 0;
/* Because the inputs are sorted by size, it's only possible
* for sets at larger indices to hold this element. */
zrangespec range;
robj *key = c->argv[1];
robj *zobj;
- int offset = 0, limit = -1;
+ long offset = 0, limit = -1;
int withscores = 0;
unsigned long rangelen = 0;
void *replylen = NULL;
pos++; remaining--;
withscores = 1;
} else if (remaining >= 3 && !strcasecmp(c->argv[pos]->ptr,"limit")) {
- offset = atoi(c->argv[pos+1]->ptr);
- limit = atoi(c->argv[pos+2]->ptr);
+ if ((getLongFromObjectOrReply(c, c->argv[pos+1], &offset, NULL) != REDIS_OK) ||
+ (getLongFromObjectOrReply(c, c->argv[pos+2], &limit, NULL) != REDIS_OK)) return;
pos += 3; remaining -= 3;
} else {
addReply(c,shared.syntaxerr);