[Tarantool-patches] [PATCH 2/4] raft: initialize raft completely at runtime
Serge Petrenko
sergepetrenko at tarantool.org
Mon Nov 9 15:50:13 MSK 2020
08.11.2020 21:03, Vladislav Shpilevoy пишет:
> Global raft object was created mostly at compile time with
> constant values assigned to all raft fields. But it won't work
> soon because raft will be moved to a separate library, and it
> will provide methods for raft creation and destruction.
>
> This patch makes raft not rely on compile time initialization,
> and moves it entirely to raft_init(). Also there are added some
> validations via new raft_validate() function, which should ensure
> raft is not used before creation.
>
> This may be hard to support, since raft is used by recovery and
> replication, even before instance has an ID. The validation should
> help to catch bugs related to the initialization order of these
> subsystems.
>
> Part of #5303
Hi! Thanks for the patch!
LGTM.
> ---
> src/box/raft.c | 37 ++++++++++++++++++++++---------------
> src/box/raft.h | 14 ++++++++++++++
> 2 files changed, 36 insertions(+), 15 deletions(-)
>
> diff --git a/src/box/raft.c b/src/box/raft.c
> index 8f8b59ba6..a6a893373 100644
> --- a/src/box/raft.c
> +++ b/src/box/raft.c
> @@ -46,21 +46,11 @@
>
> /** Raft state of this instance. */
> struct raft raft = {
> - .leader = 0,
> - .state = RAFT_STATE_FOLLOWER,
> - .volatile_term = 1,
> - .volatile_vote = 0,
> - .is_enabled = false,
> - .is_candidate = false,
> - .is_cfg_candidate = false,
> - .is_write_in_progress = false,
> - .is_broadcast_scheduled = false,
> - .term = 1,
> - .vote = 0,
> - .vote_mask = 0,
> - .vote_count = 0,
> - .worker = NULL,
> - .election_timeout = 5,
> + /*
> + * Set an invalid state to validate in all raft functions they are not
> + * used before raft initialization.
> + */
> + .state = 0,
> };
>
> /**
> @@ -325,6 +315,7 @@ raft_request_to_string(const struct raft_request *req)
> void
> raft_process_recovery(const struct raft_request *req)
> {
> + raft_validate();
> say_verbose("RAFT: recover %s", raft_request_to_string(req));
> if (req->term != 0) {
> raft.term = req->term;
> @@ -353,6 +344,7 @@ raft_process_recovery(const struct raft_request *req)
> int
> raft_process_msg(const struct raft_request *req, uint32_t source)
> {
> + raft_validate();
> say_info("RAFT: message %s from %u", raft_request_to_string(req),
> source);
> assert(source > 0);
> @@ -496,6 +488,7 @@ raft_process_msg(const struct raft_request *req, uint32_t source)
> void
> raft_process_heartbeat(uint32_t source)
> {
> + raft_validate();
> /*
> * Raft handles heartbeats from all instances, including anon instances
> * which don't participate in Raft.
> @@ -905,6 +898,7 @@ raft_sm_stop(void)
> void
> raft_serialize_for_network(struct raft_request *req, struct vclock *vclock)
> {
> + raft_validate();
> memset(req, 0, sizeof(*req));
> /*
> * Volatile state is never used for any communications.
> @@ -926,6 +920,7 @@ raft_serialize_for_network(struct raft_request *req, struct vclock *vclock)
> void
> raft_serialize_for_disk(struct raft_request *req)
> {
> + raft_validate();
> memset(req, 0, sizeof(*req));
> req->term = raft.term;
> req->vote = raft.vote;
> @@ -934,12 +929,14 @@ raft_serialize_for_disk(struct raft_request *req)
> void
> raft_on_update(struct trigger *trigger)
> {
> + raft_validate();
> trigger_add(&raft.on_update, trigger);
> }
>
> void
> raft_cfg_is_enabled(bool is_enabled)
> {
> + raft_validate();
> if (is_enabled == raft.is_enabled)
> return;
>
> @@ -952,6 +949,7 @@ raft_cfg_is_enabled(bool is_enabled)
> void
> raft_cfg_is_candidate(bool is_candidate)
> {
> + raft_validate();
> bool old_is_candidate = raft.is_candidate;
> raft.is_cfg_candidate = is_candidate;
> raft.is_candidate = is_candidate && raft.is_enabled;
> @@ -991,6 +989,7 @@ raft_cfg_is_candidate(bool is_candidate)
> void
> raft_cfg_election_timeout(double timeout)
> {
> + raft_validate();
> if (timeout == raft.election_timeout)
> return;
>
> @@ -1008,6 +1007,7 @@ raft_cfg_election_timeout(double timeout)
> void
> raft_cfg_election_quorum(void)
> {
> + raft_validate();
> if (raft.state != RAFT_STATE_CANDIDATE ||
> raft.state == RAFT_STATE_LEADER)
> return;
> @@ -1019,6 +1019,7 @@ raft_cfg_election_quorum(void)
> void
> raft_cfg_death_timeout(void)
> {
> + raft_validate();
> if (raft.state == RAFT_STATE_FOLLOWER && raft.is_candidate &&
> raft.leader != 0) {
> assert(ev_is_active(&raft.timer));
> @@ -1034,6 +1035,7 @@ raft_cfg_death_timeout(void)
> void
> raft_new_term(void)
> {
> + raft_validate();
> if (raft.is_enabled)
> raft_sm_schedule_new_term(raft.volatile_term + 1);
> }
> @@ -1079,6 +1081,11 @@ raft_schedule_broadcast(void)
> void
> raft_init(void)
> {
> + memset(&raft, 0, sizeof(raft));
> + raft.state = RAFT_STATE_FOLLOWER;
> + raft.volatile_term = 1;
> + raft.term = 1;
> + raft.election_timeout = 5;
> ev_timer_init(&raft.timer, raft_sm_schedule_new_election_cb, 0, 0);
> rlist_create(&raft.on_update);
> }
> diff --git a/src/box/raft.h b/src/box/raft.h
> index 8293d7410..0c60eccdf 100644
> --- a/src/box/raft.h
> +++ b/src/box/raft.h
> @@ -31,6 +31,7 @@
> */
> #include <stdint.h>
> #include <stdbool.h>
> +#include <assert.h>
> #include "tarantool_ev.h"
> #include "trigger.h"
>
> @@ -164,6 +165,16 @@ struct raft {
>
> extern struct raft raft;
>
> +/**
> + * Ensure the raft node can be used. I.e. that it is properly initialized.
> + * Entirely for debug purposes.
> + */
> +static inline void
> +raft_validate(void)
> +{
> + assert(raft.state != 0);
> +}
> +
> /**
> * A flag whether the instance is read-only according to Raft. Even if Raft
> * allows writes though, it does not mean the instance is writable. It can be
> @@ -172,6 +183,7 @@ extern struct raft raft;
> static inline bool
> raft_is_ro(void)
> {
> + raft_validate();
> return raft.is_enabled && raft.state != RAFT_STATE_LEADER;
> }
>
> @@ -179,6 +191,7 @@ raft_is_ro(void)
> static inline bool
> raft_is_source_allowed(uint32_t source_id)
> {
> + raft_validate();
> return !raft.is_enabled || raft.leader == source_id;
> }
>
> @@ -186,6 +199,7 @@ raft_is_source_allowed(uint32_t source_id)
> static inline bool
> raft_is_enabled(void)
> {
> + raft_validate();
> return raft.is_enabled;
> }
>
--
Serge Petrenko
More information about the Tarantool-patches
mailing list