Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
083f5277
Commit
083f5277
authored
Apr 20, 2016
by
antirez
Browse files
Modules: zset iterator redesign #1.
parent
d9981708
Changes
4
Hide whitespace changes
Inline
Side-by-side
src/module.c
View file @
083f5277
...
...
@@ -65,13 +65,25 @@ struct RedisModuleKey {
robj
*
value
;
/* Value object, or NULL if the key was not found. */
void
*
iter
;
/* Iterator. */
int
mode
;
/* Opening mode. */
/* Zset iterator. */
RedisModuleZsetRange
*
zr
;
/* Zset iterator range passed by user. */
void
*
zcurrent
;
/* Zset iterator current node. */
int
zer
;
/* Zset iterator end reached flag (true if end was reached). */
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. */
int
zer
;
/* Zset iterator end reached flag
(true if end was reached). */
};
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
* a Redis module. */
typedef
int
(
*
RedisModuleCmdFunc
)
(
RedisModuleCtx
*
ctx
,
void
**
argv
,
int
argc
);
...
...
@@ -707,6 +719,7 @@ void RM_CloseKey(RedisModuleKey *key) {
if
(
key
==
NULL
)
return
;
if
(
key
->
mode
&
REDISMODULE_WRITE
)
signalModifiedKey
(
key
->
db
,
key
->
key
);
/* TODO: if (key->iter) RM_KeyIteratorStop(kp); */
RM_ZsetRangeStop
(
key
);
decrRefCount
(
key
->
key
);
autoMemoryFreed
(
key
->
ctx
,
REDISMODULE_AM_KEY
,
key
);
zfree
(
key
);
...
...
@@ -1083,10 +1096,13 @@ int RM_ZsetScore(RedisModuleKey *key, RedisModuleString *ele, double *score) {
/* Stop a sorted set iteration. */
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
* iterator is not active will result into something more sensible
* than crashing. */
key
->
z
r
=
NULL
;
key
->
z
type
=
REDISMODULE_ZSET_RANGE_NONE
;
key
->
zcurrent
=
NULL
;
key
->
zer
=
1
;
}
...
...
@@ -1096,59 +1112,55 @@ int RM_ZsetRangeEndReached(RedisModuleKey *key) {
return
key
->
zer
;
}
/* Helper function for RM_ZsetFirstInRange() and RM_ZsetLastInRange().
* Setup the sorted set iteration according to the specified range
* (see the functions calling it for more info). If first is true the
/* Helper function for RM_ZsetFirstIn
Score
Range() and RM_ZsetLastIn
Score
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
* first element in the range is used as a starting point for the iterator
* otherwise the last. Return REDISMODULE_OK on success otherwise
* REDISMODULE_ERR. */
int
zsetInitRange
(
RedisModuleKey
*
key
,
RedisModuleZsetRange
*
zr
,
int
first
)
{
int
zsetInit
Score
Range
(
RedisModuleKey
*
key
,
double
min
,
double
max
,
int
minex
,
int
maxex
,
int
first
)
{
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
;
if
(
zr
->
type
==
REDISMODULE_ZSET_RANGE_SCORE
)
{
/* Setup the range structure used by the sorted set core implementation
* in order to seek at the specified element. */
zrangespec
zrs
;
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
)
{
key
->
zcurrent
=
first
?
zzlFirstInRange
(
key
->
value
->
ptr
,
&
zrs
)
:
zzlLastInRange
(
key
->
value
->
ptr
,
&
zrs
);
}
else
if
(
key
->
value
->
encoding
==
OBJ_ENCODING_SKIPLIST
)
{
zset
*
zs
=
key
->
value
->
ptr
;
zskiplist
*
zsl
=
zs
->
zsl
;
key
->
zcurrent
=
first
?
zslFirstInRange
(
zsl
,
&
zrs
)
:
zslLastInRange
(
zsl
,
&
zrs
);
}
else
{
serverPanic
(
"Unsupported zset encoding"
);
}
if
(
key
->
zcurrent
==
NULL
)
key
->
zer
=
1
;
return
REDISMODULE_OK
;
/* Setup the range structure used by the sorted set core implementation
* in order to seek at the specified element. */
zrangespec
*
zrs
=
&
key
->
zrs
;
zrs
->
min
=
min
;
zrs
->
max
=
max
;
zrs
->
minex
=
minex
;
zrs
->
maxex
=
maxex
;
if
(
key
->
value
->
encoding
==
OBJ_ENCODING_ZIPLIST
)
{
key
->
zcurrent
=
first
?
zzlFirstInRange
(
key
->
value
->
ptr
,
zrs
)
:
zzlLastInRange
(
key
->
value
->
ptr
,
zrs
);
}
else
if
(
key
->
value
->
encoding
==
OBJ_ENCODING_SKIPLIST
)
{
zset
*
zs
=
key
->
value
->
ptr
;
zskiplist
*
zsl
=
zs
->
zsl
;
key
->
zcurrent
=
first
?
zslFirstInRange
(
zsl
,
zrs
)
:
zslLastInRange
(
zsl
,
zrs
);
}
else
{
return
REDISMODULE_ERR
;
serverPanic
(
"Unsupported zset encoding"
)
;
}
if
(
key
->
zcurrent
==
NULL
)
key
->
zer
=
1
;
return
REDISMODULE_OK
;
}
/* Setup a sorted set iterator seeking the first element in the specified
* range. Returns REDISMODULE_OK if the iterator was correctly initialized
* 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.
* 2. The iterator type is unrecognized. */
int
RM_ZsetFirstInRange
(
RedisModuleKey
*
key
,
RedisModuleZsetRange
*
zr
)
{
return
zsetInitRange
(
key
,
zr
,
1
);
* 1. The value stored at key is not a sorted set or the key is empty. */
int
RM_ZsetFirstInScoreRange
(
RedisModuleKey
*
key
,
double
min
,
double
max
,
int
minex
,
int
maxex
)
{
return
zsetInitScoreRange
(
key
,
min
,
max
,
minex
,
maxex
,
1
);
}
/* Exactly like R
M
_ZsetFirstInRange() but the last element of
the range
* is seeked instead. */
int
RM_ZsetLastInRange
(
RedisModuleKey
*
key
,
RedisModuleZsetRange
*
zr
)
{
return
zsetInitRange
(
key
,
zr
,
0
);
/* Exactly like R
edisModule
_ZsetFirstIn
Score
Range() but the last element of
*
the range
is seeked instead. */
int
RM_ZsetLastIn
Score
Range
(
RedisModuleKey
*
key
,
double
min
,
double
max
,
int
minex
,
int
maxex
)
{
return
zsetInit
Score
Range
(
key
,
min
,
max
,
minex
,
maxex
,
0
);
}
/* Return the current sorted set element of an active sorted set iterator
...
...
@@ -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
* does not include any item at all. */
int
RM_ZsetRangeNext
(
RedisModuleKey
*
key
)
{
if
(
!
key
->
zr
||
!
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
->
ztype
||
!
key
->
zcurrent
)
return
0
;
/* No active iterator. */
if
(
key
->
value
->
encoding
==
OBJ_ENCODING_ZIPLIST
)
{
unsigned
char
*
zl
=
key
->
value
->
ptr
;
...
...
@@ -1205,13 +1207,13 @@ int RM_ZsetRangeNext(RedisModuleKey *key) {
return
0
;
}
else
{
/* Are we still within the range? */
if
(
zr
->
type
==
REDISMODULE_ZSET_RANGE_SCORE
)
{
if
(
key
->
z
type
==
REDISMODULE_ZSET_RANGE_SCORE
)
{
/* Fetch the next element score for the
* range check. */
unsigned
char
*
saved_next
=
next
;
next
=
ziplistNext
(
zl
,
next
);
/* Skip next element. */
double
score
=
zzlGetScore
(
next
);
/* Obtain the next score. */
if
(
!
zslValueLteMax
(
score
,
&
zrs
))
{
if
(
!
zslValueLteMax
(
score
,
&
key
->
zrs
))
{
key
->
zer
=
1
;
return
0
;
}
...
...
@@ -1227,8 +1229,8 @@ int RM_ZsetRangeNext(RedisModuleKey *key) {
return
0
;
}
else
{
/* Are we still within the range? */
if
(
zr
->
type
==
REDISMODULE_ZSET_RANGE_SCORE
&&
!
zslValueLteMax
(
ln
->
score
,
&
zrs
))
if
(
key
->
z
type
==
REDISMODULE_ZSET_RANGE_SCORE
&&
!
zslValueLteMax
(
ln
->
score
,
&
key
->
zrs
))
{
key
->
zer
=
1
;
return
0
;
...
...
@@ -1245,17 +1247,7 @@ int RM_ZsetRangeNext(RedisModuleKey *key) {
* a previous element, 0 if we are already at the first element or the range
* does not include any item at all. */
int
RM_ZsetRangePrev
(
RedisModuleKey
*
key
)
{
if
(
!
key
->
zr
||
!
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
->
ztype
||
!
key
->
zcurrent
)
return
0
;
/* No active iterator. */
if
(
key
->
value
->
encoding
==
OBJ_ENCODING_ZIPLIST
)
{
unsigned
char
*
zl
=
key
->
value
->
ptr
;
...
...
@@ -1268,13 +1260,13 @@ int RM_ZsetRangePrev(RedisModuleKey *key) {
return
0
;
}
else
{
/* Are we still within the range? */
if
(
zr
->
type
==
REDISMODULE_ZSET_RANGE_SCORE
)
{
if
(
key
->
z
type
==
REDISMODULE_ZSET_RANGE_SCORE
)
{
/* Fetch the previous element score for the
* range check. */
unsigned
char
*
saved_prev
=
prev
;
prev
=
ziplistNext
(
zl
,
prev
);
/* Skip element to get the score. */
double
score
=
zzlGetScore
(
prev
);
/* Obtain the prev score. */
if
(
!
zslValueGteMin
(
score
,
&
zrs
))
{
if
(
!
zslValueGteMin
(
score
,
&
key
->
zrs
))
{
key
->
zer
=
1
;
return
0
;
}
...
...
@@ -1290,8 +1282,8 @@ int RM_ZsetRangePrev(RedisModuleKey *key) {
return
0
;
}
else
{
/* Are we still within the range? */
if
(
zr
->
type
==
REDISMODULE_ZSET_RANGE_SCORE
&&
!
zslValueGteMin
(
ln
->
score
,
&
zrs
))
if
(
key
->
z
type
==
REDISMODULE_ZSET_RANGE_SCORE
&&
!
zslValueGteMin
(
ln
->
score
,
&
key
->
zrs
))
{
key
->
zer
=
1
;
return
0
;
...
...
@@ -1756,8 +1748,8 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API
(
ZsetScore
);
REGISTER_API
(
ZsetRem
);
REGISTER_API
(
ZsetRangeStop
);
REGISTER_API
(
ZsetFirstInRange
);
REGISTER_API
(
ZsetLastInRange
);
REGISTER_API
(
ZsetFirstIn
Score
Range
);
REGISTER_API
(
ZsetLastIn
Score
Range
);
REGISTER_API
(
ZsetRangeCurrentElement
);
REGISTER_API
(
ZsetRangeNext
);
REGISTER_API
(
ZsetRangePrev
);
...
...
src/modules/helloworld.c
View file @
083f5277
...
...
@@ -333,14 +333,13 @@ int HelloMoreExpire_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
* another time backward. The two scores, returned as a two element array,
* should match.*/
int
HelloZsumRange_RedisCommand
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
RedisModuleZsetRange
zrange
=
REDISMODULE_ZSET_RANGE_INIT
;
zrange
.
type
=
REDISMODULE_ZSET_RANGE_SCORE
;
if
(
RedisModule_StringToDouble
(
argv
[
2
],
&
zrange
.
score_start
)
!=
REDISMODULE_OK
||
RedisModule_StringToDouble
(
argv
[
3
],
&
zrange
.
score_end
)
!=
REDISMODULE_OK
)
double
score_start
,
score_end
;
if
(
RedisModule_StringToDouble
(
argv
[
2
],
&
score_start
)
!=
REDISMODULE_OK
||
RedisModule_StringToDouble
(
argv
[
3
],
&
score_end
)
!=
REDISMODULE_OK
)
{
return
RedisModule_ReplyWithError
(
ctx
,
"ERR invalid range"
);
}
zrange
.
flags
=
0
;
RedisModuleKey
*
key
=
RedisModule_OpenKey
(
ctx
,
argv
[
1
],
REDISMODULE_READ
|
REDISMODULE_WRITE
);
...
...
@@ -351,7 +350,7 @@ int HelloZsumRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, i
double
scoresum_a
=
0
;
double
scoresum_b
=
0
;
RedisModule_ZsetFirstInRange
(
key
,
&
zrange
);
RedisModule_ZsetFirstIn
Score
Range
(
key
,
score_start
,
score_end
,
0
,
0
);
while
(
!
RedisModule_ZsetRangeEndReached
(
key
))
{
double
score
;
RedisModuleString
*
ele
=
RedisModule_ZsetRangeCurrentElement
(
key
,
&
score
);
...
...
@@ -361,7 +360,7 @@ int HelloZsumRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, i
}
RedisModule_ZsetRangeStop
(
key
);
RedisModule_ZsetLastInRange
(
key
,
&
zrange
);
RedisModule_ZsetLastIn
Score
Range
(
key
,
score_start
,
score_end
,
0
,
0
);
while
(
!
RedisModule_ZsetRangeEndReached
(
key
))
{
double
score
;
RedisModuleString
*
ele
=
RedisModule_ZsetRangeCurrentElement
(
key
,
&
score
);
...
...
src/redismodule.h
View file @
083f5277
...
...
@@ -50,31 +50,9 @@
/* Error messages. */
#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_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 ------------------------ */
#ifndef REDISMODULE_CORE
...
...
@@ -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_ZsetRem
)(
RedisModuleKey
*
key
,
RedisModuleString
*
ele
,
int
*
deleted
);
void
REDISMODULE_API_FUNC
(
RedisModule_ZsetRangeStop
)(
RedisModuleKey
*
key
);
int
REDISMODULE_API_FUNC
(
RedisModule_ZsetFirstInRange
)(
RedisModuleKey
*
key
,
RedisModuleZsetRange
*
zr
);
int
REDISMODULE_API_FUNC
(
RedisModule_ZsetLastInRange
)(
RedisModuleKey
*
key
,
RedisModuleZsetRange
*
zr
);
int
REDISMODULE_API_FUNC
(
RedisModule_ZsetFirstIn
Score
Range
)(
RedisModuleKey
*
key
,
double
min
,
double
max
,
int
minex
,
int
maxex
);
int
REDISMODULE_API_FUNC
(
RedisModule_ZsetLastIn
Score
Range
)(
RedisModuleKey
*
key
,
double
min
,
double
max
,
int
minex
,
int
maxex
);
RedisModuleString
*
REDISMODULE_API_FUNC
(
RedisModule_ZsetRangeCurrentElement
)(
RedisModuleKey
*
key
,
double
*
score
);
int
REDISMODULE_API_FUNC
(
RedisModule_ZsetRangeNext
)(
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
REDISMODULE_GET_API
(
ZsetScore
);
REDISMODULE_GET_API
(
ZsetRem
);
REDISMODULE_GET_API
(
ZsetRangeStop
);
REDISMODULE_GET_API
(
ZsetFirstInRange
);
REDISMODULE_GET_API
(
ZsetLastInRange
);
REDISMODULE_GET_API
(
ZsetFirstIn
Score
Range
);
REDISMODULE_GET_API
(
ZsetLastIn
Score
Range
);
REDISMODULE_GET_API
(
ZsetRangeCurrentElement
);
REDISMODULE_GET_API
(
ZsetRangeNext
);
REDISMODULE_GET_API
(
ZsetRangePrev
);
...
...
src/server.h
View file @
083f5277
...
...
@@ -1347,6 +1347,7 @@ int zsetDel(robj *zobj, sds ele);
sds
ziplistGetObject
(
unsigned
char
*
sptr
);
int
zslValueGteMin
(
double
value
,
zrangespec
*
spec
);
int
zslValueLteMax
(
double
value
,
zrangespec
*
spec
);
void
zslFreeLexRange
(
zlexrangespec
*
spec
);
/* Core functions */
int
freeMemoryIfNeeded
(
void
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment