summaryrefslogtreecommitdiff
path: root/examples/redis-unstable/tests/integration/replication-rdbchannel.tcl
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2026-01-21 22:40:55 +0100
committerMitja Felicijan <mitja.felicijan@gmail.com>2026-01-21 22:40:55 +0100
commit5d8dfe892a2ea89f706ee140c3bdcfd89fe03fda (patch)
tree1acdfa5220cd13b7be43a2a01368e80d306473ca /examples/redis-unstable/tests/integration/replication-rdbchannel.tcl
parentc7ab12bba64d9c20ccd79b132dac475f7bc3923e (diff)
downloadcrep-5d8dfe892a2ea89f706ee140c3bdcfd89fe03fda.tar.gz
Add Redis source code for testing
Diffstat (limited to 'examples/redis-unstable/tests/integration/replication-rdbchannel.tcl')
-rw-r--r--examples/redis-unstable/tests/integration/replication-rdbchannel.tcl904
1 files changed, 904 insertions, 0 deletions
diff --git a/examples/redis-unstable/tests/integration/replication-rdbchannel.tcl b/examples/redis-unstable/tests/integration/replication-rdbchannel.tcl
new file mode 100644
index 0000000..0fc955b
--- /dev/null
+++ b/examples/redis-unstable/tests/integration/replication-rdbchannel.tcl
@@ -0,0 +1,904 @@
+#
+# Copyright (c) 2009-Present, Redis Ltd.
+# All rights reserved.
+#
+# Copyright (c) 2024-present, Valkey contributors.
+# All rights reserved.
+#
+# Licensed under your choice of (a) the Redis Source Available License 2.0
+# (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the
+# GNU Affero General Public License v3 (AGPLv3).
+#
+# Portions of this file are available under BSD3 terms; see REDISCONTRIBUTIONS for more information.
+#
+
+# Returns either main or rdbchannel client id
+# Assumes there is one replica with two channels
+proc get_replica_client_id {master rdbchannel} {
+ set input [$master client list type replica]
+
+ foreach line [split $input "\n"] {
+ if {[regexp {id=(\d+).*flags=(\S+)} $line match id flags]} {
+ if {$rdbchannel == "yes"} {
+ # rdbchannel will have C flag
+ if {[string match *C* $flags]} {
+ return $id
+ }
+ } else {
+ return $id
+ }
+ }
+ }
+
+ error "Replica not found"
+}
+
+start_server {tags {"repl external:skip"}} {
+ set replica1 [srv 0 client]
+
+ start_server {} {
+ set replica2 [srv 0 client]
+
+ start_server {} {
+ set master [srv 0 client]
+ set master_host [srv 0 host]
+ set master_port [srv 0 port]
+
+ $master config set repl-diskless-sync yes
+ $master config set repl-rdb-channel yes
+ populate 1000 master 10
+
+ test "Test replication with multiple replicas (rdbchannel enabled on both)" {
+ $replica1 config set repl-rdb-channel yes
+ $replica1 replicaof $master_host $master_port
+
+ $replica2 config set repl-rdb-channel yes
+ $replica2 replicaof $master_host $master_port
+
+ wait_replica_online $master 0
+ wait_replica_online $master 1
+
+ $master set x 1
+
+ # Wait until replicas catch master
+ wait_for_ofs_sync $master $replica1
+ wait_for_ofs_sync $master $replica2
+
+ # Verify db's are identical
+ assert_morethan [$master dbsize] 0
+ assert_equal [$master get x] 1
+ assert_equal [$master debug digest] [$replica1 debug digest]
+ assert_equal [$master debug digest] [$replica2 debug digest]
+ }
+
+ test "Test replication with multiple replicas (rdbchannel enabled on one of them)" {
+ # Allow both replicas to ask for sync
+ $master config set repl-diskless-sync-delay 5
+
+ $replica1 replicaof no one
+ $replica2 replicaof no one
+ $replica1 config set repl-rdb-channel yes
+ $replica2 config set repl-rdb-channel no
+
+ set loglines [count_log_lines 0]
+ set prev_forks [s 0 total_forks]
+ $master set x 2
+
+ # There will be two forks subsequently, one for rdbchannel
+ # replica another for the replica without rdbchannel config.
+ $replica1 replicaof $master_host $master_port
+ $replica2 replicaof $master_host $master_port
+
+ # There will be two forks subsequently, one for rdbchannel
+ # replica, another for the replica without rdbchannel config.
+ wait_for_log_messages 0 {"*Starting BGSAVE* replicas sockets (rdb-channel)*"} $loglines 300 100
+ wait_for_log_messages 0 {"*Starting BGSAVE* replicas sockets"} $loglines 300 100
+
+ wait_replica_online $master 0 100 100
+ wait_replica_online $master 1 100 100
+
+ # Verify two new forks.
+ assert_equal [s 0 total_forks] [expr $prev_forks + 2]
+
+ wait_for_ofs_sync $master $replica1
+ wait_for_ofs_sync $master $replica2
+
+ # Verify db's are identical
+ assert_equal [$replica1 get x] 2
+ assert_equal [$replica2 get x] 2
+ assert_equal [$master debug digest] [$replica1 debug digest]
+ assert_equal [$master debug digest] [$replica2 debug digest]
+ }
+
+ test "Test rdbchannel is not used if repl-diskless-sync config is disabled on master" {
+ $replica1 replicaof no one
+ $replica2 replicaof no one
+
+ $master config set repl-diskless-sync-delay 0
+ $master config set repl-diskless-sync no
+
+ $master set x 3
+ $replica1 replicaof $master_host $master_port
+
+ # Verify log message does not mention rdbchannel
+ wait_for_log_messages 0 {"*Starting BGSAVE for SYNC with target: disk*"} 0 2000 1
+
+ wait_replica_online $master 0
+ wait_for_ofs_sync $master $replica1
+
+ # Verify db's are identical
+ assert_equal [$replica1 get x] 3
+ assert_equal [$master debug digest] [$replica1 debug digest]
+ }
+ }
+ }
+}
+
+start_server {tags {"repl external:skip"}} {
+ set replica [srv 0 client]
+ set replica_pid [srv 0 pid]
+
+ start_server {} {
+ set master [srv 0 client]
+ set master_host [srv 0 host]
+ set master_port [srv 0 port]
+
+ $master config set repl-rdb-channel yes
+ $replica config set repl-rdb-channel yes
+
+ # Reuse this test to verify large key delivery
+ $master config set rdbcompression no
+ $master config set rdb-key-save-delay 3000
+ populate 1000 prefix1 10
+ populate 5 prefix2 3000000
+ populate 5 prefix3 2000000
+ populate 5 prefix4 1000000
+
+ # On master info output, we should see state transition in this order:
+ # 1. wait_bgsave: Replica receives psync error (+RDBCHANNELSYNC)
+ # 2. send_bulk_and_stream: Replica opens rdbchannel and delivery started
+ # 3. online: Sync is completed
+ test "Test replica state should start with wait_bgsave" {
+ $replica config set key-load-delay 100000
+ # Pause replica before opening rdb channel conn
+ $replica debug repl-pause before-rdb-channel
+ $replica replicaof $master_host $master_port
+
+ wait_for_condition 50 200 {
+ [s 0 connected_slaves] == 1 &&
+ [string match "*wait_bgsave*" [s 0 slave0]]
+ } else {
+ fail "replica failed"
+ }
+ }
+
+ test "Test replica state advances to send_bulk_and_stream when rdbchannel connects" {
+ $master set x 1
+ resume_process $replica_pid
+
+ wait_for_condition 50 200 {
+ [s 0 connected_slaves] == 1 &&
+ [s 0 rdb_bgsave_in_progress] == 1 &&
+ [string match "*send_bulk_and_stream*" [s 0 slave0]]
+ } else {
+ fail "replica failed"
+ }
+ }
+
+ test "Test replica rdbchannel client has SC flag on client list output" {
+ set input [$master client list type replica]
+
+ # There will two replicas, second one should be rdbchannel
+ set trimmed_input [string trimright $input]
+ set lines [split $trimmed_input "\n"]
+ if {[llength $lines] < 2} {
+ error "There is no second line in the input: $input"
+ }
+ set second_line [lindex $lines 1]
+
+ # Check if 'flags=SC' exists in the second line
+ if {![regexp {flags=SC} $second_line]} {
+ error "Flags are not 'SC' in the second line: $second_line"
+ }
+ }
+
+ test "Test replica state advances to online when fullsync is completed" {
+ # Speed up loading
+ $replica config set key-load-delay 0
+
+ wait_replica_online $master 0 100 1000
+ wait_for_ofs_sync $master $replica
+
+ wait_for_condition 50 200 {
+ [s 0 rdb_bgsave_in_progress] == 0 &&
+ [s 0 connected_slaves] == 1 &&
+ [string match "*online*" [s 0 slave0]]
+ } else {
+ fail "replica failed"
+ }
+
+ wait_replica_online $master 0 100 1000
+ wait_for_ofs_sync $master $replica
+
+ # Verify db's are identical
+ assert_morethan [$master dbsize] 0
+ assert_equal [$master debug digest] [$replica debug digest]
+ }
+ }
+}
+
+start_server {tags {"repl external:skip debug_defrag:skip"}} {
+ set replica [srv 0 client]
+
+ start_server {} {
+ set master [srv 0 client]
+ set master_host [srv 0 host]
+ set master_port [srv 0 port]
+
+ $master config set repl-rdb-channel yes
+ $replica config set repl-rdb-channel yes
+
+ test "Test master memory does not increase during replication" {
+ # Put some delay to rdb generation. If master doesn't forward
+ # incoming traffic to replica, master's replication buffer will grow
+ $master config set repl-diskless-sync-delay 0
+ $master config set rdb-key-save-delay 500 ;# 500us delay and 10k keys means at least 5 seconds replication
+ $master config set repl-backlog-size 5mb
+ $replica config set replica-full-sync-buffer-limit 200mb
+ populate 10000 master 10000 ;# 10k keys of 10k, means 100mb
+ $replica config set loading-process-events-interval-bytes 262144 ;# process events every 256kb of rdb or command stream
+
+ # Start write traffic
+ set load_handle [start_write_load $master_host $master_port 100 "key1" 5000 4]
+
+ set prev_used [s 0 used_memory]
+
+ $replica replicaof $master_host $master_port
+ set backlog_size [lindex [$master config get repl-backlog-size] 1]
+
+ # Verify used_memory stays low
+ set max_retry 1000
+ set peak_replica_buf_size 0
+ set peak_master_slave_buf_size 0
+ set peak_master_used_mem 0
+ set peak_master_rpl_buf 0
+ while {$max_retry} {
+ set replica_buf_size [s -1 replica_full_sync_buffer_size]
+ set master_slave_buf_size [s mem_clients_slaves]
+ set master_used_mem [s used_memory]
+ set master_rpl_buf [s mem_total_replication_buffers]
+ if {$replica_buf_size > $peak_replica_buf_size} {set peak_replica_buf_size $replica_buf_size}
+ if {$master_slave_buf_size > $peak_master_slave_buf_size} {set peak_master_slave_buf_size $master_slave_buf_size}
+ if {$master_used_mem > $peak_master_used_mem} {set peak_master_used_mem $master_used_mem}
+ if {$master_rpl_buf > $peak_master_rpl_buf} {set peak_master_rpl_buf $master_rpl_buf}
+ if {$::verbose} {
+ puts "[clock format [clock seconds] -format %H:%M:%S] master: $master_slave_buf_size replica: $replica_buf_size"
+ }
+
+ # Wait for the replica to finish reading the rdb (also from the master's perspective), and also consume much of the replica buffer
+ if {[string match *slave0*state=online* [$master info]] &&
+ [s -1 master_link_status] == "up" &&
+ $replica_buf_size < 1000000} {
+ break
+ } else {
+ incr max_retry -1
+ after 10
+ }
+ }
+ if {$max_retry == 0} {
+ error "assertion:Replica not in sync after 10 seconds"
+ }
+
+ if {$::verbose} {
+ puts "peak_master_used_mem $peak_master_used_mem"
+ puts "peak_master_rpl_buf $peak_master_rpl_buf"
+ puts "peak_master_slave_buf_size $peak_master_slave_buf_size"
+ puts "peak_replica_buf_size $peak_replica_buf_size"
+ }
+ # memory on the master is less than 1mb
+ assert_lessthan [expr $peak_master_used_mem - $prev_used - $backlog_size] 1000000
+ assert_lessthan $peak_master_rpl_buf [expr {$backlog_size + 1000000}]
+ assert_lessthan $peak_master_slave_buf_size 1000000
+ # buffers in the replica are more than 5mb
+ assert_morethan $peak_replica_buf_size 5000000
+
+ stop_write_load $load_handle
+ }
+ }
+}
+
+start_server {tags {"repl external:skip"}} {
+ set replica [srv 0 client]
+
+ start_server {} {
+ set master [srv 0 client]
+ set master_host [srv 0 host]
+ set master_port [srv 0 port]
+
+ $master config set repl-rdb-channel yes
+ $replica config set repl-rdb-channel yes
+
+ test "Test replication stream buffer becomes full on replica" {
+ # For replication stream accumulation, replica inherits slave output
+ # buffer limit as the size limit. In this test, we create traffic to
+ # fill the buffer fully. Once the limit is reached, accumulation
+ # will stop. This is not a failure scenario though. From that point,
+ # further accumulation may occur on master side. Replication should
+ # be completed successfully.
+
+ # Create some artificial delay for rdb delivery and load. We'll
+ # generate some traffic to fill the replication buffer.
+ $master config set rdb-key-save-delay 1000
+ $replica config set key-load-delay 1000
+ $replica config set client-output-buffer-limit "replica 64kb 64kb 0"
+ populate 2000 master 1
+
+ set prev_sync_full [s 0 sync_full]
+ $replica replicaof $master_host $master_port
+
+ # Wait for replica to establish psync using main channel
+ wait_for_condition 500 1000 {
+ [string match "*state=send_bulk_and_stream*" [s 0 slave0]]
+ } else {
+ fail "replica didn't start sync"
+ }
+
+ # Create some traffic on replication stream
+ populate 100 master 100000
+
+ # Wait for replica's buffer limit reached
+ wait_for_log_messages -1 {"*Replication buffer limit has been reached*"} 0 1000 10
+
+ # Speed up loading
+ $replica config set key-load-delay 0
+
+ # Wait until sync is successful
+ wait_for_condition 200 200 {
+ [status $master master_repl_offset] eq [status $replica master_repl_offset] &&
+ [status $master master_repl_offset] eq [status $replica slave_repl_offset]
+ } else {
+ fail "replica offsets didn't match in time"
+ }
+
+ # Verify sync was not interrupted.
+ assert_equal [s 0 sync_full] [expr $prev_sync_full + 1]
+
+ # Verify db's are identical
+ assert_morethan [$master dbsize] 0
+ assert_equal [$master debug digest] [$replica debug digest]
+ }
+
+ test "Test replication stream buffer config replica-full-sync-buffer-limit" {
+ # By default, replica inherits client-output-buffer-limit of replica
+ # to limit accumulated repl data during rdbchannel sync.
+ # replica-full-sync-buffer-limit should override it if it is set.
+ $replica replicaof no one
+
+ # Create some artificial delay for rdb delivery and load. We'll
+ # generate some traffic to fill the replication buffer.
+ $master config set rdb-key-save-delay 1000
+ $replica config set key-load-delay 1000
+ $replica config set client-output-buffer-limit "replica 1024 1024 0"
+ $replica config set replica-full-sync-buffer-limit 20mb
+ populate 2000 master 1
+
+ $replica replicaof $master_host $master_port
+
+ # Wait until replication starts
+ wait_for_condition 500 1000 {
+ [string match "*state=send_bulk_and_stream*" [s 0 slave0]]
+ } else {
+ fail "replica didn't start sync"
+ }
+
+ # Create some traffic on replication stream
+ populate 100 master 100000
+
+ # Make sure config is used, we accumulated more than
+ # client-output-buffer-limit
+ assert_morethan [s -1 replica_full_sync_buffer_size] 1024
+ }
+ }
+}
+
+start_server {tags {"repl external:skip debug_defrag:skip"}} {
+ set master [srv 0 client]
+ set master_host [srv 0 host]
+ set master_port [srv 0 port]
+ set master_pid [srv 0 pid]
+ set loglines [count_log_lines 0]
+
+ $master config set repl-diskless-sync yes
+ $master config set repl-rdb-channel yes
+ $master config set repl-backlog-size 1mb
+ $master config set client-output-buffer-limit "replica 100k 0 0"
+ $master config set repl-diskless-sync-delay 3
+
+ start_server {} {
+ set replica [srv 0 client]
+ set replica_pid [srv 0 pid]
+
+ $replica config set repl-rdb-channel yes
+ $replica config set repl-timeout 10
+ $replica config set key-load-delay 10000
+ $replica config set loading-process-events-interval-bytes 1024
+
+ test "Test master disconnects replica when output buffer limit is reached" {
+ populate 20000 master 100 -1
+
+ $replica replicaof $master_host $master_port
+ wait_for_condition 100 200 {
+ [s 0 loading] == 1
+ } else {
+ fail "Replica did not start loading"
+ }
+
+ # Generate replication traffic of ~20mb to disconnect the slave on obuf limit
+ populate 20 master 1000000 -1
+
+ wait_for_log_messages -1 {"*Client * closed * for overcoming of output buffer limits.*"} $loglines 1000 10
+ $replica config set key-load-delay 0
+
+ # Wait until replica loads RDB
+ wait_for_log_messages 0 {"*Done loading RDB*"} 0 1000 10
+ }
+
+ test "Test replication recovers after output buffer failures" {
+ # Verify system is operational
+ $master set x 1
+
+ # Wait until replica catches up
+ wait_replica_online $master 0 1000 100
+ wait_for_ofs_sync $master $replica
+
+ # Verify db's are identical
+ assert_morethan [$master dbsize] 0
+ assert_equal [$replica get x] 1
+ assert_equal [$master debug digest] [$replica debug digest]
+ }
+ }
+}
+
+start_server {tags {"repl external:skip"}} {
+ set master [srv 0 client]
+ set master_host [srv 0 host]
+ set master_port [srv 0 port]
+
+ $master config set repl-diskless-sync yes
+ $master config set repl-rdb-channel yes
+ $master config set rdb-key-save-delay 300
+ $master config set client-output-buffer-limit "replica 0 0 0"
+ $master config set repl-diskless-sync-delay 5
+
+ populate 10000 master 1
+
+ start_server {} {
+ set replica1 [srv 0 client]
+ $replica1 config set repl-rdb-channel yes
+
+ start_server {} {
+ set replica2 [srv 0 client]
+ $replica2 config set repl-rdb-channel yes
+
+ set load_handle [start_write_load $master_host $master_port 100 "key"]
+
+ test "Test master continues RDB delivery if not all replicas are dropped" {
+ $replica1 replicaof $master_host $master_port
+ $replica2 replicaof $master_host $master_port
+
+ wait_for_condition 50 200 {
+ [s -2 rdb_bgsave_in_progress] == 1
+ } else {
+ fail "Sync did not start"
+ }
+
+ # Verify replicas are connected
+ wait_for_condition 500 100 {
+ [s -2 connected_slaves] == 2
+ } else {
+ fail "Replicas didn't connect: [s -2 connected_slaves]"
+ }
+
+ # kill one of the replicas
+ catch {$replica1 shutdown nosave}
+
+ # Wait until replica completes full sync
+ # Verify there is no other full sync attempt
+ wait_for_condition 50 1000 {
+ [s 0 master_link_status] == "up" &&
+ [s -2 sync_full] == 2 &&
+ [s -2 connected_slaves] == 1
+ } else {
+ fail "Sync session did not continue
+ master_link_status: [s 0 master_link_status]
+ sync_full:[s -2 sync_full]
+ connected_slaves: [s -2 connected_slaves]"
+ }
+
+ # Wait until replica catches up
+ wait_replica_online $master 0 200 100
+ wait_for_condition 200 100 {
+ [s 0 mem_replica_full_sync_buffer] == 0
+ } else {
+ fail "Replica did not consume buffer in time"
+ }
+ }
+
+ test "Test master aborts rdb delivery if all replicas are dropped" {
+ $replica2 replicaof no one
+
+ # Start replication
+ $replica2 replicaof $master_host $master_port
+
+ wait_for_condition 50 1000 {
+ [s -2 rdb_bgsave_in_progress] == 1
+ } else {
+ fail "Sync did not start"
+ }
+ set loglines [count_log_lines -2]
+
+ # kill replica
+ catch {$replica2 shutdown nosave}
+
+ # Verify master aborts rdb save
+ wait_for_condition 50 1000 {
+ [s -2 rdb_bgsave_in_progress] == 0 &&
+ [s -2 connected_slaves] == 0
+ } else {
+ fail "Master should abort the sync
+ rdb_bgsave_in_progress:[s -2 rdb_bgsave_in_progress]
+ connected_slaves: [s -2 connected_slaves]"
+ }
+ wait_for_log_messages -2 {"*Background transfer error*"} $loglines 1000 50
+ }
+
+ stop_write_load $load_handle
+ }
+ }
+}
+
+start_server {tags {"repl external:skip"}} {
+ set master [srv 0 client]
+ set master_host [srv 0 host]
+ set master_port [srv 0 port]
+
+ $master config set repl-diskless-sync yes
+ $master config set repl-rdb-channel yes
+ $master config set rdb-key-save-delay 1000
+
+ populate 3000 prefix1 1
+ populate 100 prefix2 100000
+
+ start_server {} {
+ set replica [srv 0 client]
+ set replica_pid [srv 0 pid]
+
+ $replica config set repl-rdb-channel yes
+ $replica config set repl-timeout 10
+
+ set load_handle [start_write_load $master_host $master_port 100 "key"]
+
+ test "Test replica recovers when rdb channel connection is killed" {
+ $replica replicaof $master_host $master_port
+
+ # Wait for sync session to start
+ wait_for_condition 500 200 {
+ [string match "*state=send_bulk_and_stream*" [s -1 slave0]] &&
+ [s -1 rdb_bgsave_in_progress] eq 1
+ } else {
+ fail "replica didn't start sync session in time"
+ }
+
+ set loglines [count_log_lines -1]
+
+ # Kill rdb channel client
+ set id [get_replica_client_id $master yes]
+ $master client kill id $id
+
+ wait_for_log_messages -1 {"*Background transfer error*"} $loglines 1000 10
+
+ # Verify master rejects main-ch-client-id after connection is killed
+ assert_error {*Unrecognized*} {$master replconf main-ch-client-id $id}
+
+ # Replica should retry
+ wait_for_condition 500 200 {
+ [string match "*state=send_bulk_and_stream*" [s -1 slave0]] &&
+ [s -1 rdb_bgsave_in_progress] eq 1
+ } else {
+ fail "replica didn't retry after connection close"
+ }
+ }
+
+ test "Test replica recovers when main channel connection is killed" {
+ set loglines [count_log_lines -1]
+
+ # Kill main channel client
+ set id [get_replica_client_id $master yes]
+ $master client kill id $id
+
+ wait_for_log_messages -1 {"*Background transfer error*"} $loglines 1000 20
+
+ # Replica should retry
+ wait_for_condition 500 2000 {
+ [string match "*state=send_bulk_and_stream*" [s -1 slave0]] &&
+ [s -1 rdb_bgsave_in_progress] eq 1
+ } else {
+ fail "replica didn't retry after connection close"
+ }
+ }
+
+ stop_write_load $load_handle
+
+ test "Test replica recovers connection failures" {
+ # Wait until replica catches up
+ wait_replica_online $master 0 1000 100
+ wait_for_ofs_sync $master $replica
+
+ # Verify db's are identical
+ assert_morethan [$master dbsize] 0
+ assert_equal [$master debug digest] [$replica debug digest]
+ }
+ }
+}
+
+start_server {tags {"repl external:skip tsan:skip"}} {
+ set replica [srv 0 client]
+ set replica_pid [srv 0 pid]
+
+ start_server {} {
+ set master [srv 0 client]
+ set master_host [srv 0 host]
+ set master_port [srv 0 port]
+
+ test "Test master connection drops while streaming repl buffer into the db" {
+ # Just after replica loads RDB, it will stream repl buffer into the
+ # db. During streaming, we kill the master connection. Replica
+ # will abort streaming and then try another psync with master.
+ $master config set rdb-key-save-delay 1000
+ $master config set repl-rdb-channel yes
+ $master config set repl-diskless-sync yes
+ $replica config set repl-rdb-channel yes
+ $replica config set loading-process-events-interval-bytes 1024
+
+ # Populate db and start write traffic
+ populate 2000 master 1000
+ set load_handle [start_write_load $master_host $master_port 100 "key1"]
+
+ # Replica will pause in the loop of repl buffer streaming
+ $replica debug repl-pause on-streaming-repl-buf
+ $replica replicaof $master_host $master_port
+
+ # Check if repl stream accumulation is started.
+ wait_for_condition 50 1000 {
+ [s -1 replica_full_sync_buffer_size] > 0
+ } else {
+ fail "repl stream accumulation not started"
+ }
+
+ # Wait until replica starts streaming repl buffer
+ wait_for_log_messages -1 {"*Starting to stream replication buffer*"} 0 2000 10
+ stop_write_load $load_handle
+ $master config set rdb-key-save-delay 0
+
+ # Kill master connection and resume the process
+ $replica deferred 1
+ $replica client kill type master
+ $replica debug repl-pause clear
+ resume_process $replica_pid
+ $replica read
+ $replica read
+ $replica deferred 0
+
+ wait_for_log_messages -1 {"*Master client was freed while streaming*"} 0 500 10
+
+ # Quick check for stats test coverage
+ assert_morethan_equal [s -1 replica_full_sync_buffer_peak] [s -1 replica_full_sync_buffer_size]
+
+ # Wait until replica recovers and verify db's are identical
+ wait_replica_online $master 0 1000 10
+ wait_for_ofs_sync $master $replica
+
+ assert_morethan [$master dbsize] 0
+ assert_equal [$master debug digest] [$replica debug digest]
+ }
+ }
+}
+
+start_server {tags {"repl external:skip"}} {
+ set replica [srv 0 client]
+ set replica_pid [srv 0 pid]
+
+ start_server {} {
+ set master [srv 0 client]
+ set master_host [srv 0 host]
+ set master_port [srv 0 port]
+
+ test "Test main channel connection drops while loading rdb (disk based)" {
+ # While loading rdb, we kill main channel connection.
+ # We expect replica to complete loading RDB and then try psync
+ # with the master.
+ $master config set repl-rdb-channel yes
+ $replica config set repl-rdb-channel yes
+ $replica config set repl-diskless-load disabled
+ $replica config set key-load-delay 10000
+ $replica config set loading-process-events-interval-bytes 1024
+
+ # Populate db and start write traffic
+ populate 10000 master 100
+ $replica replicaof $master_host $master_port
+
+ # Wait until replica starts loading
+ wait_for_condition 50 200 {
+ [s -1 loading] == 1
+ } else {
+ fail "replica did not start loading"
+ }
+
+ # Kill replica connections
+ $master client kill type replica
+ $master set x 1
+
+ # At this point, we expect replica to complete loading RDB. Then,
+ # it will try psync with master.
+ wait_for_log_messages -1 {"*Aborting rdb channel sync while loading the RDB*"} 0 2000 10
+ wait_for_log_messages -1 {"*After loading RDB, replica will try psync with master*"} 0 2000 10
+
+ # Speed up loading
+ $replica config set key-load-delay 0
+
+ # Wait until replica becomes online
+ wait_replica_online $master 0 100 100
+
+ # Verify there is another successful psync and no other full sync
+ wait_for_condition 50 200 {
+ [s 0 sync_full] == 1 &&
+ [s 0 sync_partial_ok] == 1
+ } else {
+ fail "psync was not successful [s 0 sync_full] [s 0 sync_partial_ok]"
+ }
+
+ # Verify db's are identical after recovery
+ wait_for_ofs_sync $master $replica
+ assert_morethan [$master dbsize] 0
+ assert_equal [$master debug digest] [$replica debug digest]
+ }
+ }
+}
+
+start_server {tags {"repl external:skip"}} {
+ set replica [srv 0 client]
+ set replica_pid [srv 0 pid]
+
+ start_server {} {
+ set master [srv 0 client]
+ set master_host [srv 0 host]
+ set master_port [srv 0 port]
+
+ test "Test main channel connection drops while loading rdb (diskless)" {
+ # While loading rdb, kill both main and rdbchannel connections.
+ # We expect replica to abort sync and later retry again.
+ $master config set repl-rdb-channel yes
+ $replica config set repl-rdb-channel yes
+ $replica config set repl-diskless-load swapdb
+ $replica config set key-load-delay 10000
+ $replica config set loading-process-events-interval-bytes 1024
+
+ # Populate db and start write traffic
+ populate 10000 master 100
+
+ $replica replicaof $master_host $master_port
+
+ # Wait until replica starts loading
+ wait_for_condition 50 200 {
+ [s -1 loading] == 1
+ } else {
+ fail "replica did not start loading"
+ }
+
+ # Kill replica connections
+ $master client kill type replica
+ $master set x 1
+
+ # At this point, we expect replica to abort loading RDB.
+ wait_for_log_messages -1 {"*Aborting rdb channel sync while loading the RDB*"} 0 2000 10
+ wait_for_log_messages -1 {"*Failed trying to load the MASTER synchronization DB from socket*"} 0 2000 10
+
+ # Speed up loading
+ $replica config set key-load-delay 0
+
+ # Wait until replica recovers and becomes online
+ wait_replica_online $master 0 100 100
+
+ # Verify replica attempts another full sync
+ wait_for_condition 50 200 {
+ [s 0 sync_full] == 2 &&
+ [s 0 sync_partial_ok] == 0
+ } else {
+ fail "sync was not successful [s 0 sync_full] [s 0 sync_partial_ok]"
+ }
+
+ # Verify db's are identical after recovery
+ wait_for_ofs_sync $master $replica
+ assert_morethan [$master dbsize] 0
+ assert_equal [$master debug digest] [$replica debug digest]
+ }
+ }
+}
+
+start_server {tags {"repl external:skip tsan:skip"}} {
+ set master2 [srv 0 client]
+ set master2_host [srv 0 host]
+ set master2_port [srv 0 port]
+ start_server {tags {"repl external:skip"}} {
+ set replica [srv 0 client]
+ set replica_pid [srv 0 pid]
+
+ start_server {} {
+ set master [srv 0 client]
+ set master_host [srv 0 host]
+ set master_port [srv 0 port]
+
+ test "Test replicaof command while streaming repl buffer into the db" {
+ # After replica loads the RDB, it will stream repl buffer into
+ # the db. During streaming, replica receives command
+ # "replicaof newmaster". Replica will abort streaming and then
+ # should be able to connect to the new master.
+ $master config set rdb-key-save-delay 1000
+ $master config set repl-rdb-channel yes
+ $master config set repl-diskless-sync yes
+ $replica config set repl-rdb-channel yes
+ $replica config set loading-process-events-interval-bytes 1024
+
+ # Populate db and start write traffic
+ populate 2000 master 1000
+ set load_handle [start_write_load $master_host $master_port 100 "key1"]
+
+ # Replica will pause in the loop of repl buffer streaming
+ $replica debug repl-pause on-streaming-repl-buf
+ $replica replicaof $master_host $master_port
+
+ # Check if repl stream accumulation is started.
+ wait_for_condition 50 1000 {
+ [s -1 replica_full_sync_buffer_size] > 0
+ } else {
+ fail "repl stream accumulation not started"
+ }
+
+ # Wait until replica starts streaming repl buffer
+ wait_for_log_messages -1 {"*Starting to stream replication buffer*"} 0 2000 10
+ stop_write_load $load_handle
+ $master config set rdb-key-save-delay 0
+
+ # Populate the other master
+ populate 100 master2 100 -2
+
+ # Send "replicaof newmaster" command and resume the process
+ $replica deferred 1
+ $replica replicaof $master2_host $master2_port
+ $replica debug repl-pause clear
+ resume_process $replica_pid
+ $replica read
+ $replica read
+ $replica deferred 0
+
+ wait_for_log_messages -1 {"*Master client was freed while streaming*"} 0 500 10
+
+ # Wait until replica recovers and verify db's are identical
+ wait_replica_online $master2 0 1000 10
+ wait_for_ofs_sync $master2 $replica
+ assert_morethan [$master2 dbsize] 0
+ assert_equal [$master2 debug digest] [$replica debug digest]
+
+ # Try replication once more to be sure everything is okay.
+ $replica replicaof no one
+ $master2 set x 100
+
+ $replica replicaof $master2_host $master2_port
+ wait_replica_online $master2 0 1000 10
+ wait_for_ofs_sync $master2 $replica
+ assert_morethan [$master2 dbsize] 0
+ assert_equal [$master2 debug digest] [$replica debug digest]
+ }
+ }
+ }
+}