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
ec2d1807
Unverified
Commit
ec2d1807
authored
Jan 12, 2021
by
Oran Agra
Committed by
GitHub
Jan 12, 2021
Browse files
Merge 6.2 RC2
parents
b8c67ce4
049f2f08
Changes
89
Hide whitespace changes
Inline
Side-by-side
src/tracking.c
View file @
ec2d1807
...
@@ -99,6 +99,57 @@ void disableTracking(client *c) {
...
@@ -99,6 +99,57 @@ void disableTracking(client *c) {
}
}
}
}
static
int
stringCheckPrefix
(
unsigned
char
*
s1
,
size_t
s1_len
,
unsigned
char
*
s2
,
size_t
s2_len
)
{
size_t
min_length
=
s1_len
<
s2_len
?
s1_len
:
s2_len
;
return
memcmp
(
s1
,
s2
,
min_length
)
==
0
;
}
/* Check if any of the provided prefixes collide with one another or
* with an existing prefix for the client. A collision is defined as two
* prefixes that will emit an invalidation for the same key. If no prefix
* collision is found, 1 is return, otherwise 0 is returned and the client
* has an error emitted describing the error. */
int
checkPrefixCollisionsOrReply
(
client
*
c
,
robj
**
prefixes
,
size_t
numprefix
)
{
for
(
size_t
i
=
0
;
i
<
numprefix
;
i
++
)
{
/* Check input list has no overlap with existing prefixes. */
if
(
c
->
client_tracking_prefixes
)
{
raxIterator
ri
;
raxStart
(
&
ri
,
c
->
client_tracking_prefixes
);
raxSeek
(
&
ri
,
"^"
,
NULL
,
0
);
while
(
raxNext
(
&
ri
))
{
if
(
stringCheckPrefix
(
ri
.
key
,
ri
.
key_len
,
prefixes
[
i
]
->
ptr
,
sdslen
(
prefixes
[
i
]
->
ptr
)))
{
sds
collision
=
sdsnewlen
(
ri
.
key
,
ri
.
key_len
);
addReplyErrorFormat
(
c
,
"Prefix '%s' overlaps with an existing prefix '%s'. "
"Prefixes for a single client must not overlap."
,
(
unsigned
char
*
)
prefixes
[
i
]
->
ptr
,
(
unsigned
char
*
)
collision
);
sdsfree
(
collision
);
raxStop
(
&
ri
);
return
0
;
}
}
raxStop
(
&
ri
);
}
/* Check input has no overlap with itself. */
for
(
size_t
j
=
i
+
1
;
j
<
numprefix
;
j
++
)
{
if
(
stringCheckPrefix
(
prefixes
[
i
]
->
ptr
,
sdslen
(
prefixes
[
i
]
->
ptr
),
prefixes
[
j
]
->
ptr
,
sdslen
(
prefixes
[
j
]
->
ptr
)))
{
addReplyErrorFormat
(
c
,
"Prefix '%s' overlaps with another provided prefix '%s'. "
"Prefixes for a single client must not overlap."
,
(
unsigned
char
*
)
prefixes
[
i
]
->
ptr
,
(
unsigned
char
*
)
prefixes
[
j
]
->
ptr
);
return
i
;
}
}
}
return
-
1
;
}
/* Set the client 'c' to track the prefix 'prefix'. If the client 'c' is
/* Set the client 'c' to track the prefix 'prefix'. If the client 'c' is
* already registered for the specified prefix, no operation is performed. */
* already registered for the specified prefix, no operation is performed. */
void
enableBcastTrackingForPrefix
(
client
*
c
,
char
*
prefix
,
size_t
plen
)
{
void
enableBcastTrackingForPrefix
(
client
*
c
,
char
*
prefix
,
size_t
plen
)
{
...
@@ -350,19 +401,22 @@ void trackingInvalidateKey(client *c, robj *keyobj) {
...
@@ -350,19 +401,22 @@ void trackingInvalidateKey(client *c, robj *keyobj) {
}
}
/* This function is called when one or all the Redis databases are
/* This function is called when one or all the Redis databases are
* flushed (dbid == -1 in case of FLUSHALL). Caching keys are not
* flushed. Caching keys are not specific for each DB but are global:
* specific for each DB but are global: currently what we do is send a
* currently what we do is send a special notification to clients with
* special notification to clients with tracking enabled, sending a
* tracking enabled, sending a RESP NULL, which means, "all the keys",
* RESP NULL, which means, "all the keys", in order to avoid flooding
* in order to avoid flooding clients with many invalidation messages
* clients with many invalidation messages for all the keys they may
* for all the keys they may hold.
* hold.
*/
*/
void
freeTrackingRadixTree
(
void
*
rt
)
{
void
freeTrackingRadixTree
Callback
(
void
*
rt
)
{
raxFree
(
rt
);
raxFree
(
rt
);
}
}
void
freeTrackingRadixTree
(
rax
*
rt
)
{
raxFreeWithCallback
(
rt
,
freeTrackingRadixTreeCallback
);
}
/* A RESP NULL is sent to indicate that all keys are invalid */
/* A RESP NULL is sent to indicate that all keys are invalid */
void
trackingInvalidateKeysOnFlush
(
int
dbid
)
{
void
trackingInvalidateKeysOnFlush
(
int
async
)
{
if
(
server
.
tracking_clients
)
{
if
(
server
.
tracking_clients
)
{
listNode
*
ln
;
listNode
*
ln
;
listIter
li
;
listIter
li
;
...
@@ -376,8 +430,12 @@ void trackingInvalidateKeysOnFlush(int dbid) {
...
@@ -376,8 +430,12 @@ void trackingInvalidateKeysOnFlush(int dbid) {
}
}
/* In case of FLUSHALL, reclaim all the memory used by tracking. */
/* In case of FLUSHALL, reclaim all the memory used by tracking. */
if
(
dbid
==
-
1
&&
TrackingTable
)
{
if
(
TrackingTable
)
{
raxFreeWithCallback
(
TrackingTable
,
freeTrackingRadixTree
);
if
(
async
)
{
freeTrackingRadixTreeAsync
(
TrackingTable
);
}
else
{
freeTrackingRadixTree
(
TrackingTable
);
}
TrackingTable
=
raxNew
();
TrackingTable
=
raxNew
();
TrackingTableTotalItems
=
0
;
TrackingTableTotalItems
=
0
;
}
}
...
...
src/version.h
View file @
ec2d1807
#define REDIS_VERSION "6.1.24
0
"
#define REDIS_VERSION "6.1.24
1
"
#define REDIS_VERSION_NUM 0x000601f
0
#define REDIS_VERSION_NUM 0x000601f
1
src/ziplist.c
View file @
ec2d1807
...
@@ -431,19 +431,21 @@ unsigned int zipStoreEntryEncoding(unsigned char *p, unsigned char encoding, uns
...
@@ -431,19 +431,21 @@ unsigned int zipStoreEntryEncoding(unsigned char *p, unsigned char encoding, uns
/* Encode the length of the previous entry and write it to "p". This only
/* Encode the length of the previous entry and write it to "p". This only
* uses the larger encoding (required in __ziplistCascadeUpdate). */
* uses the larger encoding (required in __ziplistCascadeUpdate). */
int
zipStorePrevEntryLengthLarge
(
unsigned
char
*
p
,
unsigned
int
len
)
{
int
zipStorePrevEntryLengthLarge
(
unsigned
char
*
p
,
unsigned
int
len
)
{
uint32_t
u32
;
if
(
p
!=
NULL
)
{
if
(
p
!=
NULL
)
{
p
[
0
]
=
ZIP_BIG_PREVLEN
;
p
[
0
]
=
ZIP_BIG_PREVLEN
;
memcpy
(
p
+
1
,
&
len
,
sizeof
(
len
));
u32
=
len
;
memcpy
(
p
+
1
,
&
u32
,
sizeof
(
u32
));
memrev32ifbe
(
p
+
1
);
memrev32ifbe
(
p
+
1
);
}
}
return
1
+
sizeof
(
len
);
return
1
+
sizeof
(
uint32_t
);
}
}
/* Encode the length of the previous entry and write it to "p". Return the
/* Encode the length of the previous entry and write it to "p". Return the
* number of bytes needed to encode this length if "p" is NULL. */
* number of bytes needed to encode this length if "p" is NULL. */
unsigned
int
zipStorePrevEntryLength
(
unsigned
char
*
p
,
unsigned
int
len
)
{
unsigned
int
zipStorePrevEntryLength
(
unsigned
char
*
p
,
unsigned
int
len
)
{
if
(
p
==
NULL
)
{
if
(
p
==
NULL
)
{
return
(
len
<
ZIP_BIG_PREVLEN
)
?
1
:
sizeof
(
len
)
+
1
;
return
(
len
<
ZIP_BIG_PREVLEN
)
?
1
:
sizeof
(
uint32_t
)
+
1
;
}
else
{
}
else
{
if
(
len
<
ZIP_BIG_PREVLEN
)
{
if
(
len
<
ZIP_BIG_PREVLEN
)
{
p
[
0
]
=
len
;
p
[
0
]
=
len
;
...
@@ -1711,7 +1713,7 @@ int ziplistTest(int argc, char **argv) {
...
@@ -1711,7 +1713,7 @@ int ziplistTest(int argc, char **argv) {
if
(
p
==
NULL
)
{
if
(
p
==
NULL
)
{
printf
(
"No entry
\n
"
);
printf
(
"No entry
\n
"
);
}
else
{
}
else
{
printf
(
"ERROR: Out of range index should return NULL, returned offset: %ld
\n
"
,
p
-
zl
);
printf
(
"ERROR: Out of range index should return NULL, returned offset: %ld
\n
"
,
(
long
)(
p
-
zl
)
)
;
return
1
;
return
1
;
}
}
printf
(
"
\n
"
);
printf
(
"
\n
"
);
...
@@ -1761,7 +1763,7 @@ int ziplistTest(int argc, char **argv) {
...
@@ -1761,7 +1763,7 @@ int ziplistTest(int argc, char **argv) {
if
(
p
==
NULL
)
{
if
(
p
==
NULL
)
{
printf
(
"No entry
\n
"
);
printf
(
"No entry
\n
"
);
}
else
{
}
else
{
printf
(
"ERROR: Out of range index should return NULL, returned offset: %ld
\n
"
,
p
-
zl
);
printf
(
"ERROR: Out of range index should return NULL, returned offset: %ld
\n
"
,
(
long
)(
p
-
zl
)
)
;
return
1
;
return
1
;
}
}
printf
(
"
\n
"
);
printf
(
"
\n
"
);
...
...
src/zmalloc.c
View file @
ec2d1807
...
@@ -580,15 +580,18 @@ size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
...
@@ -580,15 +580,18 @@ size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
size_t
zmalloc_get_smap_bytes_by_field
(
char
*
field
,
long
pid
)
{
size_t
zmalloc_get_smap_bytes_by_field
(
char
*
field
,
long
pid
)
{
#if defined(__APPLE__)
#if defined(__APPLE__)
struct
proc_regioninfo
pri
;
struct
proc_regioninfo
pri
;
if
(
proc_pidinfo
(
pid
,
PROC_PIDREGIONINFO
,
0
,
&
pri
,
PROC_PIDREGIONINFO_SIZE
)
==
if
(
pid
==
-
1
)
pid
=
getpid
();
PROC_PIDREGIONINFO_SIZE
)
{
if
(
proc_pidinfo
(
pid
,
PROC_PIDREGIONINFO
,
0
,
&
pri
,
if
(
!
strcmp
(
field
,
"Private_Dirty:"
))
{
PROC_PIDREGIONINFO_SIZE
)
==
PROC_PIDREGIONINFO_SIZE
)
return
(
size_t
)
pri
.
pri_pages_dirtied
*
4096
;
{
}
else
if
(
!
strcmp
(
field
,
"Rss:"
))
{
int
pagesize
=
getpagesize
();
return
(
size_t
)
pri
.
pri_pages_resident
*
4096
;
if
(
!
strcmp
(
field
,
"Private_Dirty:"
))
{
}
else
if
(
!
strcmp
(
field
,
"AnonHugePages:"
))
{
return
(
size_t
)
pri
.
pri_pages_dirtied
*
pagesize
;
}
else
if
(
!
strcmp
(
field
,
"Rss:"
))
{
return
(
size_t
)
pri
.
pri_pages_resident
*
pagesize
;
}
else
if
(
!
strcmp
(
field
,
"AnonHugePages:"
))
{
return
0
;
return
0
;
}
}
}
}
return
0
;
return
0
;
#endif
#endif
...
...
tests/cluster/cluster.tcl
View file @
ec2d1807
...
@@ -57,6 +57,11 @@ proc CI {n field} {
...
@@ -57,6 +57,11 @@ proc CI {n field} {
get_info_field
[
R $n cluster info
]
$field
get_info_field
[
R $n cluster info
]
$field
}
}
# Return the value of the specified INFO field.
proc s
{
n field
}
{
get_info_field
[
R $n info
]
$field
}
# Assuming nodes are reest, this function performs slots allocation.
# Assuming nodes are reest, this function performs slots allocation.
# Only the first 'n' nodes are used.
# Only the first 'n' nodes are used.
proc cluster_allocate_slots
{
n
}
{
proc cluster_allocate_slots
{
n
}
{
...
...
tests/cluster/tests/16-transactions-on-replica.tcl
View file @
ec2d1807
...
@@ -15,6 +15,7 @@ set replica [Rn 1]
...
@@ -15,6 +15,7 @@ set replica [Rn 1]
test
"Cant read from replica without READONLY"
{
test
"Cant read from replica without READONLY"
{
$primary SET a 1
$primary SET a 1
wait_for_ofs_sync $primary $replica
catch
{
$replica
GET a
}
err
catch
{
$replica
GET a
}
err
assert
{[
string range $err 0 4
]
eq
{
MOVED
}}
assert
{[
string range $err 0 4
]
eq
{
MOVED
}}
}
}
...
@@ -28,6 +29,7 @@ test "Can preform HSET primary and HGET from replica" {
...
@@ -28,6 +29,7 @@ test "Can preform HSET primary and HGET from replica" {
$primary HSET h a 1
$primary HSET h a 1
$primary HSET h b 2
$primary HSET h b 2
$primary HSET h c 3
$primary HSET h c 3
wait_for_ofs_sync $primary $replica
assert
{[
$replica
HGET h a
]
eq
{
1
}}
assert
{[
$replica
HGET h a
]
eq
{
1
}}
assert
{[
$replica
HGET h b
]
eq
{
2
}}
assert
{[
$replica
HGET h b
]
eq
{
2
}}
assert
{[
$replica
HGET h c
]
eq
{
3
}}
assert
{[
$replica
HGET h c
]
eq
{
3
}}
...
...
tests/cluster/tests/17-diskless-load-swapdb.tcl
View file @
ec2d1807
...
@@ -22,6 +22,8 @@ test "Right to restore backups when fail to diskless load " {
...
@@ -22,6 +22,8 @@ test "Right to restore backups when fail to diskless load " {
$replica READONLY
$replica READONLY
$replica config set repl-diskless-load swapdb
$replica config set repl-diskless-load swapdb
$replica config set appendonly no
$replica config set save
""
$replica config rewrite
$replica config rewrite
$master config set repl-backlog-size 1024
$master config set repl-backlog-size 1024
$master config set repl-diskless-sync yes
$master config set repl-diskless-sync yes
...
@@ -38,7 +40,8 @@ test "Right to restore backups when fail to diskless load " {
...
@@ -38,7 +40,8 @@ test "Right to restore backups when fail to diskless load " {
assert_equal
{
1
}
[
$replica
get $slot0_key
]
assert_equal
{
1
}
[
$replica
get $slot0_key
]
assert_equal $slot0_key
[
$replica
CLUSTER GETKEYSINSLOT 0 1
]
assert_equal $slot0_key
[
$replica
CLUSTER GETKEYSINSLOT 0 1
]
# Kill the replica
# Save an RDB and kill the replica
$replica save
kill_instance redis $replica_id
kill_instance redis $replica_id
# Delete the key from master
# Delete the key from master
...
@@ -60,13 +63,12 @@ test "Right to restore backups when fail to diskless load " {
...
@@ -60,13 +63,12 @@ test "Right to restore backups when fail to diskless load " {
restart_instance redis $replica_id
restart_instance redis $replica_id
$replica READONLY
$replica READONLY
# Start full sync
# Start full sync
, wait till after db is flushed
(
backed up
)
wait_for_condition 500 10
{
wait_for_condition 500 10
{
[
s
tring match
"*sync*"
[
$replica
role
]]
[
s
$replica_id loading
]
eq 1
}
else
{
}
else
{
fail
"Fail to full sync"
fail
"Fail to full sync"
}
}
after 100
# Kill master, abort full sync
# Kill master, abort full sync
kill_instance redis $master_id
kill_instance redis $master_id
...
@@ -74,4 +76,4 @@ test "Right to restore backups when fail to diskless load " {
...
@@ -74,4 +76,4 @@ test "Right to restore backups when fail to diskless load " {
# Replica keys and keys to slots map still both are right
# Replica keys and keys to slots map still both are right
assert_equal
{
1
}
[
$replica
get $slot0_key
]
assert_equal
{
1
}
[
$replica
get $slot0_key
]
assert_equal $slot0_key
[
$replica
CLUSTER GETKEYSINSLOT 0 1
]
assert_equal $slot0_key
[
$replica
CLUSTER GETKEYSINSLOT 0 1
]
}
}
\ No newline at end of file
tests/cluster/tests/18-info.tcl
0 → 100644
View file @
ec2d1807
# Check cluster info stats
source
"../tests/includes/init-tests.tcl"
test
"Create a primary with a replica"
{
create_cluster 2 0
}
test
"Cluster should start ok"
{
assert_cluster_state ok
}
set primary1
[
Rn 0
]
set primary2
[
Rn 1
]
proc cmdstat
{
instace cmd
}
{
return
[
cmdrstat $cmd $instace
]
}
proc errorstat
{
instace cmd
}
{
return
[
errorrstat $cmd $instace
]
}
test
"errorstats: rejected call due to MOVED Redirection"
{
$primary1 config resetstat
$primary2 config resetstat
assert_match
{}
[
errorstat $primary1 MOVED
]
assert_match
{}
[
errorstat $primary2 MOVED
]
# we know that one will have a MOVED reply and one will succeed
catch
{
$primary1
set key b
}
replyP1
catch
{
$primary2
set key b
}
replyP2
# sort servers so we know which one failed
if
{
$reply
P1 eq
{
OK
}}
{
assert_match
{
MOVED*
}
$replyP2
set pok $primary1
set perr $primary2
}
else
{
assert_match
{
MOVED*
}
$replyP1
set pok $primary2
set perr $primary1
}
assert_match
{}
[
errorstat $pok MOVED
]
assert_match
{
*count=1*
}
[
errorstat $perr MOVED
]
assert_match
{
*calls=0,*,rejected_calls=1,failed_calls=0
}
[
cmdstat $perr set
]
}
tests/integration/rdb.tcl
View file @
ec2d1807
...
@@ -198,3 +198,94 @@ test {client freed during loading} {
...
@@ -198,3 +198,94 @@ test {client freed during loading} {
exec kill
[
srv 0 pid
]
exec kill
[
srv 0 pid
]
}
}
}
}
# Our COW metrics
(
Private_Dirty
)
work only on Linux
set system_name
[
string tolower
[
exec uname -s
]]
if
{
$system
_name eq
{
linux
}}
{
start_server
{
overrides
{
save
""
}}
{
test
{
Test child sending COW info
}
{
# make sure that rdb_last_cow_size and current_cow_size are zero
(
the test using new server
)
,
# so that the comparisons during the test will be valid
assert
{[
s current_cow_size
]
== 0
}
assert
{[
s rdb_last_cow_size
]
== 0
}
# using a 200us delay, the bgsave is empirically taking about 10 seconds.
# we need it to take more than some 5 seconds, since redis only report COW once a second.
r config set rdb-key-save-delay 200
r config set loglevel debug
# populate the db with 10k keys of 4k each
set rd
[
redis_deferring_client 0
]
set size 4096
set cmd_count 10000
for
{
set k 0
}
{
$k
< $cmd_count
}
{
incr k
}
{
$rd set key$k
[
string repeat A $size
]
}
for
{
set k 0
}
{
$k
< $cmd_count
}
{
incr k
}
{
catch
{
$rd read
}
}
$rd close
# start background rdb save
r bgsave
# on each iteration, we will write some key to the server to trigger copy-on-write, and
# wait to see that it reflected in INFO.
set iteration 1
while 1
{
# take a sample before writing new data to the server
set cow_size
[
s current_cow_size
]
if
{
$::verbose
}
{
puts
"COW info before copy-on-write:
$cow
_size"
}
# trigger copy-on-write
r setrange key$iteration 0
[
string repeat B $size
]
# wait to see that current_cow_size value updated
(
as long as the child is in progress
)
wait_for_condition 80 100
{
[
s rdb_bgsave_in_progress
]
== 0 ||
[
s current_cow_size
]
>= $cow_size + $size
}
else
{
if
{
$::verbose
}
{
puts
"COW info on fail:
[
s current_cow_size
]
"
puts
[
exec tail -n 100 <
[
srv 0 stdout
]]
}
fail
"COW info wasn't reported"
}
# for no accurate, stop after 2 iterations
if
{
!$::accurate && $iteration == 2
}
{
break
}
# stop iterating if the bgsave completed
if
{
[
s rdb_bgsave_in_progress
]
== 0
}
{
break
}
incr iteration 1
}
# make sure we saw report of current_cow_size
if
{
$iteration
< 2 && $::verbose
}
{
puts
[
exec tail -n 100 <
[
srv 0 stdout
]]
}
assert_morethan_equal $iteration 2
# if bgsave completed, check that rdb_last_cow_size
(
fork exit report
)
# is at least 90% of last rdb_active_cow_size.
if
{
[
s rdb_bgsave_in_progress
]
== 0
}
{
set final_cow
[
s rdb_last_cow_size
]
set cow_size
[
expr $cow_size * 0.9
]
if
{
$final
_cow < $cow_size && $::verbose
}
{
puts
[
exec tail -n 100 <
[
srv 0 stdout
]]
}
assert_morethan_equal $final_cow $cow_size
}
}
}
}
;
# system_name
tests/modules/propagate.c
View file @
ec2d1807
...
@@ -51,18 +51,31 @@ void timerHandler(RedisModuleCtx *ctx, void *data) {
...
@@ -51,18 +51,31 @@ void timerHandler(RedisModuleCtx *ctx, void *data) {
RedisModule_Replicate
(
ctx
,
"INCR"
,
"c"
,
"timer"
);
RedisModule_Replicate
(
ctx
,
"INCR"
,
"c"
,
"timer"
);
times
++
;
times
++
;
if
(
times
<
10
)
if
(
times
<
3
)
RedisModule_CreateTimer
(
ctx
,
100
,
timerHandler
,
NULL
);
RedisModule_CreateTimer
(
ctx
,
100
,
timerHandler
,
NULL
);
else
else
times
=
0
;
times
=
0
;
}
}
int
propagateTestTimerCommand
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
REDISMODULE_NOT_USED
(
argv
);
REDISMODULE_NOT_USED
(
argc
);
RedisModuleTimerID
timer_id
=
RedisModule_CreateTimer
(
ctx
,
100
,
timerHandler
,
NULL
);
REDISMODULE_NOT_USED
(
timer_id
);
RedisModule_ReplyWithSimpleString
(
ctx
,
"OK"
);
return
REDISMODULE_OK
;
}
/* The thread entry point. */
/* The thread entry point. */
void
*
threadMain
(
void
*
arg
)
{
void
*
threadMain
(
void
*
arg
)
{
REDISMODULE_NOT_USED
(
arg
);
REDISMODULE_NOT_USED
(
arg
);
RedisModuleCtx
*
ctx
=
RedisModule_GetThreadSafeContext
(
NULL
);
RedisModuleCtx
*
ctx
=
RedisModule_GetThreadSafeContext
(
NULL
);
RedisModule_SelectDb
(
ctx
,
9
);
/* Tests ran in database number 9. */
RedisModule_SelectDb
(
ctx
,
9
);
/* Tests ran in database number 9. */
for
(
int
i
=
0
;
i
<
10
;
i
++
)
{
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
RedisModule_ThreadSafeContextLock
(
ctx
);
RedisModule_ThreadSafeContextLock
(
ctx
);
RedisModule_Replicate
(
ctx
,
"INCR"
,
"c"
,
"a-from-thread"
);
RedisModule_Replicate
(
ctx
,
"INCR"
,
"c"
,
"a-from-thread"
);
RedisModule_Replicate
(
ctx
,
"INCR"
,
"c"
,
"b-from-thread"
);
RedisModule_Replicate
(
ctx
,
"INCR"
,
"c"
,
"b-from-thread"
);
...
@@ -72,15 +85,11 @@ void *threadMain(void *arg) {
...
@@ -72,15 +85,11 @@ void *threadMain(void *arg) {
return
NULL
;
return
NULL
;
}
}
int
propagateTestCommand
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
int
propagateTest
Thread
Command
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
{
REDISMODULE_NOT_USED
(
argv
);
REDISMODULE_NOT_USED
(
argv
);
REDISMODULE_NOT_USED
(
argc
);
REDISMODULE_NOT_USED
(
argc
);
RedisModuleTimerID
timer_id
=
RedisModule_CreateTimer
(
ctx
,
100
,
timerHandler
,
NULL
);
REDISMODULE_NOT_USED
(
timer_id
);
pthread_t
tid
;
pthread_t
tid
;
if
(
pthread_create
(
&
tid
,
NULL
,
threadMain
,
NULL
)
!=
0
)
if
(
pthread_create
(
&
tid
,
NULL
,
threadMain
,
NULL
)
!=
0
)
return
RedisModule_ReplyWithError
(
ctx
,
"-ERR Can't start thread"
);
return
RedisModule_ReplyWithError
(
ctx
,
"-ERR Can't start thread"
);
...
@@ -90,7 +99,7 @@ int propagateTestCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc
...
@@ -90,7 +99,7 @@ int propagateTestCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc
return
REDISMODULE_OK
;
return
REDISMODULE_OK
;
}
}
int
propagateTest
2
Command
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
int
propagateTest
Simple
Command
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
{
REDISMODULE_NOT_USED
(
argv
);
REDISMODULE_NOT_USED
(
argv
);
REDISMODULE_NOT_USED
(
argc
);
REDISMODULE_NOT_USED
(
argc
);
...
@@ -102,7 +111,7 @@ int propagateTest2Command(RedisModuleCtx *ctx, RedisModuleString **argv, int arg
...
@@ -102,7 +111,7 @@ int propagateTest2Command(RedisModuleCtx *ctx, RedisModuleString **argv, int arg
return
REDISMODULE_OK
;
return
REDISMODULE_OK
;
}
}
int
propagateTest
3
Command
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
int
propagateTest
Mixed
Command
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
{
REDISMODULE_NOT_USED
(
argv
);
REDISMODULE_NOT_USED
(
argv
);
REDISMODULE_NOT_USED
(
argc
);
REDISMODULE_NOT_USED
(
argc
);
...
@@ -129,18 +138,23 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
...
@@ -129,18 +138,23 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
if
(
RedisModule_Init
(
ctx
,
"propagate-test"
,
1
,
REDISMODULE_APIVER_1
)
if
(
RedisModule_Init
(
ctx
,
"propagate-test"
,
1
,
REDISMODULE_APIVER_1
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
RedisModule_CreateCommand
(
ctx
,
"propagate-test"
,
if
(
RedisModule_CreateCommand
(
ctx
,
"propagate-test.timer"
,
propagateTestCommand
,
propagateTestTimerCommand
,
""
,
1
,
1
,
1
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
RedisModule_CreateCommand
(
ctx
,
"propagate-test.thread"
,
propagateTestThreadCommand
,
""
,
1
,
1
,
1
)
==
REDISMODULE_ERR
)
""
,
1
,
1
,
1
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
return
REDISMODULE_ERR
;
if
(
RedisModule_CreateCommand
(
ctx
,
"propagate-test
-2
"
,
if
(
RedisModule_CreateCommand
(
ctx
,
"propagate-test
.simple
"
,
propagateTest
2
Command
,
propagateTest
Simple
Command
,
""
,
1
,
1
,
1
)
==
REDISMODULE_ERR
)
""
,
1
,
1
,
1
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
return
REDISMODULE_ERR
;
if
(
RedisModule_CreateCommand
(
ctx
,
"propagate-test
-3
"
,
if
(
RedisModule_CreateCommand
(
ctx
,
"propagate-test
.mixed
"
,
propagateTest
3
Command
,
propagateTest
Mixed
Command
,
""
,
1
,
1
,
1
)
==
REDISMODULE_ERR
)
""
,
1
,
1
,
1
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
return
REDISMODULE_ERR
;
...
...
tests/support/redis.tcl
View file @
ec2d1807
...
@@ -214,20 +214,19 @@ proc ::redis::redis_multi_bulk_read {id fd} {
...
@@ -214,20 +214,19 @@ proc ::redis::redis_multi_bulk_read {id fd} {
proc ::redis::redis_read_map
{
id fd
}
{
proc ::redis::redis_read_map
{
id fd
}
{
set count
[
redis_read_line $fd
]
set count
[
redis_read_line $fd
]
if
{
$count
== -1
}
return
{}
if
{
$count
== -1
}
return
{}
set
l
{}
set
d
{}
set err
{}
set err
{}
for
{
set i 0
}
{
$i
< $count
}
{
incr i
}
{
for
{
set i 0
}
{
$i
< $count
}
{
incr i
}
{
if
{[
catch
{
if
{[
catch
{
set t
{}
set k
[
redis_read_reply $id $fd
]
;
# key
lappend t
[
redis_read_reply $id $fd
]
;
# key
set v
[
redis_read_reply $id $fd
]
;
# value
lappend t
[
redis_read_reply $id $fd
]
;
# value
dict set d $k $v
lappend l $t
}
e
]
&& $err eq
{}}
{
}
e
]
&& $err eq
{}}
{
set err $e
set err $e
}
}
}
}
if
{
$err
ne
{}}
{
return -code error $err
}
if
{
$err
ne
{}}
{
return -code error $err
}
return $
l
return $
d
}
}
proc ::redis::redis_read_line fd
{
proc ::redis::redis_read_line fd
{
...
...
tests/support/server.tcl
View file @
ec2d1807
...
@@ -50,11 +50,17 @@ proc kill_server config {
...
@@ -50,11 +50,17 @@ proc kill_server config {
tags
{
"leaks"
}
{
tags
{
"leaks"
}
{
test
"Check for memory leaks (pid
$pid
)"
{
test
"Check for memory leaks (pid
$pid
)"
{
set output
{
0 leaks
}
set output
{
0 leaks
}
catch
{
exec leaks $pid
}
output
catch
{
exec leaks $pid
}
output option
if
{[
string match
{
*process does not exist*
}
$output
]
||
# In a few tests we kill the server process, so leaks will not find it.
[
string match
{
*cannot examine*
}
$output
]}
{
# It'll exits with exit code >1 on error, so we ignore these.
# In a few tests we kill the server process.
if
{[
dict exists $option -errorcode
]}
{
set output
"0 leaks"
set details
[
dict get $option -errorcode
]
if
{[
lindex $details 0
]
eq
"CHILDSTATUS"
}
{
set status
[
lindex $details 2
]
if
{
$status
> 1
}
{
set output
"0 leaks"
}
}
}
}
set output
set output
}
{
*0 leaks*
}
}
{
*0 leaks*
}
...
...
tests/support/test.tcl
View file @
ec2d1807
...
@@ -31,36 +31,48 @@ proc assert_match {pattern value} {
...
@@ -31,36 +31,48 @@ proc assert_match {pattern value} {
}
}
}
}
proc assert_failed
{
expected_err detail
}
{
if
{
$detail
ne
""
}
{
set detail
"(detail:
$detail
)"
}
else
{
set detail
"(context:
[
info frame -2
]
)"
}
error
"assertion:
$expected
_err
$detail
"
}
proc assert_equal
{
value expected
{
detail
""
}}
{
proc assert_equal
{
value expected
{
detail
""
}}
{
if
{
$expected
ne $value
}
{
if
{
$expected
ne $value
}
{
if
{
$detail
ne
""
}
{
assert_failed
"Expected '
$value
' to be equal to '
$expected
'"
$detail
set detail
"(detail:
$detail
)"
}
else
{
set detail
"(context:
[
info frame -1
]
)"
}
error
"assertion:Expected '
$value
' to be equal to '
$expected
'
$detail
"
}
}
}
}
proc assert_lessthan
{
value expected
{
detail
""
}}
{
proc assert_lessthan
{
value expected
{
detail
""
}}
{
if
{
!
(
$value
< $expected
)}
{
if
{
!
(
$value
< $expected
)}
{
if
{
$detail
ne
""
}
{
assert_failed
"Expected '
$value
' to be less than '
$expected
'"
$detail
set detail
"(detail:
$detail
)"
}
}
else
{
}
set detail
"(context:
[
info frame -1
]
)"
}
proc assert_lessthan_equal
{
value expected
{
detail
""
}}
{
error
"assertion:Expected '
$value
' to be lessthan to '
$expected
'
$detail
"
if
{
!
(
$value
<= $expected
)}
{
assert_failed
"Expected '
$value
' to be less than or equal to '
$expected
'"
$detail
}
}
proc assert_morethan
{
value expected
{
detail
""
}}
{
if
{
!
(
$value
> $expected
)}
{
assert_failed
"Expected '
$value
' to be more than '
$expected
'"
$detail
}
}
proc assert_morethan_equal
{
value expected
{
detail
""
}}
{
if
{
!
(
$value
>= $expected
)}
{
assert_failed
"Expected '
$value
' to be more than or equal to '
$expected
'"
$detail
}
}
}
}
proc assert_range
{
value min max
{
detail
""
}}
{
proc assert_range
{
value min max
{
detail
""
}}
{
if
{
!
(
$value
<= $max && $value >= $min
)}
{
if
{
!
(
$value
<= $max && $value >= $min
)}
{
if
{
$detail
ne
""
}
{
assert_failed
"Expected '
$value
' to be between to '
$min
' and '
$max
'"
$detail
set detail
"(detail:
$detail
)"
}
else
{
set detail
"(context:
[
info frame -1
]
)"
}
error
"assertion:Expected '
$value
' to be between to '
$min
' and '
$max
'
$detail
"
}
}
}
}
...
...
tests/support/util.tcl
View file @
ec2d1807
...
@@ -561,6 +561,12 @@ proc cmdrstat {cmd r} {
...
@@ -561,6 +561,12 @@ proc cmdrstat {cmd r} {
}
}
}
}
proc errorrstat
{
cmd r
}
{
if
{[
regexp
"
\r\n
errorstat_
$cmd:
(.*?)
\r\n
"
[
$r
info errorstats
]
_ value
]}
{
set _ $value
}
}
proc generate_fuzzy_traffic_on_key
{
key duration
}
{
proc generate_fuzzy_traffic_on_key
{
key duration
}
{
# Commands per type, blocking commands removed
# Commands per type, blocking commands removed
# TODO: extract these from help.h or elsewhere, and improve to include other types
# TODO: extract these from help.h or elsewhere, and improve to include other types
...
...
tests/test_helper.tcl
View file @
ec2d1807
...
@@ -18,6 +18,7 @@ set ::all_tests {
...
@@ -18,6 +18,7 @@ set ::all_tests {
unit/protocol
unit/protocol
unit/keyspace
unit/keyspace
unit/scan
unit/scan
unit/info
unit/type/string
unit/type/string
unit/type/incr
unit/type/incr
unit/type/list
unit/type/list
...
...
tests/unit/auth.tcl
View file @
ec2d1807
...
@@ -25,3 +25,44 @@ start_server {tags {"auth"} overrides {requirepass foobar}} {
...
@@ -25,3 +25,44 @@ start_server {tags {"auth"} overrides {requirepass foobar}} {
r incr foo
r incr foo
}
{
101
}
}
{
101
}
}
}
start_server
{
tags
{
"auth_binary_password"
}}
{
test
{
AUTH fails when binary password is wrong
}
{
r config set requirepass
"abc
\x00
def"
catch
{
r auth abc
}
err
set _ $err
}
{
WRONGPASS*
}
test
{
AUTH succeeds when binary password is correct
}
{
r config set requirepass
"abc
\x00
def"
r auth
"abc
\x00
def"
}
{
OK
}
start_server
{
tags
{
"masterauth"
}}
{
set master
[
srv -1 client
]
set master_host
[
srv -1 host
]
set master_port
[
srv -1 port
]
set slave
[
srv 0 client
]
test
{
MASTERAUTH test with binary password
}
{
$master config set requirepass
"abc
\x00
def"
# Configure the replica with masterauth
set loglines
[
count_log_lines 0
]
$slave slaveof $master_host $master_port
$slave config set masterauth
"abc"
# Verify replica is not able to sync with master
wait_for_log_messages 0
{
"*Unable to AUTH to MASTER*"
}
$loglines 1000 10
assert_equal
{
down
}
[
s 0 master_link_status
]
# Test replica with the correct masterauth
$slave config set masterauth
"abc
\x00
def"
wait_for_condition 50 100
{
[
s 0 master_link_status
]
eq
{
up
}
}
else
{
fail
"Can't turn the instance into a replica"
}
}
}
}
tests/unit/geo.tcl
View file @
ec2d1807
...
@@ -74,6 +74,49 @@ start_server {tags {"geo"}} {
...
@@ -74,6 +74,49 @@ start_server {tags {"geo"}} {
r geoadd nyc -73.9454966 40.747533
"lic market"
r geoadd nyc -73.9454966 40.747533
"lic market"
}
{
0
}
}
{
0
}
test
{
GEOADD update with CH option
}
{
assert_equal 1
[
r geoadd nyc CH 40.747533 -73.9454966
"lic market"
]
lassign
[
lindex
[
r geopos nyc
"lic market"
]
0
]
x1 y1
assert
{
abs
(
$x1
)
- 40.747 < 0.001
}
assert
{
abs
(
$y1
)
- 73.945 < 0.001
}
}
{}
test
{
GEOADD update with NX option
}
{
assert_equal 0
[
r geoadd nyc NX -73.9454966 40.747533
"lic market"
]
lassign
[
lindex
[
r geopos nyc
"lic market"
]
0
]
x1 y1
assert
{
abs
(
$x1
)
- 40.747 < 0.001
}
assert
{
abs
(
$y1
)
- 73.945 < 0.001
}
}
{}
test
{
GEOADD update with XX option
}
{
assert_equal 0
[
r geoadd nyc XX -83.9454966 40.747533
"lic market"
]
lassign
[
lindex
[
r geopos nyc
"lic market"
]
0
]
x1 y1
assert
{
abs
(
$x1
)
- 83.945 < 0.001
}
assert
{
abs
(
$y1
)
- 40.747 < 0.001
}
}
{}
test
{
GEOADD update with CH NX option
}
{
r geoadd nyc CH NX -73.9454966 40.747533
"lic market"
}
{
0
}
test
{
GEOADD update with CH XX option
}
{
r geoadd nyc CH XX -73.9454966 40.747533
"lic market"
}
{
1
}
test
{
GEOADD update with XX NX option will return syntax error
}
{
catch
{
r geoadd nyc xx nx -73.9454966 40.747533
"lic market"
}
err
set err
}
{
ERR*syntax*
}
test
{
GEOADD update with invalid option
}
{
catch
{
r geoadd nyc ch xx foo -73.9454966 40.747533
"lic market"
}
err
set err
}
{
ERR*syntax*
}
test
{
GEOADD invalid coordinates
}
{
test
{
GEOADD invalid coordinates
}
{
catch
{
catch
{
r geoadd nyc -73.9454966 40.747533
"lic market"
\
r geoadd nyc -73.9454966 40.747533
"lic market"
\
...
@@ -135,6 +178,19 @@ start_server {tags {"geo"}} {
...
@@ -135,6 +178,19 @@ start_server {tags {"geo"}} {
r georadius nyc -73.9798091 40.7598464 10 km COUNT 3
r georadius nyc -73.9798091 40.7598464 10 km COUNT 3
}
{{
central park n/q/r
}
4545
{
union square
}}
}
{{
central park n/q/r
}
4545
{
union square
}}
test
{
GEORADIUS with ANY not sorted by default
}
{
r georadius nyc -73.9798091 40.7598464 10 km COUNT 3 ANY
}
{{
wtc one
}
{
union square
}
{
central park n/q/r
}}
test
{
GEORADIUS with ANY sorted by ASC
}
{
r georadius nyc -73.9798091 40.7598464 10 km COUNT 3 ANY ASC
}
{{
central park n/q/r
}
{
union square
}
{
wtc one
}}
test
{
GEORADIUS with ANY but no COUNT
}
{
catch
{
r georadius nyc -73.9798091 40.7598464 10 km ANY ASC
}
e
set e
}
{
ERR*ANY*requires*COUNT*
}
test
{
GEORADIUS with COUNT but missing integer argument
}
{
test
{
GEORADIUS with COUNT but missing integer argument
}
{
catch
{
r georadius nyc -73.9798091 40.7598464 10 km COUNT
}
e
catch
{
r georadius nyc -73.9798091 40.7598464 10 km COUNT
}
e
set e
set e
...
...
tests/unit/info.tcl
0 → 100644
View file @
ec2d1807
proc cmdstat
{
cmd
}
{
return
[
cmdrstat $cmd r
]
}
proc errorstat
{
cmd
}
{
return
[
errorrstat $cmd r
]
}
start_server
{
tags
{
"info"
}}
{
start_server
{}
{
test
{
errorstats: failed call authentication error
}
{
r config resetstat
assert_match
{}
[
errorstat ERR
]
assert_equal
[
s total_error_replies
]
0
catch
{
r auth k
}
e
assert_match
{
ERR AUTH*
}
$e
assert_match
{
*count=1*
}
[
errorstat ERR
]
assert_match
{
*calls=1,*,rejected_calls=0,failed_calls=1
}
[
cmdstat auth
]
assert_equal
[
s total_error_replies
]
1
r config resetstat
assert_match
{}
[
errorstat ERR
]
}
test
{
errorstats: failed call within MULTI/EXEC
}
{
r config resetstat
assert_match
{}
[
errorstat ERR
]
assert_equal
[
s total_error_replies
]
0
r multi
r set a b
r auth a
catch
{
r exec
}
e
assert_match
{
ERR AUTH*
}
$e
assert_match
{
*count=1*
}
[
errorstat ERR
]
assert_match
{
*calls=1,*,rejected_calls=0,failed_calls=0
}
[
cmdstat set
]
assert_match
{
*calls=1,*,rejected_calls=0,failed_calls=1
}
[
cmdstat auth
]
assert_match
{
*calls=1,*,rejected_calls=0,failed_calls=0
}
[
cmdstat exec
]
assert_equal
[
s total_error_replies
]
1
# MULTI/EXEC command errors should still be pinpointed to him
catch
{
r exec
}
e
assert_match
{
ERR EXEC without MULTI
}
$e
assert_match
{
*calls=2,*,rejected_calls=0,failed_calls=1
}
[
cmdstat exec
]
assert_match
{
*count=2*
}
[
errorstat ERR
]
assert_equal
[
s total_error_replies
]
2
}
test
{
errorstats: failed call within LUA
}
{
r config resetstat
assert_match
{}
[
errorstat ERR
]
assert_equal
[
s total_error_replies
]
0
catch
{
r eval
{
redis.pcall
(
'XGROUP', 'CREATECONSUMER', 's1', 'mygroup', 'consumer'
)
return
}
0
}
e
assert_match
{
*count=1*
}
[
errorstat ERR
]
assert_match
{
*calls=1,*,rejected_calls=0,failed_calls=1
}
[
cmdstat xgroup
]
assert_match
{
*calls=1,*,rejected_calls=0,failed_calls=0
}
[
cmdstat eval
]
# EVAL command errors should still be pinpointed to him
catch
{
r eval a
}
e
assert_match
{
ERR wrong*
}
$e
assert_match
{
*calls=1,*,rejected_calls=1,failed_calls=0
}
[
cmdstat eval
]
assert_match
{
*count=2*
}
[
errorstat ERR
]
assert_equal
[
s total_error_replies
]
2
}
test
{
errorstats: failed call NOGROUP error
}
{
r config resetstat
assert_match
{}
[
errorstat NOGROUP
]
r del mystream
r XADD mystream * f v
catch
{
r XGROUP CREATECONSUMER mystream mygroup consumer
}
e
assert_match
{
NOGROUP*
}
$e
assert_match
{
*count=1*
}
[
errorstat NOGROUP
]
assert_match
{
*calls=1,*,rejected_calls=0,failed_calls=1
}
[
cmdstat xgroup
]
r config resetstat
assert_match
{}
[
errorstat NOGROUP
]
}
test
{
errorstats: rejected call unknown command
}
{
r config resetstat
assert_equal
[
s total_error_replies
]
0
assert_match
{}
[
errorstat ERR
]
catch
{
r asdf
}
e
assert_match
{
ERR unknown*
}
$e
assert_match
{
*count=1*
}
[
errorstat ERR
]
assert_equal
[
s total_error_replies
]
1
r config resetstat
assert_match
{}
[
errorstat ERR
]
}
test
{
errorstats: rejected call within MULTI/EXEC
}
{
r config resetstat
assert_equal
[
s total_error_replies
]
0
assert_match
{}
[
errorstat ERR
]
r multi
catch
{
r set
}
e
assert_match
{
ERR wrong number of arguments*
}
$e
catch
{
r exec
}
e
assert_match
{
EXECABORT*
}
$e
assert_match
{
*count=1*
}
[
errorstat ERR
]
assert_equal
[
s total_error_replies
]
1
assert_match
{
*calls=0,*,rejected_calls=1,failed_calls=0
}
[
cmdstat set
]
assert_match
{
*calls=1,*,rejected_calls=0,failed_calls=0
}
[
cmdstat multi
]
assert_match
{
*calls=1,*,rejected_calls=0,failed_calls=0
}
[
cmdstat exec
]
assert_equal
[
s total_error_replies
]
1
r config resetstat
assert_match
{}
[
errorstat ERR
]
}
test
{
errorstats: rejected call due to wrong arity
}
{
r config resetstat
assert_equal
[
s total_error_replies
]
0
assert_match
{}
[
errorstat ERR
]
catch
{
r set k
}
e
assert_match
{
ERR wrong number of arguments*
}
$e
assert_match
{
*count=1*
}
[
errorstat ERR
]
assert_match
{
*calls=0,*,rejected_calls=1,failed_calls=0
}
[
cmdstat set
]
# ensure that after a rejected command, valid ones are counted properly
r set k1 v1
r set k2 v2
assert_match
{
calls=2,*,rejected_calls=1,failed_calls=0
}
[
cmdstat set
]
assert_equal
[
s total_error_replies
]
1
}
test
{
errorstats: rejected call by OOM error
}
{
r config resetstat
assert_equal
[
s total_error_replies
]
0
assert_match
{}
[
errorstat OOM
]
r config set maxmemory 1
catch
{
r set a b
}
e
assert_match
{
OOM*
}
$e
assert_match
{
*count=1*
}
[
errorstat OOM
]
assert_match
{
*calls=0,*,rejected_calls=1,failed_calls=0
}
[
cmdstat set
]
assert_equal
[
s total_error_replies
]
1
r config resetstat
assert_match
{}
[
errorstat OOM
]
}
test
{
errorstats: rejected call by authorization error
}
{
r config resetstat
assert_equal
[
s total_error_replies
]
0
assert_match
{}
[
errorstat NOPERM
]
r ACL SETUSER alice on >p1pp0 ~cached:* +get +info +config
r auth alice p1pp0
catch
{
r set a b
}
e
assert_match
{
NOPERM*
}
$e
assert_match
{
*count=1*
}
[
errorstat NOPERM
]
assert_match
{
*calls=0,*,rejected_calls=1,failed_calls=0
}
[
cmdstat set
]
assert_equal
[
s total_error_replies
]
1
r config resetstat
assert_match
{}
[
errorstat NOPERM
]
}
}
}
tests/unit/memefficiency.tcl
View file @
ec2d1807
...
@@ -38,7 +38,7 @@ start_server {tags {"memefficiency"}} {
...
@@ -38,7 +38,7 @@ start_server {tags {"memefficiency"}} {
run_solo
{
defrag
}
{
run_solo
{
defrag
}
{
start_server
{
tags
{
"defrag"
}
overrides
{
appendonly yes auto-aof-rewrite-percentage 0 save
""
}}
{
start_server
{
tags
{
"defrag"
}
overrides
{
appendonly yes auto-aof-rewrite-percentage 0 save
""
}}
{
if
{[
string match
{
*jemalloc*
}
[
s mem_allocator
]]}
{
if
{[
string match
{
*jemalloc*
}
[
s mem_allocator
]]
&&
[
r debug mallctl arenas.page
]
<= 8192
}
{
test
"Active defrag"
{
test
"Active defrag"
{
r config set hz 100
r config set hz 100
r config set activedefrag no
r config set activedefrag no
...
...
tests/unit/moduleapi/propagate.tcl
View file @
ec2d1807
...
@@ -14,25 +14,103 @@ tags "modules" {
...
@@ -14,25 +14,103 @@ tags "modules" {
# Start the replication process...
# Start the replication process...
$replica replicaof $master_host $master_port
$replica replicaof $master_host $master_port
wait_for_sync $replica
wait_for_sync $replica
after 1000
after 1000
$master propagate-test
wait_for_condition 5000 10
{
test
{
module propagates from timer
}
{
([
$replica
get timer
]
eq
"10"
)
&&
\
set repl
[
attach_to_replication_stream
]
([
$replica
get a-from-thread
]
eq
"10"
)
}
else
{
$master propagate-test.timer
fail
"The two counters don't match the expected value."
wait_for_condition 5000 10
{
[
$replica
get timer
]
eq
"3"
}
else
{
fail
"The two counters don't match the expected value."
}
assert_replication_stream $repl
{
{
select *
}
{
multi
}
{
incr timer
}
{
exec
}
{
multi
}
{
incr timer
}
{
exec
}
{
multi
}
{
incr timer
}
{
exec
}
}
close_replication_stream $repl
}
}
$master propagate-test-2
test
{
module propagates from thread
}
{
$master propagate-test-3
set repl
[
attach_to_replication_stream
]
$master multi
$master propagate-test-2
$master propagate-test.thread
$master propagate-test-3
$master exec
wait_for_condition 5000 10
{
wait_for_ofs_sync $master $replica
[
$replica
get a-from-thread
]
eq
"3"
}
else
{
fail
"The two counters don't match the expected value."
}
assert_replication_stream $repl
{
{
select *
}
{
incr a-from-thread
}
{
incr b-from-thread
}
{
incr a-from-thread
}
{
incr b-from-thread
}
{
incr a-from-thread
}
{
incr b-from-thread
}
}
close_replication_stream $repl
}
test
{
module propagates from from command
}
{
set repl
[
attach_to_replication_stream
]
$master propagate-test.simple
$master propagate-test.mixed
# Note the 'after-call' propagation below is out of order
(
known limitation
)
assert_replication_stream $repl
{
{
select *
}
{
multi
}
{
incr counter-1
}
{
incr counter-2
}
{
exec
}
{
multi
}
{
incr using-call
}
{
incr after-call
}
{
incr counter-1
}
{
incr counter-2
}
{
exec
}
}
close_replication_stream $repl
}
test
{
module propagates from from multi-exec
}
{
set repl
[
attach_to_replication_stream
]
$master multi
$master propagate-test.simple
$master propagate-test.mixed
$master exec
wait_for_ofs_sync $master $replica
# Note the 'after-call' propagation below is out of order
(
known limitation
)
assert_replication_stream $repl
{
{
select *
}
{
multi
}
{
incr counter-1
}
{
incr counter-2
}
{
incr using-call
}
{
incr after-call
}
{
incr counter-1
}
{
incr counter-2
}
{
exec
}
}
close_replication_stream $repl
}
assert_equal
[
s -1 unexpected_error_replies
]
0
assert_equal
[
s -1 unexpected_error_replies
]
0
}
}
}
}
...
@@ -47,11 +125,11 @@ tags "modules aof" {
...
@@ -47,11 +125,11 @@ tags "modules aof" {
r config set auto-aof-rewrite-percentage 0
;
# Disable auto-rewrite.
r config set auto-aof-rewrite-percentage 0
;
# Disable auto-rewrite.
waitForBgrewriteaof r
waitForBgrewriteaof r
r propagate-test
-2
r propagate-test
.simple
r propagate-test
-3
r propagate-test
.mixed
r multi
r multi
r propagate-test
-2
r propagate-test
.simple
r propagate-test
-3
r propagate-test
.mixed
r exec
r exec
# Load the AOF
# Load the AOF
...
...
Prev
1
2
3
4
5
Next
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