From a6db30da05525c9a8fd26271d7629501f0bab9a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ma=C5=9Blanka?= Date: Wed, 22 May 2024 09:20:42 +0000 Subject: [PATCH] r/prevote_stm: fail prevote if term changed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a candidate receives a reply with term which is different than requested then the vote should not be treated as success. Additionally the term of candidate should be updated. Signed-off-by: Michał Maślanka --- src/v/raft/prevote_stm.cc | 53 ++++++++++++++++++++++++++++----------- src/v/raft/prevote_stm.h | 3 +++ 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/v/raft/prevote_stm.cc b/src/v/raft/prevote_stm.cc index 12904c031e544..d2b2a6268d228 100644 --- a/src/v/raft/prevote_stm.cc +++ b/src/v/raft/prevote_stm.cc @@ -21,6 +21,7 @@ #include "rpc/types.h" #include "ssx/semaphore.h" +#include #include #include @@ -81,6 +82,18 @@ prevote_stm::process_reply(vnode n, ss::future> f) { auto r = f.get0(); if (r.has_value()) { auto v = r.value(); + if (v.term != _req.term) { + vlog( + _ctxlog.trace, + "prevote ack: node {} has a higher term {}", + n, + v.term); + voter_reply->second._is_failed = true; + voter_reply->second._is_pending = false; + if (v.term > _req.term) { + _term_update = v.term; + } + } _ptr->maybe_update_node_reply_timestamp(n); if (v.log_ok) { vlog( @@ -182,20 +195,32 @@ ss::future prevote_stm::do_prevote() { [this](vnode id) { ssx::background = dispatch_prevote(id); }); // process results - return process_replies().then([this]() { - const auto only_voter = _config->unique_voter_count() == 1 - && _config->is_voter(_ptr->self()); - if ( - _success && !only_voter - && _ptr->_node_priority_override == zero_voter_priority) { - vlog( - _ctxlog.debug, - "Ignoring successful pre-vote. Node priority too low: {}", - _ptr->_node_priority_override.value()); - _success = false; - } - return _success; - }); + return process_replies() + .then([this]() { + const auto only_voter = _config->unique_voter_count() == 1 + && _config->is_voter(_ptr->self()); + if ( + _success && !only_voter + && _ptr->_node_priority_override == zero_voter_priority) { + vlog( + _ctxlog.debug, + "Ignoring successful pre-vote. Node priority too low: {}", + _ptr->_node_priority_override.value()); + _success = false; + } + }) + .then([this] { + if (_term_update) { + return update_term().then([this] { return _success; }); + } + return ss::make_ready_future(_success); + }); +} + +ss::future<> prevote_stm::update_term() { + auto u = co_await _ptr->_op_lock.get_units(); + _ptr->_term = std::max(_ptr->term(), _term_update.value()); + _ptr->_vstate = consensus::vote_state::candidate; } ss::future<> prevote_stm::process_replies() { diff --git a/src/v/raft/prevote_stm.h b/src/v/raft/prevote_stm.h index f9d319d54f312..e3b740a5a3576 100644 --- a/src/v/raft/prevote_stm.h +++ b/src/v/raft/prevote_stm.h @@ -11,6 +11,7 @@ #pragma once +#include "model/fundamental.h" #include "outcome.h" #include "raft/logger.h" #include "raft/types.h" @@ -51,11 +52,13 @@ class prevote_stm { ss::future> do_dispatch_prevote(vnode); ss::future<> process_reply(vnode n, ss::future> f); ss::future<> process_replies(); + ss::future<> update_term(); // args consensus* _ptr; // make sure to always make a copy; never move() this struct vote_request _req; bool _success = false; + std::optional _term_update; // for sequentiality/progress ssx::semaphore _sem; std::optional _config;