diff --git a/src/networking.cpp b/src/networking.cpp index 7342a0fe4..b9b684407 100644 --- a/src/networking.cpp +++ b/src/networking.cpp @@ -2577,7 +2577,9 @@ void helloCommand(client *c) { if (!g_pserver->sentinel_mode) { addReplyBulkCString(c,"role"); - addReplyBulkCString(c,listLength(g_pserver->masters) ? "replica" : "master"); + addReplyBulkCString(c,listLength(g_pserver->masters) ? + g_pserver->fActiveReplica ? "active-replica" : "replica" + : "master"); } addReplyBulkCString(c,"modules"); diff --git a/src/replication.cpp b/src/replication.cpp index b37d1b655..c782e7aa7 100644 --- a/src/replication.cpp +++ b/src/replication.cpp @@ -2342,12 +2342,15 @@ void replicationUnsetMaster(redisMaster *mi) { /* This function is called when the slave lose the connection with the * master into an unexpected way. */ void replicationHandleMasterDisconnection(redisMaster *mi) { - mi->master = NULL; - mi->repl_state = REPL_STATE_CONNECT; - mi->repl_down_since = g_pserver->unixtime; - /* We lost connection with our master, don't disconnect slaves yet, - * maybe we'll be able to PSYNC with our master later. We'll disconnect - * the slaves only if we'll have to do a full resync with our master. */ + if (mi != nullptr) + { + mi->master = NULL; + mi->repl_state = REPL_STATE_CONNECT; + mi->repl_down_since = g_pserver->unixtime; + /* We lost connection with our master, don't disconnect slaves yet, + * maybe we'll be able to PSYNC with our master later. We'll disconnect + * the slaves only if we'll have to do a full resync with our master. */ + } } void replicaofCommand(client *c) { @@ -2449,7 +2452,10 @@ void roleCommand(client *c) { redisMaster *mi = (redisMaster*)listNodeValue(ln); const char *slavestate = NULL; addReplyArrayLen(c,5); - addReplyBulkCBuffer(c,"slave",5); + if (g_pserver->fActiveReplica) + addReplyBulkCBuffer(c,"active-replica",14); + else + addReplyBulkCBuffer(c,"slave",5); addReplyBulkCString(c,mi->masterhost); addReplyLongLong(c,mi->masterport); if (slaveIsInHandshakeState(mi)) { diff --git a/tests/integration/replication-active.tcl b/tests/integration/replication-active.tcl new file mode 100644 index 000000000..02013c959 --- /dev/null +++ b/tests/integration/replication-active.tcl @@ -0,0 +1,83 @@ +start_server {tags {"active-repl"} overrides {active-replica yes}} { + set slave [srv 0 client] + set slave_host [srv 0 host] + set slave_port [srv 0 port] + set slave_log [srv 0 stdout] + set slave_pid [s process_id] + start_server {overrides {active-replica yes}} { + set master [srv 0 client] + set master_host [srv 0 host] + set master_port [srv 0 port] + + # Use a short replication timeout on the slave, so that if there + # are no bugs the timeout is triggered in a reasonable amount + # of time. + $slave config set repl-timeout 5 + + # Start the replication process... + $slave slaveof $master_host $master_port + $master slaveof $slave_host $slave_port + + test {Active replicas report the correct role} { + wait_for_condition 50 100 { + [string match *active-replica* [$slave role]] + } else { + fail "Replica0 does not report the correct role" + } + wait_for_condition 50 100 { + [string match *active-replica* [$master role]] + } else { + fail "Replica1 does not report the correct role" + } + } + + test {Active replicas propogate} { + $master set testkey foo + wait_for_condition 50 500 { + [string match *foo* [$slave get testkey]] + } else { + fail "replication failed to propogate" + } + + $slave set testkey bar + wait_for_condition 50 500 { + [string match bar [$master get testkey]] + } else { + fail "replication failed to propogate in the other direction" + } + } + + test {Active replicas WAIT} { + # Test that wait succeeds since replicas should be syncronized + $master set testkey foo + $slave set testkey2 test + assert_equal {1} [$master wait 1 10] + assert_equal {1} [$slave wait 1 10] + + # Now setup a situation where wait should fail + exec kill -SIGSTOP $slave_pid + $master set testkey fee + assert_equal {0} [$master wait 1 1] + } + # Resume the replica we paused in the prior test + exec kill -SIGCONT $slave_pid + + test {Active replica expire propogates} { + $master set testkey1 foo + wait_for_condition 50 1000 { + [string match *foo* [$slave get testkey1]] + } else { + fail "Replication failed to propogate" + } + $master pexpire testkey1 200 + after 1000 + assert_equal {0} [$master del testkey1] + assert_equal {0} [$slave del testkey1] + + $slave set testkey1 foo px 200 + after 1000 + assert_equal {0} [$master del testkey1] + assert_equal {0} [$slave del testkey1] + } + } +} diff --git a/tests/test_helper.tcl b/tests/test_helper.tcl index 1442067f5..6abbddbbe 100644 --- a/tests/test_helper.tcl +++ b/tests/test_helper.tcl @@ -41,6 +41,7 @@ set ::all_tests { integration/replication-3 integration/replication-4 integration/replication-psync + integration/replication-active integration/aof integration/rdb integration/convert-zipmap-hash-on-load