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
5267d380
Commit
5267d380
authored
Jun 12, 2022
by
Oran Agra
Browse files
Merge remote-tracking branch 'origin/unstable' into 7.0
parents
2667c412
abb2ea7e
Changes
10
Hide whitespace changes
Inline
Side-by-side
src/module.c
View file @
5267d380
...
...
@@ -1154,15 +1154,10 @@ RedisModuleCommand *moduleCreateCommandProxy(struct RedisModule *module, sds dec
cp
->
rediscmd
->
key_specs
[
0
].
fk
.
range
.
lastkey
=
lastkey
<
0
?
lastkey
:
(
lastkey
-
firstkey
);
cp
->
rediscmd
->
key_specs
[
0
].
fk
.
range
.
keystep
=
keystep
;
cp
->
rediscmd
->
key_specs
[
0
].
fk
.
range
.
limit
=
0
;
/* Copy the default range to legacy_range_key_spec */
cp
->
rediscmd
->
legacy_range_key_spec
=
cp
->
rediscmd
->
key_specs
[
0
];
}
else
{
cp
->
rediscmd
->
key_specs_num
=
0
;
cp
->
rediscmd
->
legacy_range_key_spec
.
begin_search_type
=
KSPEC_BS_INVALID
;
cp
->
rediscmd
->
legacy_range_key_spec
.
find_keys_type
=
KSPEC_FK_INVALID
;
}
populateCommand
MovableKeys
(
cp
->
rediscmd
);
populateCommand
LegacyRangeSpec
(
cp
->
rediscmd
);
cp
->
rediscmd
->
microseconds
=
0
;
cp
->
rediscmd
->
calls
=
0
;
cp
->
rediscmd
->
rejected_calls
=
0
;
...
...
@@ -1697,10 +1692,9 @@ int RM_SetCommandInfo(RedisModuleCommand *command, const RedisModuleCommandInfo
}
}
/* Update the legacy (first,last,step) spec used by the COMMAND command,
/* Update the legacy (first,last,step) spec
and "movablekeys" flag
used by the COMMAND command,
* by trying to "glue" consecutive range key specs. */
populateCommandLegacyRangeSpec
(
cmd
);
populateCommandMovableKeys
(
cmd
);
}
if
(
info
->
args
)
{
...
...
src/server.c
View file @
5267d380
...
...
@@ -372,7 +372,7 @@ int dictExpandAllowed(size_t moreMem, double usedRatio) {
* belonging to the same cluster slot. See the Slot to Key API in cluster.c. */
size_t
dictEntryMetadataSize
(
dict
*
d
)
{
UNUSED
(
d
);
/* NOTICE: this also affect overhead_ht_slot_to_keys in getMemoryOverheadData.
/* NOTICE: this also affect
s
overhead_ht_slot_to_keys in getMemoryOverheadData.
* If we ever add non-cluster related data here, that code must be modified too. */
return
server
.
cluster_enabled
?
sizeof
(
clusterDictEntryMetadata
)
:
0
;
}
...
...
@@ -774,7 +774,7 @@ int clientsCronResizeOutputBuffer(client *c, mstime_t now_ms) {
*
* This is how it works. We have an array of CLIENTS_PEAK_MEM_USAGE_SLOTS slots
* where we track, for each, the biggest client output and input buffers we
* saw in that slot. Every slot correspond to one of the latest seconds, since
* saw in that slot. Every slot correspond
s
to one of the latest seconds, since
* the array is indexed by doing UNIXTIME % CLIENTS_PEAK_MEM_USAGE_SLOTS.
*
* When we want to know what was recently the peak memory usage, we just scan
...
...
@@ -2643,9 +2643,12 @@ void InitServerLast() {
* By far the most common case is just one range spec (e.g. SET)
* but some commands' ranges were split into two or more ranges
* in order to have different flags for different keys (e.g. SMOVE,
* first key is "
read write
", second key is "
write
").
* first key is "
RW ACCESS DELETE
", second key is "
RW INSERT
").
*
* This functions uses very basic heuristics and is "best effort":
* Additionally set the CMD_MOVABLE_KEYS flag for commands that may have key
* names in their arguments, but the legacy range spec doesn't cover all of them.
*
* This function uses very basic heuristics and is "best effort":
* 1. Only commands which have only "range" specs are considered.
* 2. Only range specs with keystep of 1 are considered.
* 3. The order of the range specs must be ascending (i.e.
...
...
@@ -2667,15 +2670,26 @@ void InitServerLast() {
void
populateCommandLegacyRangeSpec
(
struct
redisCommand
*
c
)
{
memset
(
&
c
->
legacy_range_key_spec
,
0
,
sizeof
(
c
->
legacy_range_key_spec
));
if
(
c
->
key_specs_num
==
0
)
/* Set the movablekeys flag if we have a GETKEYS flag for modules.
* Note that for native redis commands, we always have keyspecs,
* with enough information to rely on for movablekeys. */
if
(
c
->
flags
&
CMD_MODULE_GETKEYS
)
c
->
flags
|=
CMD_MOVABLE_KEYS
;
/* no key-specs, no keys, exit. */
if
(
c
->
key_specs_num
==
0
)
{
return
;
}
if
(
c
->
key_specs_num
==
1
&&
c
->
key_specs
[
0
].
begin_search_type
==
KSPEC_BS_INDEX
&&
c
->
key_specs
[
0
].
find_keys_type
==
KSPEC_FK_RANGE
)
{
/* Quick win */
/* Quick win
, exactly one range spec.
*/
c
->
legacy_range_key_spec
=
c
->
key_specs
[
0
];
/* If it has the incomplete flag, set the movablekeys flag on the command. */
if
(
c
->
key_specs
[
0
].
flags
&
CMD_KEY_INCOMPLETE
)
c
->
flags
|=
CMD_MOVABLE_KEYS
;
return
;
}
...
...
@@ -2684,11 +2698,23 @@ void populateCommandLegacyRangeSpec(struct redisCommand *c) {
for
(
int
i
=
0
;
i
<
c
->
key_specs_num
;
i
++
)
{
if
(
c
->
key_specs
[
i
].
begin_search_type
!=
KSPEC_BS_INDEX
||
c
->
key_specs
[
i
].
find_keys_type
!=
KSPEC_FK_RANGE
)
{
/* Found an incompatible (non range) spec, skip it, and set the movablekeys flag. */
c
->
flags
|=
CMD_MOVABLE_KEYS
;
continue
;
if
(
c
->
key_specs
[
i
].
fk
.
range
.
keystep
!=
1
)
return
;
if
(
prev_lastkey
&&
prev_lastkey
!=
c
->
key_specs
[
i
].
bs
.
index
.
pos
-
1
)
return
;
}
if
(
c
->
key_specs
[
i
].
fk
.
range
.
keystep
!=
1
||
(
prev_lastkey
&&
prev_lastkey
!=
c
->
key_specs
[
i
].
bs
.
index
.
pos
-
1
))
{
/* Found a range spec that's not plain (step of 1) or not consecutive to the previous one.
* Skip it, and we set the movablekeys flag. */
c
->
flags
|=
CMD_MOVABLE_KEYS
;
continue
;
}
if
(
c
->
key_specs
[
i
].
flags
&
CMD_KEY_INCOMPLETE
)
{
/* The spec we're using is incomplete, we can use it, but we also have to set the movablekeys flag. */
c
->
flags
|=
CMD_MOVABLE_KEYS
;
}
firstkey
=
min
(
firstkey
,
c
->
key_specs
[
i
].
bs
.
index
.
pos
);
/* Get the absolute index for lastkey (in the "range" spec, lastkey is relative to firstkey) */
int
lastkey_abs_index
=
c
->
key_specs
[
i
].
fk
.
range
.
lastkey
;
...
...
@@ -2696,10 +2722,14 @@ void populateCommandLegacyRangeSpec(struct redisCommand *c) {
lastkey_abs_index
+=
c
->
key_specs
[
i
].
bs
.
index
.
pos
;
/* For lastkey we use unsigned comparison to handle negative values correctly */
lastkey
=
max
((
unsigned
)
lastkey
,
(
unsigned
)
lastkey_abs_index
);
prev_lastkey
=
lastkey
;
}
if
(
firstkey
==
INT_MAX
)
if
(
firstkey
==
INT_MAX
)
{
/* Couldn't find range specs, the legacy range spec will remain empty, and we set the movablekeys flag. */
c
->
flags
|=
CMD_MOVABLE_KEYS
;
return
;
}
serverAssert
(
firstkey
!=
0
);
serverAssert
(
lastkey
!=
0
);
...
...
@@ -2787,11 +2817,9 @@ void populateCommandStructure(struct redisCommand *c) {
c
->
num_tips
++
;
c
->
num_args
=
populateArgsStructure
(
c
->
args
);
/* Handle the legacy range spec and the "movablekeys" flag (must be done after populating all key specs). */
populateCommandLegacyRangeSpec
(
c
);
/* Handle the "movablekeys" flag (must be done after populating all key specs). */
populateCommandMovableKeys
(
c
);
/* Assign the ID used for ACL. */
c
->
id
=
ACLGetCommandID
(
c
->
fullname
);
...
...
@@ -2812,7 +2840,7 @@ void populateCommandStructure(struct redisCommand *c) {
extern
struct
redisCommand
redisCommandTable
[];
/* Populates the Redis Command Table dict from
from
the static table in commands.c
/* Populates the Redis Command Table dict from the static table in commands.c
* which is auto generated from the json files in the commands folder. */
void
populateCommandTable
(
void
)
{
int
j
;
...
...
@@ -3498,31 +3526,6 @@ void afterCommand(client *c) {
}
}
/* Returns 1 for commands that may have key names in their arguments, but the legacy range
* spec doesn't cover all of them. */
void
populateCommandMovableKeys
(
struct
redisCommand
*
cmd
)
{
int
movablekeys
=
0
;
if
(
cmd
->
getkeys_proc
||
(
cmd
->
flags
&
CMD_MODULE_GETKEYS
))
{
/* Command with getkeys proc */
movablekeys
=
1
;
}
else
{
/* Redis command without getkeys proc, but possibly has
* movable keys because of a keys spec. */
for
(
int
i
=
0
;
i
<
cmd
->
key_specs_num
;
i
++
)
{
if
(
cmd
->
key_specs
[
i
].
begin_search_type
!=
KSPEC_BS_INDEX
||
cmd
->
key_specs
[
i
].
find_keys_type
!=
KSPEC_FK_RANGE
)
{
/* If we have a non-range spec it means we have movable keys */
movablekeys
=
1
;
break
;
}
}
}
if
(
movablekeys
)
cmd
->
flags
|=
CMD_MOVABLE_KEYS
;
}
/* Check if c->cmd exists, fills `err` with details in case it doesn't.
* Return 1 if exists. */
int
commandCheckExistence
(
client
*
c
,
sds
*
err
)
{
...
...
@@ -6028,7 +6031,7 @@ static int THPDisable(void) {
}
void
linuxMemoryWarnings
(
void
)
{
sds
err_msg
;
sds
err_msg
=
NULL
;
if
(
checkOvercommit
(
&
err_msg
)
<
0
)
{
serverLog
(
LL_WARNING
,
"WARNING %s"
,
err_msg
);
sdsfree
(
err_msg
);
...
...
@@ -6939,7 +6942,7 @@ int main(int argc, char **argv) {
serverLog
(
LL_WARNING
,
"Server initialized"
);
#ifdef __linux__
linuxMemoryWarnings
();
sds
err_msg
;
sds
err_msg
=
NULL
;
if
(
checkXenClocksource
(
&
err_msg
)
<
0
)
{
serverLog
(
LL_WARNING
,
"WARNING %s"
,
err_msg
);
sdsfree
(
err_msg
);
...
...
src/server.h
View file @
5267d380
...
...
@@ -215,7 +215,8 @@ extern int configOOMScoreAdjValuesDefaults[CONFIG_OOM_COUNT];
#define CMD_MODULE_NO_CLUSTER (1ULL<<22)
/* Deny on Redis Cluster. */
#define CMD_NO_ASYNC_LOADING (1ULL<<23)
#define CMD_NO_MULTI (1ULL<<24)
#define CMD_MOVABLE_KEYS (1ULL<<25)
/* populated by populateCommandMovableKeys */
#define CMD_MOVABLE_KEYS (1ULL<<25)
/* The legacy range spec doesn't cover all keys.
* Populated by populateCommandLegacyRangeSpec. */
#define CMD_ALLOW_BUSY ((1ULL<<26))
#define CMD_MODULE_GETCHANNELS (1ULL<<27)
/* Use the modules getchannels interface. */
...
...
@@ -3550,7 +3551,6 @@ void mixDigest(unsigned char *digest, const void *ptr, size_t len);
void
xorDigest
(
unsigned
char
*
digest
,
const
void
*
ptr
,
size_t
len
);
sds
catSubCommandFullname
(
const
char
*
parent_name
,
const
char
*
sub_name
);
void
commandAddSubcommand
(
struct
redisCommand
*
parent
,
struct
redisCommand
*
subcommand
,
const
char
*
declared_name
);
void
populateCommandMovableKeys
(
struct
redisCommand
*
cmd
);
void
debugDelay
(
int
usec
);
void
killIOThreads
(
void
);
void
killThreads
(
void
);
...
...
src/syscheck.c
View file @
5267d380
...
...
@@ -143,7 +143,7 @@ int checkOvercommit(sds *error_msg) {
FILE
*
fp
=
fopen
(
"/proc/sys/vm/overcommit_memory"
,
"r"
);
char
buf
[
64
];
if
(
!
fp
)
return
-
1
;
if
(
!
fp
)
return
0
;
if
(
fgets
(
buf
,
64
,
fp
)
==
NULL
)
{
fclose
(
fp
);
return
0
;
...
...
@@ -152,7 +152,7 @@ int checkOvercommit(sds *error_msg) {
if
(
atoi
(
buf
))
{
*
error_msg
=
sdsnew
(
"
WARNING
overcommit_memory is set to 0! Background save may fail under low memory condition. "
"overcommit_memory is set to 0! Background save may fail under low memory condition. "
"To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the "
"command 'sysctl vm.overcommit_memory=1' for this to take effect."
);
return
-
1
;
...
...
@@ -351,7 +351,7 @@ check checks[] = {
int
syscheck
(
void
)
{
check
*
cur_check
=
checks
;
int
ret
=
1
;
sds
err_msg
;
sds
err_msg
=
NULL
;
while
(
cur_check
->
check_fn
)
{
int
res
=
cur_check
->
check_fn
(
&
err_msg
);
printf
(
"[%s]..."
,
cur_check
->
name
);
...
...
src/t_stream.c
View file @
5267d380
...
...
@@ -2144,7 +2144,7 @@ void xrevrangeCommand(client *c) {
xrangeGenericCommand
(
c
,
1
);
}
/* XLEN */
/* XLEN
key
*/
void
xlenCommand
(
client
*
c
)
{
robj
*
o
;
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
...
...
@@ -2156,10 +2156,10 @@ void xlenCommand(client *c) {
/* XREAD [BLOCK <milliseconds>] [COUNT <count>] STREAMS key_1 key_2 ... key_N
* ID_1 ID_2 ... ID_N
*
* This function also implements the XREAD
-
GROUP command, which is like XREAD
* This function also implements the XREADGROUP command, which is like XREAD
* but accepting the [GROUP group-name consumer-name] additional option.
* This is useful because while XREAD is a read command and can be called
* on slaves, XREAD
-
GROUP is not. */
* on slaves, XREADGROUP is not. */
#define XREAD_BLOCKED_DEFAULT_COUNT 1000
void
xreadCommand
(
client
*
c
)
{
long
long
timeout
=
-
1
;
/* -1 means, no BLOCK argument given. */
...
...
@@ -2566,8 +2566,8 @@ void streamDelConsumer(streamCG *cg, streamConsumer *consumer) {
* Consumer groups commands
* ----------------------------------------------------------------------- */
/* XGROUP CREATE <key> <groupname> <id or $> [MKSTREAM] [ENTRIES
ADDED count
]
* XGROUP SETID <key> <groupname> <id or $> [ENTRIES
ADDED count
]
/* XGROUP CREATE <key> <groupname> <id or $> [MKSTREAM] [ENTRIES
READ entries_read
]
* XGROUP SETID <key> <groupname> <id or $> [ENTRIES
READ entries_read
]
* XGROUP DESTROY <key> <groupname>
* XGROUP CREATECONSUMER <key> <groupname> <consumer>
* XGROUP DELCONSUMER <key> <groupname> <consumername> */
...
...
@@ -2805,7 +2805,6 @@ void xsetidCommand(client *c) {
}
/* XACK <key> <group> <id> <id> ... <id>
*
* Acknowledge a message as processed. In practical terms we just check the
* pending entries list (PEL) of the group, and delete the PEL entry both from
* the group and the consumer (pending messages are referenced in both places).
...
...
@@ -3050,7 +3049,7 @@ void xpendingCommand(client *c) {
* [IDLE <milliseconds>] [TIME <mstime>] [RETRYCOUNT <count>]
* [FORCE] [JUSTID]
*
*
Get
s ownership of one or multiple messages in the Pending Entries List
*
Change
s ownership of one or multiple messages in the Pending Entries List
* of a given stream consumer group.
*
* If the message ID (among the specified ones) exists, and its idle
...
...
@@ -3316,7 +3315,7 @@ cleanup:
/* XAUTOCLAIM <key> <group> <consumer> <min-idle-time> <start> [COUNT <count>] [JUSTID]
*
*
Get
s ownership of one or multiple messages in the Pending Entries List
*
Change
s ownership of one or multiple messages in the Pending Entries List
* of a given stream consumer group.
*
* For each PEL entry, if its idle time greater or equal to <min-idle-time>,
...
...
tests/integration/logging.tcl
View file @
5267d380
...
...
@@ -8,9 +8,12 @@ if {$system_name eq {darwin}} {
set backtrace_supported 1
}
elseif
{
$system
_name eq
{
linux
}}
{
# Avoid the test on libmusl, which does not support backtrace
set ldd
[
exec ldd src/redis-server
]
if
{
!
[
string match
{
*libc.*musl*
}
$ldd
]}
{
set backtrace_supported 1
# and on static binaries
(
ldd exit code 1
)
where we can't detect libmusl
catch
{
set ldd
[
exec ldd src/redis-server
]
if
{
!
[
string match
{
*libc.*musl*
}
$ldd
]}
{
set backtrace_supported 1
}
}
}
...
...
tests/modules/keyspecs.c
View file @
5267d380
...
...
@@ -18,6 +18,13 @@ int createKspecNone(RedisModuleCtx *ctx) {
return
REDISMODULE_OK
;
}
int
createKspecNoneWithGetkeys
(
RedisModuleCtx
*
ctx
)
{
/* A command without keyspecs; only the legacy (first,last,step) triple (MSET like spec), but also has a getkeys callback */
if
(
RedisModule_CreateCommand
(
ctx
,
"kspec.nonewithgetkeys"
,
kspec_impl
,
"getkeys-api"
,
1
,
-
1
,
2
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
return
REDISMODULE_OK
;
}
int
createKspecTwoRanges
(
RedisModuleCtx
*
ctx
)
{
/* Test that two position/range-based key specs are combined to produce the
* legacy (first,last,step) values representing both keys. */
...
...
@@ -51,6 +58,39 @@ int createKspecTwoRanges(RedisModuleCtx *ctx) {
return
REDISMODULE_OK
;
}
int
createKspecTwoRangesWithGap
(
RedisModuleCtx
*
ctx
)
{
/* Test that two position/range-based key specs are combined to produce the
* legacy (first,last,step) values representing just one key. */
if
(
RedisModule_CreateCommand
(
ctx
,
"kspec.tworangeswithgap"
,
kspec_impl
,
""
,
0
,
0
,
0
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
RedisModuleCommand
*
command
=
RedisModule_GetCommand
(
ctx
,
"kspec.tworangeswithgap"
);
RedisModuleCommandInfo
info
=
{
.
version
=
REDISMODULE_COMMAND_INFO_VERSION
,
.
arity
=
-
2
,
.
key_specs
=
(
RedisModuleCommandKeySpec
[]){
{
.
flags
=
REDISMODULE_CMD_KEY_RO
|
REDISMODULE_CMD_KEY_ACCESS
,
.
begin_search_type
=
REDISMODULE_KSPEC_BS_INDEX
,
.
bs
.
index
.
pos
=
1
,
.
find_keys_type
=
REDISMODULE_KSPEC_FK_RANGE
,
.
fk
.
range
=
{
0
,
1
,
0
}
},
{
.
flags
=
REDISMODULE_CMD_KEY_RW
|
REDISMODULE_CMD_KEY_UPDATE
,
.
begin_search_type
=
REDISMODULE_KSPEC_BS_INDEX
,
.
bs
.
index
.
pos
=
3
,
/* Omitted find_keys_type is shorthand for RANGE {0,1,0} */
},
{
0
}
}
};
if
(
RedisModule_SetCommandInfo
(
command
,
&
info
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
return
REDISMODULE_OK
;
}
int
createKspecKeyword
(
RedisModuleCtx
*
ctx
)
{
/* Only keyword-based specs. The legacy triple is wiped and set to (0,0,0). */
if
(
RedisModule_CreateCommand
(
ctx
,
"kspec.keyword"
,
kspec_impl
,
""
,
3
,
-
1
,
1
)
==
REDISMODULE_ERR
)
...
...
@@ -177,7 +217,9 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
return
REDISMODULE_ERR
;
if
(
createKspecNone
(
ctx
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
createKspecNoneWithGetkeys
(
ctx
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
createKspecTwoRanges
(
ctx
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
createKspecTwoRangesWithGap
(
ctx
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
createKspecKeyword
(
ctx
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
createKspecComplex1
(
ctx
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
createKspecComplex2
(
ctx
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
...
...
tests/unit/introspection-2.tcl
View file @
5267d380
...
...
@@ -176,4 +176,19 @@ start_server {tags {"introspection"}} {
assert_equal
{{}}
[
r command info get|key
]
assert_equal
{{}}
[
r command info config|get|key
]
}
foreach cmd
{
SET GET MSET BITFIELD LMOVE LPOP BLPOP PING MEMORY MEMORY|USAGE RENAME GEORADIUS_RO
}
{
test
"
$cmd
command will not be marked with movablekeys"
{
set info
[
lindex
[
r command info $cmd
]
0
]
assert_no_match
{
*movablekeys*
}
[
lindex $info 2
]
}
}
foreach cmd
{
ZUNIONSTORE XREAD EVAL SORT SORT_RO MIGRATE GEORADIUS
}
{
test
"
$cmd
command is marked with movablekeys"
{
set info
[
lindex
[
r command info $cmd
]
0
]
assert_match
{
*movablekeys*
}
[
lindex $info 2
]
}
}
}
tests/unit/moduleapi/keyspecs.tcl
View file @
5267d380
...
...
@@ -31,6 +31,20 @@ start_server {tags {"modules"}} {
assert_equal
[
r command getkeys kspec.tworanges foo bar baz quux
]
{
foo bar
}
}
test
"Module key specs: Two ranges with gap"
{
set reply
[
lindex
[
r command info kspec.tworangeswithgap
]
0
]
# Verify
(
first, last, step
)
and movablekeys
assert_equal
[
lindex $reply 2
]
{
module movablekeys
}
assert_equal
[
lindex $reply 3
]
1
assert_equal
[
lindex $reply 4
]
1
assert_equal
[
lindex $reply 5
]
1
# Verify key-specs
set keyspecs
[
lindex $reply 8
]
assert_equal
[
lindex $keyspecs 0
]
{
flags
{
RO access
}
begin_search
{
type index spec
{
index 1
}}
find_keys
{
type range spec
{
lastkey 0 keystep 1 limit 0
}}}
assert_equal
[
lindex $keyspecs 1
]
{
flags
{
RW update
}
begin_search
{
type index spec
{
index 3
}}
find_keys
{
type range spec
{
lastkey 0 keystep 1 limit 0
}}}
assert_equal
[
r command getkeys kspec.tworangeswithgap foo bar baz quux
]
{
foo baz
}
}
test
"Module key specs: Keyword-only spec clears the legacy triple"
{
set reply
[
lindex
[
r command info kspec.keyword
]
0
]
# Verify
(
first, last, step
)
and movablekeys
...
...
@@ -79,7 +93,7 @@ start_server {tags {"modules"}} {
test
"Module command list filtering"
{
;
# Note: we piggyback this tcl file to test the general functionality of command list filtering
set reply
[
r command list filterby module keyspecs
]
assert_equal
[
lsort $reply
]
{
kspec.complex1 kspec.complex2 kspec.keyword kspec.none kspec.
tworanges
}
assert_equal
[
lsort $reply
]
{
kspec.complex1 kspec.complex2 kspec.keyword kspec.none kspec.
nonewithgetkeys kspec.tworanges kspec.tworangeswithgap
}
assert_equal
[
r command getkeys kspec.complex2 foo bar 2 baz quux banana STORE dst dummy MOREKEYS hey ho
]
{
dst foo bar baz quux hey ho
}
}
...
...
@@ -108,6 +122,20 @@ start_server {tags {"modules"}} {
assert_equal
"This user has no permissions to access the 'write' key"
[
r ACL DRYRUN testuser kspec.tworanges write rw
]
}
foreach cmd
{
kspec.none kspec.tworanges
}
{
test
"
$cmd
command will not be marked with movablekeys"
{
set info
[
lindex
[
r command info $cmd
]
0
]
assert_no_match
{
*movablekeys*
}
[
lindex $info 2
]
}
}
foreach cmd
{
kspec.keyword kspec.complex1 kspec.complex2 kspec.nonewithgetkeys
}
{
test
"
$cmd
command is marked with movablekeys"
{
set info
[
lindex
[
r command info $cmd
]
0
]
assert_match
{
*movablekeys*
}
[
lindex $info 2
]
}
}
test
"Unload the module - keyspecs"
{
assert_equal
{
OK
}
[
r module unload keyspecs
]
}
...
...
utils/generate-module-api-doc.rb
View file @
5267d380
...
...
@@ -20,7 +20,7 @@ def markdown(s)
# Add backquotes around RedisModule functions and type where missing.
l
=
l
.
gsub
(
/(?<!`)RedisModule[A-z]+(?:\*?\(\))?/
){
|
x
|
"`
#{
x
}
`"
}
# Add backquotes around c functions like malloc() where missing.
l
=
l
.
gsub
(
/(?<![`A-z])[a-z_]+\(\)/
,
'`\0`'
)
l
=
l
.
gsub
(
/(?<![`A-z
.
])[a-z_]+\(\)/
,
'`\0`'
)
# Add backquotes around macro and var names containing underscores.
l
=
l
.
gsub
(
/(?<![`A-z\*])[A-Za-z]+_[A-Za-z0-9_]+/
){
|
x
|
"`
#{
x
}
`"
}
# Link URLs preceded by space or newline (not already linked)
...
...
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