提交 083f5277 编写于 作者: A antirez

Modules: zset iterator redesign #1.

上级 d9981708
...@@ -65,13 +65,25 @@ struct RedisModuleKey { ...@@ -65,13 +65,25 @@ struct RedisModuleKey {
robj *value; /* Value object, or NULL if the key was not found. */ robj *value; /* Value object, or NULL if the key was not found. */
void *iter; /* Iterator. */ void *iter; /* Iterator. */
int mode; /* Opening mode. */ int mode; /* Opening mode. */
/* Zset iterator. */ /* Zset iterator. */
RedisModuleZsetRange *zr; /* Zset iterator range passed by user. */ uint32_t ztype; /* REDISMODULE_ZSET_RANGE_* */
zrangespec zrs; /* Score range. */
zlexrangespec zlrs; /* Lex range. */
uint32_t zstart; /* Start pos for positional ranges. */
uint32_t zend; /* End pos for positional ranges. */
void *zcurrent; /* Zset iterator current node. */ void *zcurrent; /* Zset iterator current node. */
int zer; /* Zset iterator end reached flag (true if end was reached). */ int zer; /* Zset iterator end reached flag
(true if end was reached). */
}; };
typedef struct RedisModuleKey RedisModuleKey; typedef struct RedisModuleKey RedisModuleKey;
/* RedisModuleKey 'ztype' values. */
#define REDISMODULE_ZSET_RANGE_NONE 0 /* This must always be 0. */
#define REDISMODULE_ZSET_RANGE_LEX 1
#define REDISMODULE_ZSET_RANGE_SCORE 2
#define REDISMODULE_ZSET_RANGE_POS 3
/* Function pointer type of a function representing a command inside /* Function pointer type of a function representing a command inside
* a Redis module. */ * a Redis module. */
typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, void **argv, int argc); typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, void **argv, int argc);
...@@ -707,6 +719,7 @@ void RM_CloseKey(RedisModuleKey *key) { ...@@ -707,6 +719,7 @@ void RM_CloseKey(RedisModuleKey *key) {
if (key == NULL) return; if (key == NULL) return;
if (key->mode & REDISMODULE_WRITE) signalModifiedKey(key->db,key->key); if (key->mode & REDISMODULE_WRITE) signalModifiedKey(key->db,key->key);
/* TODO: if (key->iter) RM_KeyIteratorStop(kp); */ /* TODO: if (key->iter) RM_KeyIteratorStop(kp); */
RM_ZsetRangeStop(key);
decrRefCount(key->key); decrRefCount(key->key);
autoMemoryFreed(key->ctx,REDISMODULE_AM_KEY,key); autoMemoryFreed(key->ctx,REDISMODULE_AM_KEY,key);
zfree(key); zfree(key);
...@@ -1083,10 +1096,13 @@ int RM_ZsetScore(RedisModuleKey *key, RedisModuleString *ele, double *score) { ...@@ -1083,10 +1096,13 @@ int RM_ZsetScore(RedisModuleKey *key, RedisModuleString *ele, double *score) {
/* Stop a sorted set iteration. */ /* Stop a sorted set iteration. */
void RM_ZsetRangeStop(RedisModuleKey *key) { void RM_ZsetRangeStop(RedisModuleKey *key) {
/* Free resources if needed. */
if (key->ztype == REDISMODULE_ZSET_RANGE_LEX)
zslFreeLexRange(&key->zlrs);
/* Setup sensible values so that misused iteration API calls when an /* Setup sensible values so that misused iteration API calls when an
* iterator is not active will result into something more sensible * iterator is not active will result into something more sensible
* than crashing. */ * than crashing. */
key->zr = NULL; key->ztype = REDISMODULE_ZSET_RANGE_NONE;
key->zcurrent = NULL; key->zcurrent = NULL;
key->zer = 1; key->zer = 1;
} }
...@@ -1096,59 +1112,55 @@ int RM_ZsetRangeEndReached(RedisModuleKey *key) { ...@@ -1096,59 +1112,55 @@ int RM_ZsetRangeEndReached(RedisModuleKey *key) {
return key->zer; return key->zer;
} }
/* Helper function for RM_ZsetFirstInRange() and RM_ZsetLastInRange(). /* Helper function for RM_ZsetFirstInScoreRange() and RM_ZsetLastInScoreRange().
* Setup the sorted set iteration according to the specified range * Setup the sorted set iteration according to the specified score range
* (see the functions calling it for more info). If first is true the * (see the functions calling it for more info). If 'first' is true the
* first element in the range is used as a starting point for the iterator * first element in the range is used as a starting point for the iterator
* otherwise the last. Return REDISMODULE_OK on success otherwise * otherwise the last. Return REDISMODULE_OK on success otherwise
* REDISMODULE_ERR. */ * REDISMODULE_ERR. */
int zsetInitRange(RedisModuleKey *key, RedisModuleZsetRange *zr, int first) { int zsetInitScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex, int first) {
if (!key->value || key->value->type != OBJ_ZSET) return REDISMODULE_ERR; if (!key->value || key->value->type != OBJ_ZSET) return REDISMODULE_ERR;
key->zr = zr;
key->zcurrent = NULL; RM_ZsetRangeStop(key);
key->ztype = REDISMODULE_ZSET_RANGE_SCORE;
key->zer = 0; key->zer = 0;
if (zr->type == REDISMODULE_ZSET_RANGE_SCORE) {
/* Setup the range structure used by the sorted set core implementation /* Setup the range structure used by the sorted set core implementation
* in order to seek at the specified element. */ * in order to seek at the specified element. */
zrangespec zrs; zrangespec *zrs = &key->zrs;
zrs.min = zr->score_start; zrs->min = min;
zrs.max = zr->score_end; zrs->max = max;
zrs.minex = (zr->flags & REDISMODULE_ZSET_RANGE_START_EX) != 0; zrs->minex = minex;
zrs.maxex = (zr->flags & REDISMODULE_ZSET_RANGE_END_EX) != 0; zrs->maxex = maxex;
if (key->value->encoding == OBJ_ENCODING_ZIPLIST) { if (key->value->encoding == OBJ_ENCODING_ZIPLIST) {
key->zcurrent = first ? zzlFirstInRange(key->value->ptr,&zrs) : key->zcurrent = first ? zzlFirstInRange(key->value->ptr,zrs) :
zzlLastInRange(key->value->ptr,&zrs); zzlLastInRange(key->value->ptr,zrs);
} else if (key->value->encoding == OBJ_ENCODING_SKIPLIST) { } else if (key->value->encoding == OBJ_ENCODING_SKIPLIST) {
zset *zs = key->value->ptr; zset *zs = key->value->ptr;
zskiplist *zsl = zs->zsl; zskiplist *zsl = zs->zsl;
key->zcurrent = first ? zslFirstInRange(zsl,&zrs) : key->zcurrent = first ? zslFirstInRange(zsl,zrs) :
zslLastInRange(zsl,&zrs); zslLastInRange(zsl,zrs);
} else { } else {
serverPanic("Unsupported zset encoding"); serverPanic("Unsupported zset encoding");
} }
if (key->zcurrent == NULL) key->zer = 1; if (key->zcurrent == NULL) key->zer = 1;
return REDISMODULE_OK; return REDISMODULE_OK;
} else {
return REDISMODULE_ERR;
}
} }
/* Setup a sorted set iterator seeking the first element in the specified /* Setup a sorted set iterator seeking the first element in the specified
* range. Returns REDISMODULE_OK if the iterator was correctly initialized * range. Returns REDISMODULE_OK if the iterator was correctly initialized
* otherwise REDISMODULE_ERR is returned in the following conditions: * otherwise REDISMODULE_ERR is returned in the following conditions:
* *
* 1. The value stored at key is not a sorted set or the key is empty. * 1. The value stored at key is not a sorted set or the key is empty. */
* 2. The iterator type is unrecognized. */ int RM_ZsetFirstInScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex) {
int RM_ZsetFirstInRange(RedisModuleKey *key, RedisModuleZsetRange *zr) { return zsetInitScoreRange(key,min,max,minex,maxex,1);
return zsetInitRange(key,zr,1);
} }
/* Exactly like RM_ZsetFirstInRange() but the last element of the range /* Exactly like RedisModule_ZsetFirstInScoreRange() but the last element of
* is seeked instead. */ * the range is seeked instead. */
int RM_ZsetLastInRange(RedisModuleKey *key, RedisModuleZsetRange *zr) { int RM_ZsetLastInScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex) {
return zsetInitRange(key,zr,0); return zsetInitScoreRange(key,min,max,minex,maxex,0);
} }
/* Return the current sorted set element of an active sorted set iterator /* Return the current sorted set element of an active sorted set iterator
...@@ -1182,17 +1194,7 @@ RedisModuleString *RM_ZsetRangeCurrentElement(RedisModuleKey *key, double *score ...@@ -1182,17 +1194,7 @@ RedisModuleString *RM_ZsetRangeCurrentElement(RedisModuleKey *key, double *score
* a next element, 0 if we are already at the latest element or the range * a next element, 0 if we are already at the latest element or the range
* does not include any item at all. */ * does not include any item at all. */
int RM_ZsetRangeNext(RedisModuleKey *key) { int RM_ZsetRangeNext(RedisModuleKey *key) {
if (!key->zr || !key->zcurrent) return 0; /* No active iterator. */ if (!key->ztype || !key->zcurrent) return 0; /* No active iterator. */
zrangespec zrs;
/* Convert to core range structure. */
RedisModuleZsetRange *zr = key->zr;
if (zr->type == REDISMODULE_ZSET_RANGE_SCORE) {
zrs.min = zr->score_start;
zrs.max = zr->score_end;
zrs.minex = (zr->flags & REDISMODULE_ZSET_RANGE_START_EX) != 0;
zrs.maxex = (zr->flags & REDISMODULE_ZSET_RANGE_END_EX) != 0;
}
if (key->value->encoding == OBJ_ENCODING_ZIPLIST) { if (key->value->encoding == OBJ_ENCODING_ZIPLIST) {
unsigned char *zl = key->value->ptr; unsigned char *zl = key->value->ptr;
...@@ -1205,13 +1207,13 @@ int RM_ZsetRangeNext(RedisModuleKey *key) { ...@@ -1205,13 +1207,13 @@ int RM_ZsetRangeNext(RedisModuleKey *key) {
return 0; return 0;
} else { } else {
/* Are we still within the range? */ /* Are we still within the range? */
if (zr->type == REDISMODULE_ZSET_RANGE_SCORE) { if (key->ztype == REDISMODULE_ZSET_RANGE_SCORE) {
/* Fetch the next element score for the /* Fetch the next element score for the
* range check. */ * range check. */
unsigned char *saved_next = next; unsigned char *saved_next = next;
next = ziplistNext(zl,next); /* Skip next element. */ next = ziplistNext(zl,next); /* Skip next element. */
double score = zzlGetScore(next); /* Obtain the next score. */ double score = zzlGetScore(next); /* Obtain the next score. */
if (!zslValueLteMax(score,&zrs)) { if (!zslValueLteMax(score,&key->zrs)) {
key->zer = 1; key->zer = 1;
return 0; return 0;
} }
...@@ -1227,8 +1229,8 @@ int RM_ZsetRangeNext(RedisModuleKey *key) { ...@@ -1227,8 +1229,8 @@ int RM_ZsetRangeNext(RedisModuleKey *key) {
return 0; return 0;
} else { } else {
/* Are we still within the range? */ /* Are we still within the range? */
if (zr->type == REDISMODULE_ZSET_RANGE_SCORE && if (key->ztype == REDISMODULE_ZSET_RANGE_SCORE &&
!zslValueLteMax(ln->score,&zrs)) !zslValueLteMax(ln->score,&key->zrs))
{ {
key->zer = 1; key->zer = 1;
return 0; return 0;
...@@ -1245,17 +1247,7 @@ int RM_ZsetRangeNext(RedisModuleKey *key) { ...@@ -1245,17 +1247,7 @@ int RM_ZsetRangeNext(RedisModuleKey *key) {
* a previous element, 0 if we are already at the first element or the range * a previous element, 0 if we are already at the first element or the range
* does not include any item at all. */ * does not include any item at all. */
int RM_ZsetRangePrev(RedisModuleKey *key) { int RM_ZsetRangePrev(RedisModuleKey *key) {
if (!key->zr || !key->zcurrent) return 0; /* No active iterator. */ if (!key->ztype || !key->zcurrent) return 0; /* No active iterator. */
zrangespec zrs;
/* Convert to core range structure. */
RedisModuleZsetRange *zr = key->zr;
if (zr->type == REDISMODULE_ZSET_RANGE_SCORE) {
zrs.min = zr->score_start;
zrs.max = zr->score_end;
zrs.minex = (zr->flags & REDISMODULE_ZSET_RANGE_START_EX) != 0;
zrs.maxex = (zr->flags & REDISMODULE_ZSET_RANGE_END_EX) != 0;
}
if (key->value->encoding == OBJ_ENCODING_ZIPLIST) { if (key->value->encoding == OBJ_ENCODING_ZIPLIST) {
unsigned char *zl = key->value->ptr; unsigned char *zl = key->value->ptr;
...@@ -1268,13 +1260,13 @@ int RM_ZsetRangePrev(RedisModuleKey *key) { ...@@ -1268,13 +1260,13 @@ int RM_ZsetRangePrev(RedisModuleKey *key) {
return 0; return 0;
} else { } else {
/* Are we still within the range? */ /* Are we still within the range? */
if (zr->type == REDISMODULE_ZSET_RANGE_SCORE) { if (key->ztype == REDISMODULE_ZSET_RANGE_SCORE) {
/* Fetch the previous element score for the /* Fetch the previous element score for the
* range check. */ * range check. */
unsigned char *saved_prev = prev; unsigned char *saved_prev = prev;
prev = ziplistNext(zl,prev); /* Skip element to get the score. */ prev = ziplistNext(zl,prev); /* Skip element to get the score. */
double score = zzlGetScore(prev); /* Obtain the prev score. */ double score = zzlGetScore(prev); /* Obtain the prev score. */
if (!zslValueGteMin(score,&zrs)) { if (!zslValueGteMin(score,&key->zrs)) {
key->zer = 1; key->zer = 1;
return 0; return 0;
} }
...@@ -1290,8 +1282,8 @@ int RM_ZsetRangePrev(RedisModuleKey *key) { ...@@ -1290,8 +1282,8 @@ int RM_ZsetRangePrev(RedisModuleKey *key) {
return 0; return 0;
} else { } else {
/* Are we still within the range? */ /* Are we still within the range? */
if (zr->type == REDISMODULE_ZSET_RANGE_SCORE && if (key->ztype == REDISMODULE_ZSET_RANGE_SCORE &&
!zslValueGteMin(ln->score,&zrs)) !zslValueGteMin(ln->score,&key->zrs))
{ {
key->zer = 1; key->zer = 1;
return 0; return 0;
...@@ -1756,8 +1748,8 @@ void moduleRegisterCoreAPI(void) { ...@@ -1756,8 +1748,8 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API(ZsetScore); REGISTER_API(ZsetScore);
REGISTER_API(ZsetRem); REGISTER_API(ZsetRem);
REGISTER_API(ZsetRangeStop); REGISTER_API(ZsetRangeStop);
REGISTER_API(ZsetFirstInRange); REGISTER_API(ZsetFirstInScoreRange);
REGISTER_API(ZsetLastInRange); REGISTER_API(ZsetLastInScoreRange);
REGISTER_API(ZsetRangeCurrentElement); REGISTER_API(ZsetRangeCurrentElement);
REGISTER_API(ZsetRangeNext); REGISTER_API(ZsetRangeNext);
REGISTER_API(ZsetRangePrev); REGISTER_API(ZsetRangePrev);
......
...@@ -333,14 +333,13 @@ int HelloMoreExpire_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, ...@@ -333,14 +333,13 @@ int HelloMoreExpire_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
* another time backward. The two scores, returned as a two element array, * another time backward. The two scores, returned as a two element array,
* should match.*/ * should match.*/
int HelloZsumRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int HelloZsumRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
RedisModuleZsetRange zrange = REDISMODULE_ZSET_RANGE_INIT; double score_start, score_end;
zrange.type = REDISMODULE_ZSET_RANGE_SCORE;
if (RedisModule_StringToDouble(argv[2],&zrange.score_start) != REDISMODULE_OK || if (RedisModule_StringToDouble(argv[2],&score_start) != REDISMODULE_OK ||
RedisModule_StringToDouble(argv[3],&zrange.score_end) != REDISMODULE_OK) RedisModule_StringToDouble(argv[3],&score_end) != REDISMODULE_OK)
{ {
return RedisModule_ReplyWithError(ctx,"ERR invalid range"); return RedisModule_ReplyWithError(ctx,"ERR invalid range");
} }
zrange.flags = 0;
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1], RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE); REDISMODULE_READ|REDISMODULE_WRITE);
...@@ -351,7 +350,7 @@ int HelloZsumRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, i ...@@ -351,7 +350,7 @@ int HelloZsumRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, i
double scoresum_a = 0; double scoresum_a = 0;
double scoresum_b = 0; double scoresum_b = 0;
RedisModule_ZsetFirstInRange(key,&zrange); RedisModule_ZsetFirstInScoreRange(key,score_start,score_end,0,0);
while(!RedisModule_ZsetRangeEndReached(key)) { while(!RedisModule_ZsetRangeEndReached(key)) {
double score; double score;
RedisModuleString *ele = RedisModule_ZsetRangeCurrentElement(key,&score); RedisModuleString *ele = RedisModule_ZsetRangeCurrentElement(key,&score);
...@@ -361,7 +360,7 @@ int HelloZsumRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, i ...@@ -361,7 +360,7 @@ int HelloZsumRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, i
} }
RedisModule_ZsetRangeStop(key); RedisModule_ZsetRangeStop(key);
RedisModule_ZsetLastInRange(key,&zrange); RedisModule_ZsetLastInScoreRange(key,score_start,score_end,0,0);
while(!RedisModule_ZsetRangeEndReached(key)) { while(!RedisModule_ZsetRangeEndReached(key)) {
double score; double score;
RedisModuleString *ele = RedisModule_ZsetRangeCurrentElement(key,&score); RedisModuleString *ele = RedisModule_ZsetRangeCurrentElement(key,&score);
......
...@@ -50,31 +50,9 @@ ...@@ -50,31 +50,9 @@
/* Error messages. */ /* Error messages. */
#define REDISMODULE_ERRORMSG_WRONGTYPE "WRONGTYPE Operation against a key holding the wrong kind of value" #define REDISMODULE_ERRORMSG_WRONGTYPE "WRONGTYPE Operation against a key holding the wrong kind of value"
/* Sorted set range structure. */
typedef struct RedisModuleZsetRange {
uint32_t type;
uint32_t flags;
double score_start;
double score_end;
char *lex_start;
char *lex_end;
uint32_t lex_start_len;
uint32_t lex_end_len;
uint32_t pos_start;
uint32_t pos_end;
} RedisModuleZsetRange;
#define REDISMODULE_POSITIVE_INFINITE (1.0/0.0) #define REDISMODULE_POSITIVE_INFINITE (1.0/0.0)
#define REDISMODULE_NEGATIVE_INFINITE (-1.0/0.0) #define REDISMODULE_NEGATIVE_INFINITE (-1.0/0.0)
#define REDISMODULE_ZSET_RANGE_INIT {0,0,REDISMODULE_NEGATIVE_INFINITE,REDISMODULE_POSITIVE_INFINITE,"-","+",1,1,0,-1}
#define REDISMODULE_ZSET_RANGE_LEX 1
#define REDISMODULE_ZSET_RANGE_SCORE 2
#define REDISMODULE_ZSET_RANGE_POS 3
#define REDISMODULE_ZSET_RANGE_START_EX (1<<0)
#define REDISMODULE_ZSET_RANGE_END_EX (1<<1)
/* ------------------------- End of common defines ------------------------ */ /* ------------------------- End of common defines ------------------------ */
#ifndef REDISMODULE_CORE #ifndef REDISMODULE_CORE
...@@ -144,8 +122,8 @@ int REDISMODULE_API_FUNC(RedisModule_ZsetIncrby)(RedisModuleKey *key, double sco ...@@ -144,8 +122,8 @@ int REDISMODULE_API_FUNC(RedisModule_ZsetIncrby)(RedisModuleKey *key, double sco
int REDISMODULE_API_FUNC(RedisModule_ZsetScore)(RedisModuleKey *key, RedisModuleString *ele, double *score); int REDISMODULE_API_FUNC(RedisModule_ZsetScore)(RedisModuleKey *key, RedisModuleString *ele, double *score);
int REDISMODULE_API_FUNC(RedisModule_ZsetRem)(RedisModuleKey *key, RedisModuleString *ele, int *deleted); int REDISMODULE_API_FUNC(RedisModule_ZsetRem)(RedisModuleKey *key, RedisModuleString *ele, int *deleted);
void REDISMODULE_API_FUNC(RedisModule_ZsetRangeStop)(RedisModuleKey *key); void REDISMODULE_API_FUNC(RedisModule_ZsetRangeStop)(RedisModuleKey *key);
int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInRange)(RedisModuleKey *key, RedisModuleZsetRange *zr); int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex);
int REDISMODULE_API_FUNC(RedisModule_ZsetLastInRange)(RedisModuleKey *key, RedisModuleZsetRange *zr); int REDISMODULE_API_FUNC(RedisModule_ZsetLastInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex);
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ZsetRangeCurrentElement)(RedisModuleKey *key, double *score); RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ZsetRangeCurrentElement)(RedisModuleKey *key, double *score);
int REDISMODULE_API_FUNC(RedisModule_ZsetRangeNext)(RedisModuleKey *key); int REDISMODULE_API_FUNC(RedisModule_ZsetRangeNext)(RedisModuleKey *key);
int REDISMODULE_API_FUNC(RedisModule_ZsetRangePrev)(RedisModuleKey *key); int REDISMODULE_API_FUNC(RedisModule_ZsetRangePrev)(RedisModuleKey *key);
...@@ -204,8 +182,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int ...@@ -204,8 +182,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API(ZsetScore); REDISMODULE_GET_API(ZsetScore);
REDISMODULE_GET_API(ZsetRem); REDISMODULE_GET_API(ZsetRem);
REDISMODULE_GET_API(ZsetRangeStop); REDISMODULE_GET_API(ZsetRangeStop);
REDISMODULE_GET_API(ZsetFirstInRange); REDISMODULE_GET_API(ZsetFirstInScoreRange);
REDISMODULE_GET_API(ZsetLastInRange); REDISMODULE_GET_API(ZsetLastInScoreRange);
REDISMODULE_GET_API(ZsetRangeCurrentElement); REDISMODULE_GET_API(ZsetRangeCurrentElement);
REDISMODULE_GET_API(ZsetRangeNext); REDISMODULE_GET_API(ZsetRangeNext);
REDISMODULE_GET_API(ZsetRangePrev); REDISMODULE_GET_API(ZsetRangePrev);
......
...@@ -1347,6 +1347,7 @@ int zsetDel(robj *zobj, sds ele); ...@@ -1347,6 +1347,7 @@ int zsetDel(robj *zobj, sds ele);
sds ziplistGetObject(unsigned char *sptr); sds ziplistGetObject(unsigned char *sptr);
int zslValueGteMin(double value, zrangespec *spec); int zslValueGteMin(double value, zrangespec *spec);
int zslValueLteMax(double value, zrangespec *spec); int zslValueLteMax(double value, zrangespec *spec);
void zslFreeLexRange(zlexrangespec *spec);
/* Core functions */ /* Core functions */
int freeMemoryIfNeeded(void); int freeMemoryIfNeeded(void);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册