mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 16:18:28 -05:00
2e1979a21e
This would mean that the effects of `CONFIG SET maxmemory` may not be visible once the command returns. That could anyway happen since incremental eviction was added in redis 6.2 (see #7653) We do this to fix one of the propagation bugs about eviction see #9890 and #10014.
605 lines
23 KiB
Tcl
605 lines
23 KiB
Tcl
set testmodule [file normalize tests/modules/propagate.so]
|
|
set keyspace_events [file normalize tests/modules/keyspace_events.so]
|
|
|
|
tags "modules" {
|
|
test {Modules can propagate in async and threaded contexts} {
|
|
start_server [list overrides [list loadmodule "$testmodule"]] {
|
|
set replica [srv 0 client]
|
|
set replica_host [srv 0 host]
|
|
set replica_port [srv 0 port]
|
|
$replica module load $keyspace_events
|
|
start_server [list overrides [list loadmodule "$testmodule"]] {
|
|
set master [srv 0 client]
|
|
set master_host [srv 0 host]
|
|
set master_port [srv 0 port]
|
|
$master module load $keyspace_events
|
|
|
|
# Start the replication process...
|
|
$replica replicaof $master_host $master_port
|
|
wait_for_sync $replica
|
|
after 1000
|
|
|
|
test {module propagates from timer} {
|
|
set repl [attach_to_replication_stream]
|
|
|
|
$master propagate-test.timer
|
|
|
|
wait_for_condition 500 10 {
|
|
[$replica get timer] eq "3"
|
|
} else {
|
|
fail "The two counters don't match the expected value."
|
|
}
|
|
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{incr timer}
|
|
{incr timer}
|
|
{incr timer}
|
|
}
|
|
close_replication_stream $repl
|
|
}
|
|
|
|
test {module propagation with notifications} {
|
|
set repl [attach_to_replication_stream]
|
|
|
|
$master set x y
|
|
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{incr notifications}
|
|
{set x y}
|
|
{exec}
|
|
}
|
|
close_replication_stream $repl
|
|
}
|
|
|
|
test {module propagation with notifications with multi} {
|
|
set repl [attach_to_replication_stream]
|
|
|
|
$master multi
|
|
$master set x1 y1
|
|
$master set x2 y2
|
|
$master exec
|
|
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{incr notifications}
|
|
{set x1 y1}
|
|
{incr notifications}
|
|
{set x2 y2}
|
|
{exec}
|
|
}
|
|
close_replication_stream $repl
|
|
}
|
|
|
|
test {module propagation with notifications with active-expire} {
|
|
$master debug set-active-expire 1
|
|
set repl [attach_to_replication_stream]
|
|
|
|
$master set asdf1 1 PX 300
|
|
$master set asdf2 2 PX 300
|
|
$master set asdf3 3 PX 300
|
|
|
|
wait_for_condition 500 10 {
|
|
[$replica keys asdf*] eq {}
|
|
} else {
|
|
fail "Not all keys have expired"
|
|
}
|
|
|
|
# Note whenever there's double notification: SET with PX issues two separate
|
|
# notifications: one for "set" and one for "expire"
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{incr notifications}
|
|
{incr notifications}
|
|
{set asdf1 1 PXAT *}
|
|
{exec}
|
|
{multi}
|
|
{incr notifications}
|
|
{incr notifications}
|
|
{set asdf2 2 PXAT *}
|
|
{exec}
|
|
{multi}
|
|
{incr notifications}
|
|
{incr notifications}
|
|
{set asdf3 3 PXAT *}
|
|
{exec}
|
|
{incr notifications}
|
|
{del asdf*}
|
|
{incr notifications}
|
|
{del asdf*}
|
|
{incr notifications}
|
|
{del asdf*}
|
|
}
|
|
close_replication_stream $repl
|
|
|
|
$master debug set-active-expire 0
|
|
}
|
|
|
|
test {module propagation with notifications with eviction case 1} {
|
|
$master flushall
|
|
$master set asdf1 1
|
|
$master set asdf2 2
|
|
$master set asdf3 3
|
|
|
|
$master config set maxmemory-policy allkeys-random
|
|
$master config set maxmemory 1
|
|
|
|
# Please note the following loop:
|
|
# We evict a key and send a notification, which does INCR on the "notifications" key, so
|
|
# that every time we evict any key, "notifications" key exist (it happens inside the
|
|
# performEvictions loop). So even evicting "notifications" causes INCR on "notifications".
|
|
# If maxmemory_eviction_tenacity would have been set to 100 this would be an endless loop, but
|
|
# since the default is 10, at some point the performEvictions loop would end.
|
|
# Bottom line: "notifications" always exists and we can't really determine the order of evictions
|
|
# This test is here only for sanity
|
|
|
|
wait_for_condition 500 10 {
|
|
[$replica dbsize] eq 1
|
|
} else {
|
|
fail "Not all keys have been evicted"
|
|
}
|
|
|
|
$master config set maxmemory 0
|
|
$master config set maxmemory-policy noeviction
|
|
}
|
|
|
|
test {module propagation with notifications with eviction case 2} {
|
|
$master flushall
|
|
set repl [attach_to_replication_stream]
|
|
|
|
$master set asdf1 1 EX 300
|
|
$master set asdf2 2 EX 300
|
|
$master set asdf3 3 EX 300
|
|
|
|
# Please note we use volatile eviction to prevent the loop described in the test above.
|
|
# "notifications" is not volatile so it always remains
|
|
$master config resetstat
|
|
$master config set maxmemory-policy volatile-ttl
|
|
$master config set maxmemory 1
|
|
|
|
wait_for_condition 500 10 {
|
|
[s evicted_keys] eq 3
|
|
} else {
|
|
fail "Not all keys have been evicted"
|
|
}
|
|
|
|
$master config set maxmemory 0
|
|
$master config set maxmemory-policy noeviction
|
|
|
|
$master set asdf4 4
|
|
|
|
# Note whenever there's double notification: SET with EX issues two separate
|
|
# notifications: one for "set" and one for "expire"
|
|
# Note that although CONFIG SET maxmemory is called in this flow (see issue #10014),
|
|
# eviction will happen and will not induce propagation of the CONFIG command (see #10019).
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{incr notifications}
|
|
{incr notifications}
|
|
{set asdf1 1 PXAT *}
|
|
{exec}
|
|
{multi}
|
|
{incr notifications}
|
|
{incr notifications}
|
|
{set asdf2 2 PXAT *}
|
|
{exec}
|
|
{multi}
|
|
{incr notifications}
|
|
{incr notifications}
|
|
{set asdf3 3 PXAT *}
|
|
{exec}
|
|
{incr notifications}
|
|
{del asdf*}
|
|
{incr notifications}
|
|
{del asdf*}
|
|
{incr notifications}
|
|
{del asdf*}
|
|
{multi}
|
|
{incr notifications}
|
|
{set asdf4 4}
|
|
{exec}
|
|
}
|
|
close_replication_stream $repl
|
|
}
|
|
|
|
test {module propagation with timer and CONFIG SET maxmemory} {
|
|
set repl [attach_to_replication_stream]
|
|
|
|
$master config resetstat
|
|
$master config set maxmemory-policy volatile-random
|
|
|
|
$master propagate-test.timer-maxmemory
|
|
|
|
# Wait until the volatile keys are evicted
|
|
wait_for_condition 500 10 {
|
|
[s evicted_keys] eq 2
|
|
} else {
|
|
fail "Not all keys have been evicted"
|
|
}
|
|
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{incr notifications}
|
|
{incr notifications}
|
|
{set timer-maxmemory-volatile-start 1 PXAT *}
|
|
{incr timer-maxmemory-middle}
|
|
{incr notifications}
|
|
{incr notifications}
|
|
{set timer-maxmemory-volatile-end 1 PXAT *}
|
|
{exec}
|
|
{incr notifications}
|
|
{del timer-maxmemory-volatile-*}
|
|
{incr notifications}
|
|
{del timer-maxmemory-volatile-*}
|
|
}
|
|
close_replication_stream $repl
|
|
|
|
$master config set maxmemory 0
|
|
$master config set maxmemory-policy noeviction
|
|
}
|
|
|
|
test {module propagation with timer and EVAL} {
|
|
set repl [attach_to_replication_stream]
|
|
|
|
$master propagate-test.timer-eval
|
|
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{incr notifications}
|
|
{incrby timer-eval-start 1}
|
|
{incr notifications}
|
|
{set foo bar}
|
|
{incr timer-eval-middle}
|
|
{incr notifications}
|
|
{incrby timer-eval-end 1}
|
|
{exec}
|
|
}
|
|
close_replication_stream $repl
|
|
}
|
|
|
|
test {module propagates nested ctx case1} {
|
|
set repl [attach_to_replication_stream]
|
|
|
|
$master propagate-test.timer-nested
|
|
|
|
wait_for_condition 500 10 {
|
|
[$replica get timer-nested-end] eq "1"
|
|
} else {
|
|
fail "The two counters don't match the expected value."
|
|
}
|
|
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{incrby timer-nested-start 1}
|
|
{incrby timer-nested-end 1}
|
|
{exec}
|
|
}
|
|
close_replication_stream $repl
|
|
|
|
# Note propagate-test.timer-nested just propagates INCRBY, causing an
|
|
# inconsistency, so we flush
|
|
$master flushall
|
|
}
|
|
|
|
test {module propagates nested ctx case2} {
|
|
set repl [attach_to_replication_stream]
|
|
|
|
$master propagate-test.timer-nested-repl
|
|
|
|
wait_for_condition 500 10 {
|
|
[$replica get timer-nested-end] eq "1"
|
|
} else {
|
|
fail "The two counters don't match the expected value."
|
|
}
|
|
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{incrby timer-nested-start 1}
|
|
{incr notifications}
|
|
{incr using-call}
|
|
{incr counter-1}
|
|
{incr counter-2}
|
|
{incr counter-3}
|
|
{incr counter-4}
|
|
{incr notifications}
|
|
{incr after-call}
|
|
{incr notifications}
|
|
{incr before-call-2}
|
|
{incr notifications}
|
|
{incr asdf}
|
|
{incr notifications}
|
|
{del asdf}
|
|
{incr notifications}
|
|
{incr after-call-2}
|
|
{incr notifications}
|
|
{incr timer-nested-middle}
|
|
{incrby timer-nested-end 1}
|
|
{exec}
|
|
}
|
|
close_replication_stream $repl
|
|
|
|
# Note propagate-test.timer-nested-repl just propagates INCRBY, causing an
|
|
# inconsistency, so we flush
|
|
$master flushall
|
|
}
|
|
|
|
test {module propagates from thread} {
|
|
set repl [attach_to_replication_stream]
|
|
|
|
$master propagate-test.thread
|
|
|
|
wait_for_condition 500 10 {
|
|
[$replica get a-from-thread] eq "3"
|
|
} else {
|
|
fail "The two counters don't match the expected value."
|
|
}
|
|
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{incr a-from-thread}
|
|
{incr notifications}
|
|
{incr thread-call}
|
|
{incr b-from-thread}
|
|
{exec}
|
|
{multi}
|
|
{incr a-from-thread}
|
|
{incr notifications}
|
|
{incr thread-call}
|
|
{incr b-from-thread}
|
|
{exec}
|
|
{multi}
|
|
{incr a-from-thread}
|
|
{incr notifications}
|
|
{incr thread-call}
|
|
{incr b-from-thread}
|
|
{exec}
|
|
}
|
|
close_replication_stream $repl
|
|
}
|
|
|
|
test {module propagates from thread with detached ctx} {
|
|
set repl [attach_to_replication_stream]
|
|
|
|
$master propagate-test.detached-thread
|
|
|
|
wait_for_condition 500 10 {
|
|
[$replica get thread-detached-after] eq "1"
|
|
} else {
|
|
fail "The key doesn't match the expected value."
|
|
}
|
|
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{incr thread-detached-before}
|
|
{incr notifications}
|
|
{incr thread-detached-1}
|
|
{incr notifications}
|
|
{incr thread-detached-2}
|
|
{incr thread-detached-after}
|
|
{exec}
|
|
}
|
|
close_replication_stream $repl
|
|
}
|
|
|
|
test {module propagates from command} {
|
|
set repl [attach_to_replication_stream]
|
|
|
|
$master propagate-test.simple
|
|
$master propagate-test.mixed
|
|
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{incr counter-1}
|
|
{incr counter-2}
|
|
{exec}
|
|
{multi}
|
|
{incr notifications}
|
|
{incr using-call}
|
|
{incr counter-1}
|
|
{incr counter-2}
|
|
{incr notifications}
|
|
{incr after-call}
|
|
{exec}
|
|
}
|
|
close_replication_stream $repl
|
|
}
|
|
|
|
test {module propagates from EVAL} {
|
|
set repl [attach_to_replication_stream]
|
|
|
|
assert_equal [ $master eval { \
|
|
redis.call("propagate-test.simple"); \
|
|
redis.call("set", "x", "y"); \
|
|
redis.call("propagate-test.mixed"); return "OK" } 0 ] {OK}
|
|
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{incr counter-1}
|
|
{incr counter-2}
|
|
{incr notifications}
|
|
{set x y}
|
|
{incr notifications}
|
|
{incr using-call}
|
|
{incr counter-1}
|
|
{incr counter-2}
|
|
{incr notifications}
|
|
{incr after-call}
|
|
{exec}
|
|
}
|
|
close_replication_stream $repl
|
|
}
|
|
|
|
test {module propagates from command after good EVAL} {
|
|
set repl [attach_to_replication_stream]
|
|
|
|
assert_equal [ $master eval { return "hello" } 0 ] {hello}
|
|
$master propagate-test.simple
|
|
$master propagate-test.mixed
|
|
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{incr counter-1}
|
|
{incr counter-2}
|
|
{exec}
|
|
{multi}
|
|
{incr notifications}
|
|
{incr using-call}
|
|
{incr counter-1}
|
|
{incr counter-2}
|
|
{incr notifications}
|
|
{incr after-call}
|
|
{exec}
|
|
}
|
|
close_replication_stream $repl
|
|
}
|
|
|
|
test {module propagates from command after bad EVAL} {
|
|
set repl [attach_to_replication_stream]
|
|
|
|
catch { $master eval { return "hello" } -12 } e
|
|
assert_equal $e {ERR Number of keys can't be negative}
|
|
$master propagate-test.simple
|
|
$master propagate-test.mixed
|
|
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{incr counter-1}
|
|
{incr counter-2}
|
|
{exec}
|
|
{multi}
|
|
{incr notifications}
|
|
{incr using-call}
|
|
{incr counter-1}
|
|
{incr counter-2}
|
|
{incr notifications}
|
|
{incr after-call}
|
|
{exec}
|
|
}
|
|
close_replication_stream $repl
|
|
}
|
|
|
|
test {module propagates from multi-exec} {
|
|
set repl [attach_to_replication_stream]
|
|
|
|
$master multi
|
|
$master propagate-test.simple
|
|
$master propagate-test.mixed
|
|
$master propagate-test.timer-nested-repl
|
|
$master exec
|
|
|
|
wait_for_condition 500 10 {
|
|
[$replica get timer-nested-end] eq "1"
|
|
} else {
|
|
fail "The two counters don't match the expected value."
|
|
}
|
|
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{incr counter-1}
|
|
{incr counter-2}
|
|
{incr notifications}
|
|
{incr using-call}
|
|
{incr counter-1}
|
|
{incr counter-2}
|
|
{incr notifications}
|
|
{incr after-call}
|
|
{exec}
|
|
{multi}
|
|
{incrby timer-nested-start 1}
|
|
{incr notifications}
|
|
{incr using-call}
|
|
{incr counter-1}
|
|
{incr counter-2}
|
|
{incr counter-3}
|
|
{incr counter-4}
|
|
{incr notifications}
|
|
{incr after-call}
|
|
{incr notifications}
|
|
{incr before-call-2}
|
|
{incr notifications}
|
|
{incr asdf}
|
|
{incr notifications}
|
|
{del asdf}
|
|
{incr notifications}
|
|
{incr after-call-2}
|
|
{incr notifications}
|
|
{incr timer-nested-middle}
|
|
{incrby timer-nested-end 1}
|
|
{exec}
|
|
}
|
|
close_replication_stream $repl
|
|
|
|
# Note propagate-test.timer-nested just propagates INCRBY, causing an
|
|
# inconsistency, so we flush
|
|
$master flushall
|
|
}
|
|
|
|
test {module RM_Call of expired key propagation} {
|
|
$master debug set-active-expire 0
|
|
|
|
$master set k1 900 px 100
|
|
after 110
|
|
|
|
set repl [attach_to_replication_stream]
|
|
$master propagate-test.incr k1
|
|
|
|
assert_replication_stream $repl {
|
|
{select *}
|
|
{multi}
|
|
{del k1}
|
|
{propagate-test.incr k1}
|
|
{exec}
|
|
}
|
|
close_replication_stream $repl
|
|
|
|
assert_equal [$master get k1] 1
|
|
assert_equal [$master ttl k1] -1
|
|
assert_equal [$replica get k1] 1
|
|
assert_equal [$replica ttl k1] -1
|
|
}
|
|
|
|
assert_equal [s -1 unexpected_error_replies] 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
tags "modules aof" {
|
|
test {Modules RM_Replicate replicates MULTI/EXEC correctly} {
|
|
start_server [list overrides [list loadmodule "$testmodule"]] {
|
|
# Enable the AOF
|
|
r config set appendonly yes
|
|
r config set auto-aof-rewrite-percentage 0 ; # Disable auto-rewrite.
|
|
waitForBgrewriteaof r
|
|
|
|
r propagate-test.simple
|
|
r propagate-test.mixed
|
|
r multi
|
|
r propagate-test.simple
|
|
r propagate-test.mixed
|
|
r exec
|
|
|
|
# Load the AOF
|
|
r debug loadaof
|
|
|
|
assert_equal [s 0 unexpected_error_replies] 0
|
|
}
|
|
}
|
|
}
|