summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--redis-cli.c1
-rw-r--r--redis.c67
2 files changed, 67 insertions, 1 deletions
diff --git a/redis-cli.c b/redis-cli.c
index 54867fabd..46450f6b3 100644
--- a/redis-cli.c
+++ b/redis-cli.c
@@ -92,6 +92,7 @@ static struct redisCommand cmdTable[] = {
{"zadd",4,REDIS_CMD_BULK},
{"zrem",3,REDIS_CMD_BULK},
{"zrange",4,REDIS_CMD_INLINE},
+ {"zrangebyscore",4,REDIS_CMD_INLINE},
{"zrevrange",4,REDIS_CMD_INLINE},
{"zlen",2,REDIS_CMD_INLINE},
{"incrby",3,REDIS_CMD_INLINE},
diff --git a/redis.c b/redis.c
index 1c07dbc2f..09237345f 100644
--- a/redis.c
+++ b/redis.c
@@ -444,6 +444,7 @@ static void msetCommand(redisClient *c);
static void msetnxCommand(redisClient *c);
static void zaddCommand(redisClient *c);
static void zrangeCommand(redisClient *c);
+static void zrangebyscoreCommand(redisClient *c);
static void zrevrangeCommand(redisClient *c);
static void zlenCommand(redisClient *c);
static void zremCommand(redisClient *c);
@@ -488,6 +489,7 @@ static struct redisCommand cmdTable[] = {
{"zadd",zaddCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
{"zrem",zremCommand,3,REDIS_CMD_BULK},
{"zrange",zrangeCommand,4,REDIS_CMD_INLINE},
+ {"zrangebyscore",zrangebyscoreCommand,4,REDIS_CMD_INLINE},
{"zrevrange",zrevrangeCommand,4,REDIS_CMD_INLINE},
{"zlen",zlenCommand,2,REDIS_CMD_INLINE},
{"incrby",incrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
@@ -3885,6 +3887,7 @@ static void zslInsert(zskiplist *zsl, double score, robj *obj) {
zsl->length++;
}
+/* Delete an element with matching score/object from the skiplist. */
static int zslDelete(zskiplist *zsl, double score, robj *obj) {
zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
int i;
@@ -3901,7 +3904,7 @@ static int zslDelete(zskiplist *zsl, double score, robj *obj) {
/* We may have multiple elements with the same score, what we need
* is to find the element with both the right score and object. */
x = x->forward[0];
- if (compareStringObjects(x->obj,obj) == 0) {
+ if (x && score == x->score && compareStringObjects(x->obj,obj) == 0) {
for (i = 0; i < zsl->level; i++) {
if (update[i]->forward[i] != x) break;
update[i]->forward[i] = x->forward[i];
@@ -3923,6 +3926,22 @@ static int zslDelete(zskiplist *zsl, double score, robj *obj) {
return 0; /* not found */
}
+/* Find the first node having a score equal or greater than the specified one.
+ * Returns NULL if there is no match. */
+static zskiplistNode *zslFirstWithScore(zskiplist *zsl, double score) {
+ zskiplistNode *x;
+ int i;
+
+ x = zsl->header;
+ for (i = zsl->level-1; i >= 0; i--) {
+ while (x->forward[i] && x->forward[i]->score < score)
+ x = x->forward[i];
+ }
+ /* We may have multiple elements with the same score, what we need
+ * is to find the element with both the right score and object. */
+ return x->forward[0];
+}
+
/* The actual Z-commands implementations */
static void zaddCommand(redisClient *c) {
@@ -4076,6 +4095,52 @@ static void zrevrangeCommand(redisClient *c) {
zrangeGenericCommand(c,1);
}
+static void zrangebyscoreCommand(redisClient *c) {
+ robj *o;
+ double min = strtod(c->argv[2]->ptr,NULL);
+ double max = strtod(c->argv[3]->ptr,NULL);
+
+ o = lookupKeyRead(c->db,c->argv[1]);
+ if (o == NULL) {
+ addReply(c,shared.nullmultibulk);
+ } else {
+ if (o->type != REDIS_ZSET) {
+ addReply(c,shared.wrongtypeerr);
+ } else {
+ zset *zsetobj = o->ptr;
+ zskiplist *zsl = zsetobj->zsl;
+ zskiplistNode *ln;
+ robj *ele, *lenobj;
+ unsigned int rangelen = 0;
+
+ /* Get the first node with the score >= min */
+ ln = zslFirstWithScore(zsl,min);
+ if (ln == NULL) {
+ /* No element matching the speciifed interval */
+ 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 */
+ lenobj = createObject(REDIS_STRING,NULL);
+ addReply(c,lenobj);
+
+ while(ln->score <= max) {
+ ele = ln->obj;
+ addReplyBulkLen(c,ele);
+ addReply(c,ele);
+ addReply(c,shared.crlf);
+ ln = ln->forward[0];
+ rangelen++;
+ }
+ lenobj->ptr = sdscatprintf(sdsempty(),"*%d\r\n",rangelen);
+ }
+ }
+}
+
static void zlenCommand(redisClient *c) {
robj *o;
zset *zs;