mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 16:18:28 -05:00
ZREMRANGEBYLEX implemented.
This commit is contained in:
parent
8827dc4eec
commit
78954ca3a2
@ -171,6 +171,7 @@ struct redisCommand redisCommandTable[] = {
|
|||||||
{"zrem",zremCommand,-3,"w",0,NULL,1,1,1,0,0},
|
{"zrem",zremCommand,-3,"w",0,NULL,1,1,1,0,0},
|
||||||
{"zremrangebyscore",zremrangebyscoreCommand,4,"w",0,NULL,1,1,1,0,0},
|
{"zremrangebyscore",zremrangebyscoreCommand,4,"w",0,NULL,1,1,1,0,0},
|
||||||
{"zremrangebyrank",zremrangebyrankCommand,4,"w",0,NULL,1,1,1,0,0},
|
{"zremrangebyrank",zremrangebyrankCommand,4,"w",0,NULL,1,1,1,0,0},
|
||||||
|
{"zremrangebylex",zremrangebylexCommand,4,"w",0,NULL,1,1,1,0,0},
|
||||||
{"zunionstore",zunionstoreCommand,-4,"wm",0,zunionInterGetKeys,0,0,0,0,0},
|
{"zunionstore",zunionstoreCommand,-4,"wm",0,zunionInterGetKeys,0,0,0,0,0},
|
||||||
{"zinterstore",zinterstoreCommand,-4,"wm",0,zunionInterGetKeys,0,0,0,0,0},
|
{"zinterstore",zinterstoreCommand,-4,"wm",0,zunionInterGetKeys,0,0,0,0,0},
|
||||||
{"zrange",zrangeCommand,-4,"r",0,NULL,1,1,1,0,0},
|
{"zrange",zrangeCommand,-4,"r",0,NULL,1,1,1,0,0},
|
||||||
|
@ -1406,6 +1406,7 @@ void zcardCommand(redisClient *c);
|
|||||||
void zremCommand(redisClient *c);
|
void zremCommand(redisClient *c);
|
||||||
void zscoreCommand(redisClient *c);
|
void zscoreCommand(redisClient *c);
|
||||||
void zremrangebyscoreCommand(redisClient *c);
|
void zremrangebyscoreCommand(redisClient *c);
|
||||||
|
void zremrangebylexCommand(redisClient *c);
|
||||||
void multiCommand(redisClient *c);
|
void multiCommand(redisClient *c);
|
||||||
void execCommand(redisClient *c);
|
void execCommand(redisClient *c);
|
||||||
void discardCommand(redisClient *c);
|
void discardCommand(redisClient *c);
|
||||||
|
75
src/t_zset.c
75
src/t_zset.c
@ -52,6 +52,9 @@
|
|||||||
#include "redis.h"
|
#include "redis.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
static int zslLexValueGteMin(robj *value, zlexrangespec *spec);
|
||||||
|
static int zslLexValueLteMax(robj *value, zlexrangespec *spec);
|
||||||
|
|
||||||
zskiplistNode *zslCreateNode(int level, double score, robj *obj) {
|
zskiplistNode *zslCreateNode(int level, double score, robj *obj) {
|
||||||
zskiplistNode *zn = zmalloc(sizeof(*zn)+level*sizeof(struct zskiplistLevel));
|
zskiplistNode *zn = zmalloc(sizeof(*zn)+level*sizeof(struct zskiplistLevel));
|
||||||
zn->score = score;
|
zn->score = score;
|
||||||
@ -319,6 +322,35 @@ unsigned long zslDeleteRangeByScore(zskiplist *zsl, zrangespec *range, dict *dic
|
|||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long zslDeleteRangeByLex(zskiplist *zsl, zlexrangespec *range, dict *dict) {
|
||||||
|
zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
|
||||||
|
unsigned long removed = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
|
||||||
|
x = zsl->header;
|
||||||
|
for (i = zsl->level-1; i >= 0; i--) {
|
||||||
|
while (x->level[i].forward &&
|
||||||
|
!zslLexValueGteMin(x->level[i].forward->obj,range))
|
||||||
|
x = x->level[i].forward;
|
||||||
|
update[i] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Current node is the last with score < or <= min. */
|
||||||
|
x = x->level[0].forward;
|
||||||
|
|
||||||
|
/* Delete nodes while in range. */
|
||||||
|
while (x && zslLexValueLteMax(x->obj,range)) {
|
||||||
|
zskiplistNode *next = x->level[0].forward;
|
||||||
|
zslDeleteNode(zsl,x,update);
|
||||||
|
dictDelete(dict,x->obj);
|
||||||
|
zslFreeNode(x);
|
||||||
|
removed++;
|
||||||
|
x = next;
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
/* Delete all the elements with rank between start and end from the skiplist.
|
/* Delete all the elements with rank between start and end from the skiplist.
|
||||||
* Start and end are inclusive. Note that start and end need to be 1-based */
|
* Start and end are inclusive. Note that start and end need to be 1-based */
|
||||||
unsigned long zslDeleteRangeByRank(zskiplist *zsl, unsigned int start, unsigned int end, dict *dict) {
|
unsigned long zslDeleteRangeByRank(zskiplist *zsl, unsigned int start, unsigned int end, dict *dict) {
|
||||||
@ -1008,6 +1040,33 @@ unsigned char *zzlDeleteRangeByScore(unsigned char *zl, zrangespec *range, unsig
|
|||||||
return zl;
|
return zl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned char *zzlDeleteRangeByLex(unsigned char *zl, zlexrangespec *range, unsigned long *deleted) {
|
||||||
|
unsigned char *eptr, *sptr;
|
||||||
|
unsigned long num = 0;
|
||||||
|
|
||||||
|
if (deleted != NULL) *deleted = 0;
|
||||||
|
|
||||||
|
eptr = zzlFirstInLexRange(zl,range);
|
||||||
|
if (eptr == NULL) return zl;
|
||||||
|
|
||||||
|
/* When the tail of the ziplist is deleted, eptr will point to the sentinel
|
||||||
|
* byte and ziplistNext will return NULL. */
|
||||||
|
while ((sptr = ziplistNext(zl,eptr)) != NULL) {
|
||||||
|
if (zzlLexValueLteMax(eptr,range)) {
|
||||||
|
/* Delete both the element and the score. */
|
||||||
|
zl = ziplistDelete(zl,&eptr);
|
||||||
|
zl = ziplistDelete(zl,&eptr);
|
||||||
|
num++;
|
||||||
|
} else {
|
||||||
|
/* No longer in range. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deleted != NULL) *deleted = num;
|
||||||
|
return zl;
|
||||||
|
}
|
||||||
|
|
||||||
/* Delete all the elements with rank between start and end from the skiplist.
|
/* Delete all the elements with rank between start and end from the skiplist.
|
||||||
* Start and end are inclusive. Note that start and end need to be 1-based */
|
* Start and end are inclusive. Note that start and end need to be 1-based */
|
||||||
unsigned char *zzlDeleteRangeByRank(unsigned char *zl, unsigned int start, unsigned int end, unsigned long *deleted) {
|
unsigned char *zzlDeleteRangeByRank(unsigned char *zl, unsigned int start, unsigned int end, unsigned long *deleted) {
|
||||||
@ -1325,6 +1384,7 @@ void zremrangeGenericCommand(redisClient *c, int rangetype) {
|
|||||||
int keyremoved = 0;
|
int keyremoved = 0;
|
||||||
unsigned long deleted;
|
unsigned long deleted;
|
||||||
zrangespec range;
|
zrangespec range;
|
||||||
|
zlexrangespec lexrange;
|
||||||
long start, end, llen;
|
long start, end, llen;
|
||||||
|
|
||||||
/* Step 1: Parse the range. */
|
/* Step 1: Parse the range. */
|
||||||
@ -1337,6 +1397,11 @@ void zremrangeGenericCommand(redisClient *c, int rangetype) {
|
|||||||
addReplyError(c,"min or max is not a float");
|
addReplyError(c,"min or max is not a float");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (rangetype == ZRANGE_LEX) {
|
||||||
|
if (zslParseLexRange(c->argv[2],c->argv[3],&lexrange) != REDIS_OK) {
|
||||||
|
addReplyError(c,"min or max not valid string range item");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step 2: Lookup & range sanity checks if needed. */
|
/* Step 2: Lookup & range sanity checks if needed. */
|
||||||
@ -1368,6 +1433,9 @@ void zremrangeGenericCommand(redisClient *c, int rangetype) {
|
|||||||
case ZRANGE_SCORE:
|
case ZRANGE_SCORE:
|
||||||
zobj->ptr = zzlDeleteRangeByScore(zobj->ptr,&range,&deleted);
|
zobj->ptr = zzlDeleteRangeByScore(zobj->ptr,&range,&deleted);
|
||||||
break;
|
break;
|
||||||
|
case ZRANGE_LEX:
|
||||||
|
zobj->ptr = zzlDeleteRangeByLex(zobj->ptr,&lexrange,&deleted);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (zzlLength(zobj->ptr) == 0) {
|
if (zzlLength(zobj->ptr) == 0) {
|
||||||
dbDelete(c->db,key);
|
dbDelete(c->db,key);
|
||||||
@ -1382,6 +1450,9 @@ void zremrangeGenericCommand(redisClient *c, int rangetype) {
|
|||||||
case ZRANGE_SCORE:
|
case ZRANGE_SCORE:
|
||||||
deleted = zslDeleteRangeByScore(zs->zsl,&range,zs->dict);
|
deleted = zslDeleteRangeByScore(zs->zsl,&range,zs->dict);
|
||||||
break;
|
break;
|
||||||
|
case ZRANGE_LEX:
|
||||||
|
deleted = zslDeleteRangeByLex(zs->zsl,&lexrange,zs->dict);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (htNeedsResize(zs->dict)) dictResize(zs->dict);
|
if (htNeedsResize(zs->dict)) dictResize(zs->dict);
|
||||||
if (dictSize(zs->dict) == 0) {
|
if (dictSize(zs->dict) == 0) {
|
||||||
@ -1412,6 +1483,10 @@ void zremrangebyscoreCommand(redisClient *c) {
|
|||||||
zremrangeGenericCommand(c,ZRANGE_SCORE);
|
zremrangeGenericCommand(c,ZRANGE_SCORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void zremrangebylexCommand(redisClient *c) {
|
||||||
|
zremrangeGenericCommand(c,ZRANGE_LEX);
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
robj *subject;
|
robj *subject;
|
||||||
int type; /* Set, sorted set */
|
int type; /* Set, sorted set */
|
||||||
|
Loading…
Reference in New Issue
Block a user