Skip to content

Commit 50c55df

Browse files
committed
ZRANGEBYSCORE implemented. Redis got range queries!
1 parent 9d60e6e commit 50c55df

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed

redis-cli.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ static struct redisCommand cmdTable[] = {
9292
{"zadd",4,REDIS_CMD_BULK},
9393
{"zrem",3,REDIS_CMD_BULK},
9494
{"zrange",4,REDIS_CMD_INLINE},
95+
{"zrangebyscore",4,REDIS_CMD_INLINE},
9596
{"zrevrange",4,REDIS_CMD_INLINE},
9697
{"zlen",2,REDIS_CMD_INLINE},
9798
{"incrby",3,REDIS_CMD_INLINE},

redis.c

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ static void msetCommand(redisClient *c);
444444
static void msetnxCommand(redisClient *c);
445445
static void zaddCommand(redisClient *c);
446446
static void zrangeCommand(redisClient *c);
447+
static void zrangebyscoreCommand(redisClient *c);
447448
static void zrevrangeCommand(redisClient *c);
448449
static void zlenCommand(redisClient *c);
449450
static void zremCommand(redisClient *c);
@@ -488,6 +489,7 @@ static struct redisCommand cmdTable[] = {
488489
{"zadd",zaddCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
489490
{"zrem",zremCommand,3,REDIS_CMD_BULK},
490491
{"zrange",zrangeCommand,4,REDIS_CMD_INLINE},
492+
{"zrangebyscore",zrangebyscoreCommand,4,REDIS_CMD_INLINE},
491493
{"zrevrange",zrevrangeCommand,4,REDIS_CMD_INLINE},
492494
{"zlen",zlenCommand,2,REDIS_CMD_INLINE},
493495
{"incrby",incrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
@@ -3885,6 +3887,7 @@ static void zslInsert(zskiplist *zsl, double score, robj *obj) {
38853887
zsl->length++;
38863888
}
38873889

3890+
/* Delete an element with matching score/object from the skiplist. */
38883891
static int zslDelete(zskiplist *zsl, double score, robj *obj) {
38893892
zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
38903893
int i;
@@ -3901,7 +3904,7 @@ static int zslDelete(zskiplist *zsl, double score, robj *obj) {
39013904
/* We may have multiple elements with the same score, what we need
39023905
* is to find the element with both the right score and object. */
39033906
x = x->forward[0];
3904-
if (compareStringObjects(x->obj,obj) == 0) {
3907+
if (x && score == x->score && compareStringObjects(x->obj,obj) == 0) {
39053908
for (i = 0; i < zsl->level; i++) {
39063909
if (update[i]->forward[i] != x) break;
39073910
update[i]->forward[i] = x->forward[i];
@@ -3923,6 +3926,22 @@ static int zslDelete(zskiplist *zsl, double score, robj *obj) {
39233926
return 0; /* not found */
39243927
}
39253928

3929+
/* Find the first node having a score equal or greater than the specified one.
3930+
* Returns NULL if there is no match. */
3931+
static zskiplistNode *zslFirstWithScore(zskiplist *zsl, double score) {
3932+
zskiplistNode *x;
3933+
int i;
3934+
3935+
x = zsl->header;
3936+
for (i = zsl->level-1; i >= 0; i--) {
3937+
while (x->forward[i] && x->forward[i]->score < score)
3938+
x = x->forward[i];
3939+
}
3940+
/* We may have multiple elements with the same score, what we need
3941+
* is to find the element with both the right score and object. */
3942+
return x->forward[0];
3943+
}
3944+
39263945
/* The actual Z-commands implementations */
39273946

39283947
static void zaddCommand(redisClient *c) {
@@ -4076,6 +4095,52 @@ static void zrevrangeCommand(redisClient *c) {
40764095
zrangeGenericCommand(c,1);
40774096
}
40784097

4098+
static void zrangebyscoreCommand(redisClient *c) {
4099+
robj *o;
4100+
double min = strtod(c->argv[2]->ptr,NULL);
4101+
double max = strtod(c->argv[3]->ptr,NULL);
4102+
4103+
o = lookupKeyRead(c->db,c->argv[1]);
4104+
if (o == NULL) {
4105+
addReply(c,shared.nullmultibulk);
4106+
} else {
4107+
if (o->type != REDIS_ZSET) {
4108+
addReply(c,shared.wrongtypeerr);
4109+
} else {
4110+
zset *zsetobj = o->ptr;
4111+
zskiplist *zsl = zsetobj->zsl;
4112+
zskiplistNode *ln;
4113+
robj *ele, *lenobj;
4114+
unsigned int rangelen = 0;
4115+
4116+
/* Get the first node with the score >= min */
4117+
ln = zslFirstWithScore(zsl,min);
4118+
if (ln == NULL) {
4119+
/* No element matching the speciifed interval */
4120+
addReply(c,shared.emptymultibulk);
4121+
return;
4122+
}
4123+
4124+
/* We don't know in advance how many matching elements there
4125+
* are in the list, so we push this object that will represent
4126+
* the multi-bulk length in the output buffer, and will "fix"
4127+
* it later */
4128+
lenobj = createObject(REDIS_STRING,NULL);
4129+
addReply(c,lenobj);
4130+
4131+
while(ln->score <= max) {
4132+
ele = ln->obj;
4133+
addReplyBulkLen(c,ele);
4134+
addReply(c,ele);
4135+
addReply(c,shared.crlf);
4136+
ln = ln->forward[0];
4137+
rangelen++;
4138+
}
4139+
lenobj->ptr = sdscatprintf(sdsempty(),"*%d\r\n",rangelen);
4140+
}
4141+
}
4142+
}
4143+
40794144
static void zlenCommand(redisClient *c) {
40804145
robj *o;
40814146
zset *zs;

0 commit comments

Comments
 (0)