diff options
author | Pieter Noordhuis <pcnoordhuis@gmail.com> | 2011-10-03 14:14:43 +0200 |
---|---|---|
committer | Pieter Noordhuis <pcnoordhuis@gmail.com> | 2011-10-03 14:14:43 +0200 |
commit | 62d774e5ba6056be39012ecedb88c3fec10304fb (patch) | |
tree | 301b9a86af91987d41073178d4fe9e5522e7c263 /src/t_zset.c | |
parent | 13c7e5ef299f4f6b38cd81c924bdf3eca691d691 (diff) | |
download | redis-62d774e5ba6056be39012ecedb88c3fec10304fb.tar.gz |
Use element rank instead of iterating in ZCOUNT
Diffstat (limited to 'src/t_zset.c')
-rw-r--r-- | src/t_zset.c | 75 |
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) { |