From 24974f36a40523adc4aed6a69134e21c5439e27e Mon Sep 17 00:00:00 2001 From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> Date: Tue, 6 Oct 2020 22:29:06 +0200 Subject: [PATCH] raft: introduce election_mode configuration option The new option can be one of 3 values: 'off', 'candidate', 'voter'. It replaces 2 old options: election_is_enabled and election_is_candidate. These flags looked strange, that it was possible to set candidate true, but disable election at the same time. Also it would not look good if we would ever decide to introduce another mode like a data-less sentinel node, for example. Just for voting. Anyway, the single option approach looks easier to configure and to extend. - 'off' means the election is disabled on the node. It is the same as election_is_enabled = false in the old config; - 'voter' means the node can vote and is never writable. The same as election_is_enabled = true + election_is_candidate = false in the old config; - 'candidate' means the node is a full-featured cluster member, which eventually may become a leader. The same as election_is_enabled = true + election_is_candidate = true in the old config. Part of #1146 --- src/box/box.cc | 54 +++++++----------------- src/box/box.h | 3 +- src/box/lua/cfg.cc | 15 ++----- src/box/lua/load_cfg.lua | 15 +++---- test/app-tap/init_script.result | 3 +- test/box/admin.result | 6 +-- test/box/cfg.result | 12 ++---- test/replication/election_basic.result | 28 ++++-------- test/replication/election_basic.test.lua | 17 +++----- test/replication/election_replica.lua | 3 +- 10 files changed, 48 insertions(+), 108 deletions(-) diff --git a/src/box/box.cc b/src/box/box.cc index 6ec813c129..566cb41efa 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -477,26 +477,17 @@ box_check_uri(const char *source, const char *option_name) } } -static int -box_check_election_is_enabled(void) +static const char * +box_check_election_mode(void) { - int b = cfg_getb("election_is_enabled"); - if (b < 0) { - diag_set(ClientError, ER_CFG, "election_is_enabled", - "the value must be a boolean"); + const char *mode = cfg_gets("election_mode"); + if (mode == NULL || (strcmp(mode, "off") != 0 && + strcmp(mode, "voter") != 0 && strcmp(mode, "candidate") != 0)) { + diag_set(ClientError, ER_CFG, "election_mode", "the value must " + "be a string 'off' or 'voter' or 'candidate'"); + return NULL; } - return b; -} - -static int -box_check_election_is_candidate(void) -{ - int b = cfg_getb("election_is_candidate"); - if (b < 0) { - diag_set(ClientError, ER_CFG, "election_is_candidate", - "the value must be a boolean"); - } - return b; + return mode; } static double @@ -768,9 +759,7 @@ box_check_config(void) box_check_uri(cfg_gets("listen"), "listen"); box_check_instance_uuid(&uuid); box_check_replicaset_uuid(&uuid); - if (box_check_election_is_enabled() < 0) - diag_raise(); - if (box_check_election_is_candidate() < 0) + if (box_check_election_mode() == NULL) diag_raise(); if (box_check_election_timeout() < 0) diag_raise(); @@ -797,22 +786,13 @@ box_check_config(void) } int -box_set_election_is_enabled(void) +box_set_election_mode(void) { - int b = box_check_election_is_enabled(); - if (b < 0) + const char *mode = box_check_election_mode(); + if (mode == NULL) return -1; - raft_cfg_is_enabled(b); - return 0; -} - -int -box_set_election_is_candidate(void) -{ - int b = box_check_election_is_candidate(); - if (b < 0) - return -1; - raft_cfg_is_candidate(b); + raft_cfg_is_candidate(strcmp(mode, "candidate") == 0); + raft_cfg_is_enabled(strcmp(mode, "off") != 0); return 0; } @@ -2786,15 +2766,13 @@ box_cfg_xc(void) * election-enabled node without election actually enabled leading to * disconnect. */ - if (box_set_election_is_candidate() != 0) - diag_raise(); if (box_set_election_timeout() != 0) diag_raise(); /* * Election is enabled last. So as all the parameters are installed by * that time. */ - if (box_set_election_is_enabled() != 0) + if (box_set_election_mode() != 0) diag_raise(); title("running"); diff --git a/src/box/box.h b/src/box/box.h index 45ff8bbbff..a151fb8f1d 100644 --- a/src/box/box.h +++ b/src/box/box.h @@ -245,8 +245,7 @@ void box_set_vinyl_memory(void); void box_set_vinyl_max_tuple_size(void); void box_set_vinyl_cache(void); void box_set_vinyl_timeout(void); -int box_set_election_is_enabled(void); -int box_set_election_is_candidate(void); +int box_set_election_mode(void); int box_set_election_timeout(void); void box_set_replication_timeout(void); void box_set_replication_connect_timeout(void); diff --git a/src/box/lua/cfg.cc b/src/box/lua/cfg.cc index bbb92f038d..42805e6027 100644 --- a/src/box/lua/cfg.cc +++ b/src/box/lua/cfg.cc @@ -270,17 +270,9 @@ lbox_cfg_set_worker_pool_threads(struct lua_State *L) } static int -lbox_cfg_set_election_is_enabled(struct lua_State *L) +lbox_cfg_set_election_mode(struct lua_State *L) { - if (box_set_election_is_enabled() != 0) - luaT_error(L); - return 0; -} - -static int -lbox_cfg_set_election_is_candidate(struct lua_State *L) -{ - if (box_set_election_is_candidate() != 0) + if (box_set_election_mode() != 0) luaT_error(L); return 0; } @@ -406,8 +398,7 @@ box_lua_cfg_init(struct lua_State *L) {"cfg_set_vinyl_max_tuple_size", lbox_cfg_set_vinyl_max_tuple_size}, {"cfg_set_vinyl_cache", lbox_cfg_set_vinyl_cache}, {"cfg_set_vinyl_timeout", lbox_cfg_set_vinyl_timeout}, - {"cfg_set_election_is_enabled", lbox_cfg_set_election_is_enabled}, - {"cfg_set_election_is_candidate", lbox_cfg_set_election_is_candidate}, + {"cfg_set_election_mode", lbox_cfg_set_election_mode}, {"cfg_set_election_timeout", lbox_cfg_set_election_timeout}, {"cfg_set_replication_timeout", lbox_cfg_set_replication_timeout}, {"cfg_set_replication_connect_quorum", lbox_cfg_set_replication_connect_quorum}, diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua index d558e7ac9c..76e2e92c2d 100644 --- a/src/box/lua/load_cfg.lua +++ b/src/box/lua/load_cfg.lua @@ -87,8 +87,7 @@ local default_cfg = { checkpoint_wal_threshold = 1e18, checkpoint_count = 2, worker_pool_threads = 4, - election_is_enabled = false, - election_is_candidate = true, + election_mode = 'off', election_timeout = 5, replication_timeout = 1, replication_sync_lag = 10, @@ -168,8 +167,7 @@ local template_cfg = { hot_standby = 'boolean', memtx_use_mvcc_engine = 'boolean', worker_pool_threads = 'number', - election_is_enabled = 'boolean', - election_is_candidate = 'boolean', + election_mode = 'string', election_timeout = 'number', replication_timeout = 'number', replication_sync_lag = 'number', @@ -287,8 +285,7 @@ local dynamic_cfg = { require('title').update(box.cfg.custom_proc_title) end, force_recovery = function() end, - election_is_enabled = private.cfg_set_election_is_enabled, - election_is_candidate = private.cfg_set_election_is_candidate, + election_mode = private.cfg_set_election_mode, election_timeout = private.cfg_set_election_timeout, replication_timeout = private.cfg_set_replication_timeout, replication_connect_timeout = private.cfg_set_replication_connect_timeout, @@ -344,8 +341,7 @@ local dynamic_cfg_order = { -- the new one. This should be fixed when box.cfg is able to -- apply some parameters together and atomically. replication_anon = 250, - election_is_enabled = 300, - election_is_candidate = 310, + election_mode = 300, election_timeout = 320, } @@ -364,8 +360,7 @@ local dynamic_cfg_skip_at_load = { vinyl_cache = true, vinyl_timeout = true, too_long_threshold = true, - election_is_enabled = true, - election_is_candidate = true, + election_mode = true, election_timeout = true, replication = true, replication_timeout = true, diff --git a/test/app-tap/init_script.result b/test/app-tap/init_script.result index d8969278bc..72aa67db22 100644 --- a/test/app-tap/init_script.result +++ b/test/app-tap/init_script.result @@ -8,8 +8,7 @@ checkpoint_count:2 checkpoint_interval:3600 checkpoint_wal_threshold:1e+18 coredump:false -election_is_candidate:true -election_is_enabled:false +election_mode:off election_timeout:5 feedback_enabled:true feedback_host:https://feedback.tarantool.io diff --git a/test/box/admin.result b/test/box/admin.result index 52b62356f0..8c5626c365 100644 --- a/test/box/admin.result +++ b/test/box/admin.result @@ -37,10 +37,8 @@ cfg_filter(box.cfg) - 1000000000000000000 - - coredump - false - - - election_is_candidate - - true - - - election_is_enabled - - false + - - election_mode + - off - - election_timeout - 5 - - feedback_enabled diff --git a/test/box/cfg.result b/test/box/cfg.result index f19f4bff77..4ad3c64937 100644 --- a/test/box/cfg.result +++ b/test/box/cfg.result @@ -25,10 +25,8 @@ cfg_filter(box.cfg) | - 1000000000000000000 | - - coredump | - false - | - - election_is_candidate - | - true - | - - election_is_enabled - | - false + | - - election_mode + | - off | - - election_timeout | - 5 | - - feedback_enabled @@ -140,10 +138,8 @@ cfg_filter(box.cfg) | - 1000000000000000000 | - - coredump | - false - | - - election_is_candidate - | - true - | - - election_is_enabled - | - false + | - - election_mode + | - off | - - election_timeout | - 5 | - - feedback_enabled diff --git a/test/replication/election_basic.result b/test/replication/election_basic.result index e59386f900..03917c7e40 100644 --- a/test/replication/election_basic.result +++ b/test/replication/election_basic.result @@ -11,25 +11,19 @@ old_election_timeout = box.cfg_election_timeout | ... -- Election is turned off by default. -assert(not box.cfg.election_is_enabled) - | --- - | - true - | ... --- Is candidate by default. Although it does not matter, until election is --- turned on. -assert(box.cfg.election_is_candidate) +assert(box.cfg.election_mode == 'off') | --- | - true | ... -- Ensure election options are validated. -box.cfg{election_is_enabled = 100} +box.cfg{election_mode = 100} | --- - | - error: 'Incorrect value for option ''election_is_enabled'': should be of type boolean' + | - error: 'Incorrect value for option ''election_mode'': should be of type string' | ... -box.cfg{election_is_candidate = 100} +box.cfg{election_mode = '100'} | --- - | - error: 'Incorrect value for option ''election_is_candidate'': should be of type - | boolean' + | - error: 'Incorrect value for option ''election_mode'': the value must be a string + | ''off'' or ''voter'' or ''candidate''' | ... box.cfg{election_timeout = -1} | --- @@ -64,10 +58,7 @@ assert(not box.info.ro) | ... -- Turned on election blocks writes until the instance becomes a leader. -box.cfg{election_is_candidate = false} - | --- - | ... -box.cfg{election_is_enabled = true} +box.cfg{election_mode = 'voter'} | --- | ... assert(box.info.election.state == 'follower') @@ -97,7 +88,7 @@ assert(box.info.election.leader == 0) box.cfg{election_timeout = 1000} | --- | ... -box.cfg{election_is_candidate = true} +box.cfg{election_mode = 'candidate'} | --- | ... test_run:wait_cond(function() return box.info.election.state == 'leader' end) @@ -118,8 +109,7 @@ assert(box.info.election.leader == box.info.id) | ... box.cfg{ \ - election_is_enabled = false, \ - election_is_candidate = true, \ + election_mode = 'off', \ election_timeout = old_election_timeout \ } | --- diff --git a/test/replication/election_basic.test.lua b/test/replication/election_basic.test.lua index 506d5ec4e4..1b4bb8d273 100644 --- a/test/replication/election_basic.test.lua +++ b/test/replication/election_basic.test.lua @@ -6,13 +6,10 @@ test_run = require('test_run').new() old_election_timeout = box.cfg_election_timeout -- Election is turned off by default. -assert(not box.cfg.election_is_enabled) --- Is candidate by default. Although it does not matter, until election is --- turned on. -assert(box.cfg.election_is_candidate) +assert(box.cfg.election_mode == 'off') -- Ensure election options are validated. -box.cfg{election_is_enabled = 100} -box.cfg{election_is_candidate = 100} +box.cfg{election_mode = 100} +box.cfg{election_mode = '100'} box.cfg{election_timeout = -1} box.cfg{election_timeout = 0} @@ -25,8 +22,7 @@ assert(box.info.election.leader == 0) assert(not box.info.ro) -- Turned on election blocks writes until the instance becomes a leader. -box.cfg{election_is_candidate = false} -box.cfg{election_is_enabled = true} +box.cfg{election_mode = 'voter'} assert(box.info.election.state == 'follower') assert(box.info.ro) -- Term is not changed, because the instance can't be a candidate, @@ -37,15 +33,14 @@ assert(box.info.election.leader == 0) -- Candidate instance votes immediately, if sees no leader. box.cfg{election_timeout = 1000} -box.cfg{election_is_candidate = true} +box.cfg{election_mode = 'candidate'} test_run:wait_cond(function() return box.info.election.state == 'leader' end) assert(box.info.election.term > term) assert(box.info.election.vote == box.info.id) assert(box.info.election.leader == box.info.id) box.cfg{ \ - election_is_enabled = false, \ - election_is_candidate = true, \ + election_mode = 'off', \ election_timeout = old_election_timeout \ } diff --git a/test/replication/election_replica.lua b/test/replication/election_replica.lua index b7d1aebe71..db037ed671 100644 --- a/test/replication/election_replica.lua +++ b/test/replication/election_replica.lua @@ -19,8 +19,7 @@ box.cfg({ instance_uri(3), }, replication_timeout = 0.1, - election_is_enabled = true, - election_is_candidate = true, + election_mode = 'candidate', election_timeout = ELECTION_TIMEOUT, replication_synchro_quorum = SYNCHRO_QUORUM, replication_synchro_timeout = 0.1, -- GitLab