mirror of
https://github.com/fluencelabs/redis
synced 2025-03-18 08:30:51 +00:00
Support dual encoding for ZRANGE
This commit is contained in:
parent
0f23eb3b10
commit
5d1b4fb698
125
src/t_zset.c
125
src/t_zset.c
@ -666,6 +666,22 @@ unsigned long zzlDeleteRangeByScore(robj *zobj, zrangespec range) {
|
|||||||
return deleted;
|
return deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
* Common sorted set API
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
int zsLength(robj *zobj) {
|
||||||
|
int length = -1;
|
||||||
|
if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
|
||||||
|
length = zzlLength(zobj);
|
||||||
|
} else if (zobj->encoding == REDIS_ENCODING_RAW) {
|
||||||
|
length = ((zset*)zobj->ptr)->zsl->length;
|
||||||
|
} else {
|
||||||
|
redisPanic("Unknown sorted set encoding");
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
* Sorted set commands
|
* Sorted set commands
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
@ -1135,16 +1151,13 @@ void zinterstoreCommand(redisClient *c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void zrangeGenericCommand(redisClient *c, int reverse) {
|
void zrangeGenericCommand(redisClient *c, int reverse) {
|
||||||
robj *o;
|
robj *key = c->argv[1];
|
||||||
|
robj *zobj;
|
||||||
|
int withscores = 0;
|
||||||
long start;
|
long start;
|
||||||
long end;
|
long end;
|
||||||
int withscores = 0;
|
|
||||||
int llen;
|
int llen;
|
||||||
int rangelen, j;
|
int rangelen;
|
||||||
zset *zsetobj;
|
|
||||||
zskiplist *zsl;
|
|
||||||
zskiplistNode *ln;
|
|
||||||
robj *ele;
|
|
||||||
|
|
||||||
if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != REDIS_OK) ||
|
if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != REDIS_OK) ||
|
||||||
(getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != REDIS_OK)) return;
|
(getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != REDIS_OK)) return;
|
||||||
@ -1156,13 +1169,11 @@ void zrangeGenericCommand(redisClient *c, int reverse) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
|
if ((zobj = lookupKeyReadOrReply(c,key,shared.emptymultibulk)) == NULL
|
||||||
|| checkType(c,o,REDIS_ZSET)) return;
|
|| checkType(c,zobj,REDIS_ZSET)) return;
|
||||||
zsetobj = o->ptr;
|
|
||||||
zsl = zsetobj->zsl;
|
|
||||||
llen = zsl->length;
|
|
||||||
|
|
||||||
/* convert negative indexes */
|
/* Sanitize indexes. */
|
||||||
|
llen = zsLength(zobj);
|
||||||
if (start < 0) start = llen+start;
|
if (start < 0) start = llen+start;
|
||||||
if (end < 0) end = llen+end;
|
if (end < 0) end = llen+end;
|
||||||
if (start < 0) start = 0;
|
if (start < 0) start = 0;
|
||||||
@ -1176,23 +1187,79 @@ void zrangeGenericCommand(redisClient *c, int reverse) {
|
|||||||
if (end >= llen) end = llen-1;
|
if (end >= llen) end = llen-1;
|
||||||
rangelen = (end-start)+1;
|
rangelen = (end-start)+1;
|
||||||
|
|
||||||
/* check if starting point is trivial, before searching
|
|
||||||
* the element in log(N) time */
|
|
||||||
if (reverse) {
|
|
||||||
ln = start == 0 ? zsl->tail : zslGetElementByRank(zsl, llen-start);
|
|
||||||
} else {
|
|
||||||
ln = start == 0 ?
|
|
||||||
zsl->header->level[0].forward : zslGetElementByRank(zsl, start+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the result in form of a multi-bulk reply */
|
/* Return the result in form of a multi-bulk reply */
|
||||||
addReplyMultiBulkLen(c,withscores ? (rangelen*2) : rangelen);
|
addReplyMultiBulkLen(c, withscores ? (rangelen*2) : rangelen);
|
||||||
for (j = 0; j < rangelen; j++) {
|
|
||||||
ele = ln->obj;
|
if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
|
||||||
addReplyBulk(c,ele);
|
unsigned char *zl = zobj->ptr;
|
||||||
if (withscores)
|
unsigned char *eptr, *sptr;
|
||||||
addReplyDouble(c,ln->score);
|
unsigned char *vstr;
|
||||||
ln = reverse ? ln->backward : ln->level[0].forward;
|
unsigned int vlen;
|
||||||
|
long long vlong;
|
||||||
|
|
||||||
|
if (reverse)
|
||||||
|
eptr = ziplistIndex(zl,-2-(2*start));
|
||||||
|
else
|
||||||
|
eptr = ziplistIndex(zl,2*start);
|
||||||
|
|
||||||
|
while (rangelen--) {
|
||||||
|
redisAssert(eptr != NULL);
|
||||||
|
redisAssert(ziplistGet(eptr,&vstr,&vlen,&vlong));
|
||||||
|
if (vstr == NULL)
|
||||||
|
addReplyBulkLongLong(c,vlong);
|
||||||
|
else
|
||||||
|
addReplyBulkCBuffer(c,vstr,vlen);
|
||||||
|
|
||||||
|
if (withscores) {
|
||||||
|
sptr = ziplistNext(zl,eptr);
|
||||||
|
redisAssert(sptr != NULL);
|
||||||
|
addReplyDouble(c,zzlGetScore(sptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reverse) {
|
||||||
|
/* Move to previous element by moving to the score of previous
|
||||||
|
* element. When NULL, we know there also is no element. */
|
||||||
|
sptr = ziplistPrev(zl,eptr);
|
||||||
|
if (sptr != NULL) {
|
||||||
|
eptr = ziplistPrev(zl,sptr);
|
||||||
|
redisAssert(eptr != NULL);
|
||||||
|
} else {
|
||||||
|
eptr = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sptr = ziplistNext(zl,eptr);
|
||||||
|
redisAssert(sptr != NULL);
|
||||||
|
eptr = ziplistNext(zl,sptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (zobj->encoding == REDIS_ENCODING_RAW) {
|
||||||
|
zset *zs = zobj->ptr;
|
||||||
|
zskiplist *zsl = zs->zsl;
|
||||||
|
zskiplistNode *ln;
|
||||||
|
robj *ele;
|
||||||
|
|
||||||
|
/* Check if starting point is trivial, before doing log(N) lookup. */
|
||||||
|
if (reverse) {
|
||||||
|
ln = zsl->tail;
|
||||||
|
if (start > 0)
|
||||||
|
ln = zslGetElementByRank(zsl,llen-start);
|
||||||
|
} else {
|
||||||
|
ln = zsl->header->level[0].forward;
|
||||||
|
if (start > 0)
|
||||||
|
ln = zslGetElementByRank(zsl,start+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(rangelen--) {
|
||||||
|
redisAssert(ln != NULL);
|
||||||
|
ele = ln->obj;
|
||||||
|
addReplyBulk(c,ele);
|
||||||
|
if (withscores)
|
||||||
|
addReplyDouble(c,ln->score);
|
||||||
|
ln = reverse ? ln->backward : ln->level[0].forward;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
redisPanic("Unknown sorted set encoding");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user