summaryrefslogtreecommitdiff
path: root/src/t_zset.c
diff options
context:
space:
mode:
authorPieter Noordhuis <pcnoordhuis@gmail.com>2011-10-03 14:14:43 +0200
committerPieter Noordhuis <pcnoordhuis@gmail.com>2011-10-03 14:14:43 +0200
commit62d774e5ba6056be39012ecedb88c3fec10304fb (patch)
tree301b9a86af91987d41073178d4fe9e5522e7c263 /src/t_zset.c
parent13c7e5ef299f4f6b38cd81c924bdf3eca691d691 (diff)
downloadredis-62d774e5ba6056be39012ecedb88c3fec10304fb.tar.gz
Use element rank instead of iterating in ZCOUNT
Diffstat (limited to 'src/t_zset.c')
-rw-r--r--src/t_zset.c75
1 files changed, 74 insertions, 1 deletions
diff --git a/src/t_zset.c b/src/t_zset.c
index 6a56c3b4e..7ffed366e 100644
--- a/src/t_zset.c
+++ b/src/t_zset.c
@@ -1943,7 +1943,80 @@ void zrevrangebyscoreCommand(redisClient *c) {
}
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);
+ redisAssert(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) {