diff --git a/redis.conf b/redis.conf index a131b406fad53..6fbf26708c9f0 100644 --- a/redis.conf +++ b/redis.conf @@ -628,9 +628,15 @@ repl-disable-tcp-nodelay no # for instance if there are three replicas with priority 10, 100, 25 Sentinel # will pick the one with priority 10, that is the lowest. # -# However a special priority of 0 marks the replica as not able to perform the -# role of master, so a replica with priority of 0 will never be selected by -# Redis Sentinel for promotion. +# However there are special priority values: +# 0: the replica is marked as not able to perform the role of master, so a +# replica with priority of 0 will never be selected by Redis Sentinel +# for promotion. +# +# -1: the replica won't be exposed by Redis Sentinel to clients and the +# replica is marked as not able to perform the role of master +# (the same as 0). The 'sentinel replicas ' command will ignore +# replicas with priority of -1. # # By default the priority is 100. replica-priority 100 diff --git a/src/config.c b/src/config.c index 5db08f8bc9da2..e4e669962c2da 100644 --- a/src/config.c +++ b/src/config.c @@ -2464,7 +2464,7 @@ standardConfig configs[] = { createIntConfig("active-defrag-threshold-upper", NULL, MODIFIABLE_CONFIG, 0, 1000, server.active_defrag_threshold_upper, 100, INTEGER_CONFIG, NULL, NULL), /* Default: maximum defrag force at 100% fragmentation */ createIntConfig("lfu-log-factor", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.lfu_log_factor, 10, INTEGER_CONFIG, NULL, NULL), createIntConfig("lfu-decay-time", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.lfu_decay_time, 1, INTEGER_CONFIG, NULL, NULL), - createIntConfig("replica-priority", "slave-priority", MODIFIABLE_CONFIG, 0, INT_MAX, server.slave_priority, 100, INTEGER_CONFIG, NULL, NULL), + createIntConfig("replica-priority", "slave-priority", MODIFIABLE_CONFIG, -1, INT_MAX, server.slave_priority, 100, INTEGER_CONFIG, NULL, NULL), createIntConfig("repl-diskless-sync-delay", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.repl_diskless_sync_delay, 5, INTEGER_CONFIG, NULL, NULL), createIntConfig("maxmemory-samples", NULL, MODIFIABLE_CONFIG, 1, INT_MAX, server.maxmemory_samples, 5, INTEGER_CONFIG, NULL, NULL), createIntConfig("maxmemory-eviction-tenacity", NULL, MODIFIABLE_CONFIG, 0, 100, server.maxmemory_eviction_tenacity, 10, INTEGER_CONFIG, NULL, NULL), diff --git a/src/sentinel.c b/src/sentinel.c index 7f79e702ad5d3..d52d9dc06fe31 100644 --- a/src/sentinel.c +++ b/src/sentinel.c @@ -3249,12 +3249,24 @@ void addReplySentinelRedisInstance(client *c, sentinelRedisInstance *ri) { void addReplyDictOfRedisInstances(client *c, dict *instances) { dictIterator *di; dictEntry *de; + int ds; + + /* count elements excluding slaves with prio < 0 */ + ds = 0; + di = dictGetIterator(instances); + while((de = dictNext(di)) != NULL) { + sentinelRedisInstance *ri = dictGetVal(de); + if (ri->flags & SRI_SLAVE && ri->slave_priority < 0) continue; + ds++; + } + dictReleaseIterator(di); + addReplyArrayLen(c,ds); di = dictGetIterator(instances); - addReplyArrayLen(c,dictSize(instances)); while((de = dictNext(di)) != NULL) { sentinelRedisInstance *ri = dictGetVal(de); + if (ri->flags & SRI_SLAVE && ri->slave_priority < 0) continue; addReplySentinelRedisInstance(c,ri); } dictReleaseIterator(di); @@ -4482,7 +4494,7 @@ sentinelRedisInstance *sentinelSelectSlave(sentinelRedisInstance *master) { if (slave->flags & (SRI_S_DOWN|SRI_O_DOWN)) continue; if (slave->link->disconnected) continue; if (mstime() - slave->link->last_avail_time > SENTINEL_PING_PERIOD*5) continue; - if (slave->slave_priority == 0) continue; + if (slave->slave_priority <= 0) continue; /* If the master is in SDOWN state we get INFO for slaves every second. * Otherwise we get it with the usual period so we need to account for diff --git a/tests/sentinel/tests/08-replica-priority.tcl b/tests/sentinel/tests/08-replica-priority.tcl new file mode 100644 index 0000000000000..b76974b62ac7c --- /dev/null +++ b/tests/sentinel/tests/08-replica-priority.tcl @@ -0,0 +1,67 @@ +# Check that slaves are reconfigured at a latter time if they are partitioned. +# +# Here we should test: +# 1) That slaves point to the new master after failover. +# 2) That partitioned slaves point to new master when they are partitioned +# away during failover and return at a latter time. + +source "../tests/includes/init-tests.tcl" + +test "Check acceptable replica-priority values" { + foreach_redis_id id { + if {$id == $master_id} continue + + # ensure a priority of -2 throw an error + catch {R $id CONFIG SET replica-priority -2} e + if {$e eq "OK"} { + fail "Able to set replica-priority -2 to one redis replica whereas it should not be possible" + } + + # ensure a priority between -1 and 1000 is valid + for {set priority -1} {$priority <= 1000} {incr priority} { + catch {R $id CONFIG SET replica-priority $priority} e + if {$e ne "OK"} { + fail "Unable to set replica-priority $priority to one redis replica" + } + } + + # test only the first redis replica, no need to double test + break + } +} + +proc 08_test_number_of_replicas {} { + uplevel 1 { + test "Check sentinel replies with replicas ignoring those with priority of -1" { + # count number of replicas + set n_replicas 0 + foreach_redis_id id { + if {$id == $master_id} continue + if {[R $id CONFIG GET replica-priority] ne "replica-priority -1"} { + incr n_replicas + } + } + + # ensure sentinels replies with the right number of replicas + foreach_sentinel_id id { + # retries 40 x 500ms = 20s as SENTINEL_INFO_PERIOD = 10s + wait_for_condition 40 500 { + [llength [S $id SENTINEL REPLICAS mymaster]] == $n_replicas + } else { + fail "Sentinel replies with a wrong number of replicas with priority >=0" + } + } + } + } +} + + +08_test_number_of_replicas +test "Set replica-priority -1 of the first found replica" { + foreach_redis_id id { + if {$id == $master_id} continue + R $id CONFIG SET replica-priority "-1" + break + } +} +08_test_number_of_replicas