ele = getDecodedObject(ele);
while (eptr != NULL) {
sptr = ziplistNext(zl,eptr);
- redisAssert(sptr != NULL);
+ redisAssertWithInfo(NULL,ele,sptr != NULL);
if (ziplistCompare(eptr,ele->ptr,sdslen(ele->ptr))) {
/* Matching element, pull out score. */
int scorelen;
size_t offset;
- redisAssert(ele->encoding == REDIS_ENCODING_RAW);
+ redisAssertWithInfo(NULL,ele,ele->encoding == REDIS_ENCODING_RAW);
scorelen = d2string(scorebuf,sizeof(scorebuf),score);
if (eptr == NULL) {
zl = ziplistPush(zl,ele->ptr,sdslen(ele->ptr),ZIPLIST_TAIL);
eptr = zl+offset;
/* Insert score after the element. */
- redisAssert((sptr = ziplistNext(zl,eptr)) != NULL);
+ redisAssertWithInfo(NULL,ele,(sptr = ziplistNext(zl,eptr)) != NULL);
zl = ziplistInsert(zl,sptr,(unsigned char*)scorebuf,scorelen);
}
ele = getDecodedObject(ele);
while (eptr != NULL) {
sptr = ziplistNext(zl,eptr);
- redisAssert(sptr != NULL);
+ redisAssertWithInfo(NULL,ele,sptr != NULL);
s = zzlGetScore(sptr);
if (s > score) {
zs->zsl = zslCreate();
eptr = ziplistIndex(zl,0);
- redisAssert(eptr != NULL);
+ redisAssertWithInfo(NULL,zobj,eptr != NULL);
sptr = ziplistNext(zl,eptr);
- redisAssert(sptr != NULL);
+ redisAssertWithInfo(NULL,zobj,sptr != NULL);
while (eptr != NULL) {
score = zzlGetScore(sptr);
- redisAssert(ziplistGet(eptr,&vstr,&vlen,&vlong));
+ redisAssertWithInfo(NULL,zobj,ziplistGet(eptr,&vstr,&vlen,&vlong));
if (vstr == NULL)
ele = createStringObjectFromLongLong(vlong);
else
/* Has incremented refcount since it was just created. */
node = zslInsert(zs->zsl,score,ele);
- redisAssert(dictAdd(zs->dict,ele,&node->score) == DICT_OK);
+ redisAssertWithInfo(NULL,zobj,dictAdd(zs->dict,ele,&node->score) == DICT_OK);
incrRefCount(ele); /* Added to dictionary. */
zzlNext(zl,&eptr,&sptr);
}
* delete the key object from the skiplist, since the
* dictionary still has a reference to it. */
if (score != curscore) {
- redisAssert(zslDelete(zs->zsl,curscore,curobj));
+ redisAssertWithInfo(c,curobj,zslDelete(zs->zsl,curscore,curobj));
znode = zslInsert(zs->zsl,score,curobj);
incrRefCount(curobj); /* Re-inserted in skiplist. */
dictGetEntryVal(de) = &znode->score; /* Update score ptr. */
} else {
znode = zslInsert(zs->zsl,score,ele);
incrRefCount(ele); /* Inserted in skiplist. */
- redisAssert(dictAdd(zs->dict,ele,&znode->score) == DICT_OK);
+ redisAssertWithInfo(c,curobj,dictAdd(zs->dict,ele,&znode->score) == DICT_OK);
incrRefCount(ele); /* Added to dictionary. */
signalModifiedKey(c->db,key);
void zremCommand(redisClient *c) {
robj *key = c->argv[1];
- robj *ele = c->argv[2];
robj *zobj;
+ int deleted = 0, j;
if ((zobj = lookupKeyWriteOrReply(c,key,shared.czero)) == NULL ||
checkType(c,zobj,REDIS_ZSET)) return;
if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
unsigned char *eptr;
- if ((eptr = zzlFind(zobj->ptr,ele,NULL)) != NULL) {
- zobj->ptr = zzlDelete(zobj->ptr,eptr);
- if (zzlLength(zobj->ptr) == 0) dbDelete(c->db,key);
- } else {
- addReply(c,shared.czero);
- return;
+ for (j = 2; j < c->argc; j++) {
+ if ((eptr = zzlFind(zobj->ptr,c->argv[j],NULL)) != NULL) {
+ deleted++;
+ zobj->ptr = zzlDelete(zobj->ptr,eptr);
+ if (zzlLength(zobj->ptr) == 0) {
+ dbDelete(c->db,key);
+ break;
+ }
+ }
}
} else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
zset *zs = zobj->ptr;
dictEntry *de;
double score;
- de = dictFind(zs->dict,ele);
- if (de != NULL) {
- /* Delete from the skiplist */
- score = *(double*)dictGetEntryVal(de);
- redisAssert(zslDelete(zs->zsl,score,ele));
-
- /* Delete from the hash table */
- dictDelete(zs->dict,ele);
- if (htNeedsResize(zs->dict)) dictResize(zs->dict);
- if (dictSize(zs->dict) == 0) dbDelete(c->db,key);
- } else {
- addReply(c,shared.czero);
- return;
+ for (j = 2; j < c->argc; j++) {
+ de = dictFind(zs->dict,c->argv[j]);
+ if (de != NULL) {
+ deleted++;
+
+ /* Delete from the skiplist */
+ score = *(double*)dictGetEntryVal(de);
+ redisAssertWithInfo(c,c->argv[j],zslDelete(zs->zsl,score,c->argv[j]));
+
+ /* Delete from the hash table */
+ dictDelete(zs->dict,c->argv[j]);
+ if (htNeedsResize(zs->dict)) dictResize(zs->dict);
+ if (dictSize(zs->dict) == 0) {
+ dbDelete(c->db,key);
+ break;
+ }
+ }
}
} else {
redisPanic("Unknown sorted set encoding");
}
- signalModifiedKey(c->db,key);
- server.dirty++;
- addReply(c,shared.cone);
+ if (deleted) {
+ signalModifiedKey(c->db,key);
+ server.dirty += deleted;
+ }
+ addReplyLongLong(c,deleted);
}
void zremrangebyscoreCommand(redisClient *c) {
else
eptr = ziplistIndex(zl,2*start);
- redisAssert(eptr != NULL);
+ redisAssertWithInfo(c,zobj,eptr != NULL);
sptr = ziplistNext(zl,eptr);
while (rangelen--) {
- redisAssert(eptr != NULL && sptr != NULL);
- redisAssert(ziplistGet(eptr,&vstr,&vlen,&vlong));
+ redisAssertWithInfo(c,zobj,eptr != NULL && sptr != NULL);
+ redisAssertWithInfo(c,zobj,ziplistGet(eptr,&vstr,&vlen,&vlong));
if (vstr == NULL)
addReplyBulkLongLong(c,vlong);
else
}
while(rangelen--) {
- redisAssert(ln != NULL);
+ redisAssertWithInfo(c,zobj,ln != NULL);
ele = ln->obj;
addReplyBulk(c,ele);
if (withscores)
zrangeGenericCommand(c,1);
}
-/* This command implements ZRANGEBYSCORE, ZREVRANGEBYSCORE and ZCOUNT.
- * If "justcount", only the number of elements in the range is returned. */
-void genericZrangebyscoreCommand(redisClient *c, int reverse, int justcount) {
+/* This command implements ZRANGEBYSCORE, ZREVRANGEBYSCORE. */
+void genericZrangebyscoreCommand(redisClient *c, int reverse) {
zrangespec range;
robj *key = c->argv[1];
- robj *emptyreply, *zobj;
+ robj *zobj;
int offset = 0, limit = -1;
int withscores = 0;
unsigned long rangelen = 0;
}
/* Ok, lookup the key and get the range */
- emptyreply = justcount ? shared.czero : shared.emptymultibulk;
- if ((zobj = lookupKeyReadOrReply(c,key,emptyreply)) == NULL ||
+ if ((zobj = lookupKeyReadOrReply(c,key,shared.emptymultibulk)) == NULL ||
checkType(c,zobj,REDIS_ZSET)) return;
if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
double score;
/* If reversed, get the last node in range as starting point. */
- if (reverse)
+ if (reverse) {
eptr = zzlLastInRange(zl,range);
- else
+ } else {
eptr = zzlFirstInRange(zl,range);
+ }
/* No "first" element in the specified interval. */
if (eptr == NULL) {
- addReply(c,emptyreply);
+ addReply(c, shared.emptymultibulk);
return;
}
/* Get score pointer for the first element. */
- redisAssert(eptr != NULL);
+ redisAssertWithInfo(c,zobj,eptr != NULL);
sptr = ziplistNext(zl,eptr);
/* We don't know in advance how many matching elements there are in the
* list, so we push this object that will represent the multi-bulk
* length in the output buffer, and will "fix" it later */
- if (!justcount)
- replylen = addDeferredMultiBulkLength(c);
+ replylen = addDeferredMultiBulkLength(c);
/* If there is an offset, just traverse the number of elements without
* checking the score because that is done in the next loop. */
- while (eptr && offset--)
- if (reverse)
+ while (eptr && offset--) {
+ if (reverse) {
zzlPrev(zl,&eptr,&sptr);
- else
+ } else {
zzlNext(zl,&eptr,&sptr);
+ }
+ }
while (eptr && limit--) {
score = zzlGetScore(sptr);
if (!zslValueLteMax(score,&range)) break;
}
- /* Do our magic */
+ /* We know the element exists, so ziplistGet should always succeed */
+ redisAssertWithInfo(c,zobj,ziplistGet(eptr,&vstr,&vlen,&vlong));
+
rangelen++;
- if (!justcount) {
- redisAssert(ziplistGet(eptr,&vstr,&vlen,&vlong));
- if (vstr == NULL)
- addReplyBulkLongLong(c,vlong);
- else
- addReplyBulkCBuffer(c,vstr,vlen);
-
- if (withscores)
- addReplyDouble(c,score);
+ if (vstr == NULL) {
+ addReplyBulkLongLong(c,vlong);
+ } else {
+ addReplyBulkCBuffer(c,vstr,vlen);
+ }
+
+ if (withscores) {
+ addReplyDouble(c,score);
}
/* Move to next node */
- if (reverse)
+ if (reverse) {
zzlPrev(zl,&eptr,&sptr);
- else
+ } else {
zzlNext(zl,&eptr,&sptr);
+ }
}
} else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
zset *zs = zobj->ptr;
zskiplistNode *ln;
/* If reversed, get the last node in range as starting point. */
- if (reverse)
+ if (reverse) {
ln = zslLastInRange(zsl,range);
- else
+ } else {
ln = zslFirstInRange(zsl,range);
+ }
/* No "first" element in the specified interval. */
if (ln == NULL) {
- addReply(c,emptyreply);
+ addReply(c, shared.emptymultibulk);
return;
}
/* We don't know in advance how many matching elements there are in the
* list, so we push this object that will represent the multi-bulk
* length in the output buffer, and will "fix" it later */
- if (!justcount)
- replylen = addDeferredMultiBulkLength(c);
+ replylen = addDeferredMultiBulkLength(c);
/* If there is an offset, just traverse the number of elements without
* checking the score because that is done in the next loop. */
- while (ln && offset--)
- ln = reverse ? ln->backward : ln->level[0].forward;
+ while (ln && offset--) {
+ if (reverse) {
+ ln = ln->backward;
+ } else {
+ ln = ln->level[0].forward;
+ }
+ }
while (ln && limit--) {
/* Abort when the node is no longer in range. */
if (!zslValueLteMax(ln->score,&range)) break;
}
- /* Do our magic */
rangelen++;
- if (!justcount) {
- addReplyBulk(c,ln->obj);
- if (withscores)
- addReplyDouble(c,ln->score);
+ addReplyBulk(c,ln->obj);
+
+ if (withscores) {
+ addReplyDouble(c,ln->score);
}
/* Move to next node */
- ln = reverse ? ln->backward : ln->level[0].forward;
+ if (reverse) {
+ ln = ln->backward;
+ } else {
+ ln = ln->level[0].forward;
+ }
}
} else {
redisPanic("Unknown sorted set encoding");
}
- if (justcount) {
- addReplyLongLong(c,(long)rangelen);
- } else {
- if (withscores) rangelen *= 2;
- setDeferredMultiBulkLength(c,replylen,rangelen);
+ if (withscores) {
+ rangelen *= 2;
}
+
+ setDeferredMultiBulkLength(c, replylen, rangelen);
}
void zrangebyscoreCommand(redisClient *c) {
- genericZrangebyscoreCommand(c,0,0);
+ genericZrangebyscoreCommand(c,0);
}
void zrevrangebyscoreCommand(redisClient *c) {
- genericZrangebyscoreCommand(c,1,0);
+ genericZrangebyscoreCommand(c,1);
}
void zcountCommand(redisClient *c) {
- genericZrangebyscoreCommand(c,0,1);
+ robj *key = c->argv[1];
+ robj *zobj;
+ zrangespec range;
+ int count = 0;
+
+ /* Parse the range arguments */
+ if (zslParseRange(c->argv[2],c->argv[3],&range) != REDIS_OK) {
+ addReplyError(c,"min or max is not a double");
+ return;
+ }
+
+ /* Lookup the sorted set */
+ if ((zobj = lookupKeyReadOrReply(c, key, shared.czero)) == NULL ||
+ checkType(c, zobj, REDIS_ZSET)) return;
+
+ if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
+ unsigned char *zl = zobj->ptr;
+ unsigned char *eptr, *sptr;
+ double score;
+
+ /* Use the first element in range as the starting point */
+ eptr = zzlFirstInRange(zl,range);
+
+ /* No "first" element */
+ if (eptr == NULL) {
+ addReply(c, shared.czero);
+ return;
+ }
+
+ /* First element is in range */
+ sptr = ziplistNext(zl,eptr);
+ score = zzlGetScore(sptr);
+ redisAssertWithInfo(c,zobj,zslValueLteMax(score,&range));
+
+ /* Iterate over elements in range */
+ while (eptr) {
+ score = zzlGetScore(sptr);
+
+ /* Abort when the node is no longer in range. */
+ if (!zslValueLteMax(score,&range)) {
+ break;
+ } else {
+ count++;
+ zzlNext(zl,&eptr,&sptr);
+ }
+ }
+ } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
+ zset *zs = zobj->ptr;
+ zskiplist *zsl = zs->zsl;
+ zskiplistNode *zn;
+ unsigned long rank;
+
+ /* Find first element in range */
+ zn = zslFirstInRange(zsl, range);
+
+ /* Use rank of first element, if any, to determine preliminary count */
+ if (zn != NULL) {
+ rank = zslGetRank(zsl, zn->score, zn->obj);
+ count = (zsl->length - (rank - 1));
+
+ /* Find last element in range */
+ zn = zslLastInRange(zsl, range);
+
+ /* Use rank of last element, if any, to determine the actual count */
+ if (zn != NULL) {
+ rank = zslGetRank(zsl, zn->score, zn->obj);
+ count -= (zsl->length - rank);
+ }
+ }
+ } else {
+ redisPanic("Unknown sorted set encoding");
+ }
+
+ addReplyLongLong(c, count);
}
void zcardCommand(redisClient *c) {
checkType(c,zobj,REDIS_ZSET)) return;
llen = zsetLength(zobj);
- redisAssert(ele->encoding == REDIS_ENCODING_RAW);
+ redisAssertWithInfo(c,ele,ele->encoding == REDIS_ENCODING_RAW);
if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
unsigned char *zl = zobj->ptr;
unsigned char *eptr, *sptr;
eptr = ziplistIndex(zl,0);
- redisAssert(eptr != NULL);
+ redisAssertWithInfo(c,zobj,eptr != NULL);
sptr = ziplistNext(zl,eptr);
- redisAssert(sptr != NULL);
+ redisAssertWithInfo(c,zobj,sptr != NULL);
rank = 1;
while(eptr != NULL) {
if (de != NULL) {
score = *(double*)dictGetEntryVal(de);
rank = zslGetRank(zsl,score,ele);
- redisAssert(rank); /* Existing elements always have a rank. */
+ redisAssertWithInfo(c,ele,rank); /* Existing elements always have a rank. */
if (reverse)
addReplyLongLong(c,llen-rank);
else