From 313d7d243709e98f9472100757dd5f9c12ee0dc3 Mon Sep 17 00:00:00 2001 From: Teemu Ollakka Date: Fri, 11 Jun 2021 12:54:23 +0300 Subject: [PATCH] Enable DBMS initialization from applying codepath In general the provider might not guarantee that after joining to replication group, the first applied event is view event. Made init_initialized_ atomic and check it also from applying codepath. If the DBMS is not yet initialized when applying the first event, change state to initializing and wait for DBMS initialization completion. Notes: - Allow connected -> initializing state change. - Handle bootstrap_view in mock_connect to make server state synced for tests. --- include/wsrep/server_state.hpp | 5 ++++- src/server_state.cpp | 22 +++++++++++++++++++++- test/mock_server_state.hpp | 8 ++++++++ test/server_context_test.cpp | 16 ++++++++++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/include/wsrep/server_state.hpp b/include/wsrep/server_state.hpp index 0fa6420b..c6636f6d 100644 --- a/include/wsrep/server_state.hpp +++ b/include/wsrep/server_state.hpp @@ -92,10 +92,13 @@ #include "compiler.hpp" #include "xid.hpp" +#include #include #include #include #include +#include +#include /** * Magic string to tell provider to engage into trivial (empty) @@ -686,7 +689,7 @@ namespace wsrep mutable std::vector state_waiters_; bool bootstrap_; const wsrep::gtid initial_position_; - bool init_initialized_; + std::atomic init_initialized_; bool init_synced_; wsrep::gtid sst_gtid_; size_t desync_count_; diff --git a/src/server_state.cpp b/src/server_state.cpp index 79a720be..5b64428e 100644 --- a/src/server_state.cpp +++ b/src/server_state.cpp @@ -1098,6 +1098,26 @@ int wsrep::server_state::on_apply( const wsrep::ws_meta& ws_meta, const wsrep::const_buffer& data) { + if (not init_initialized_.load()) + { + wsrep::unique_lock lock(mutex_); + if (state(lock) == s_connected) + { + state(lock, s_initializing); + lock.unlock(); + server_service_.debug_sync("on_view_wait_initialized"); + lock.lock(); + } + while (not init_initialized_.load()) + { + wait_until_state(lock, s_initialized); + } + if (state(lock) == s_initialized) + { + state(lock, s_joined); + } + } + if (is_toi(ws_meta.flags())) { return apply_toi(provider(), high_priority_service, @@ -1330,7 +1350,7 @@ void wsrep::server_state::state( { 0, 1, 0, 1, 0, 0, 0, 0, 0}, /* dis */ { 1, 0, 1, 0, 0, 0, 0, 0, 1}, /* ing */ { 1, 0, 0, 1, 0, 1, 0, 0, 1}, /* ized */ - { 1, 0, 0, 1, 1, 0, 0, 1, 1}, /* cted */ + { 1, 1, 0, 1, 1, 0, 0, 1, 1}, /* cted */ { 1, 1, 0, 0, 0, 1, 0, 0, 1}, /* jer */ { 1, 0, 0, 1, 0, 0, 1, 1, 1}, /* jed */ { 1, 0, 0, 1, 0, 1, 0, 0, 1}, /* dor */ diff --git a/test/mock_server_state.hpp b/test/mock_server_state.hpp index 730c9c04..d22656df 100644 --- a/test/mock_server_state.hpp +++ b/test/mock_server_state.hpp @@ -278,6 +278,14 @@ namespace wsrep 1, members); server_state::on_connect(bootstrap_view); + server_state::initialized(); + wsrep::mock_client cs(*this, wsrep::client_id(0), + wsrep::client_state::m_high_priority); + wsrep::mock_high_priority_service hps(*this, &cs, false); + server_state::on_view(bootstrap_view, &hps); + BOOST_REQUIRE(state() == wsrep::server_state::s_joined); + server_state::on_sync(); + BOOST_REQUIRE(state() == wsrep::server_state::s_synced); } else { diff --git a/test/server_context_test.cpp b/test/server_context_test.cpp index 1c0b8bde..9ac8ccf6 100644 --- a/test/server_context_test.cpp +++ b/test/server_context_test.cpp @@ -485,6 +485,22 @@ BOOST_FIXTURE_TEST_CASE( BOOST_REQUIRE(ss.state() == wsrep::server_state::s_disconnected); } +BOOST_FIXTURE_TEST_CASE( + server_state_sst_first_init_on_apply, + sst_first_server_fixture) +{ + connect_in_view(second_view); + BOOST_REQUIRE(ss.state() == wsrep::server_state::s_connected); + sst_received_action(); + char buf[1] = { 1 }; + BOOST_REQUIRE(ss.on_apply(hps, ws_handle, ws_meta, + wsrep::const_buffer(buf, 1)) == 0); + const wsrep::transaction& txc(cc.transaction()); + BOOST_REQUIRE(txc.state() == wsrep::transaction::s_committed); + BOOST_REQUIRE(ss.state() == wsrep::server_state::s_joined); + +} + /////////////////////////////////////////////////////////////////////////////// // Test cases for init first // ///////////////////////////////////////////////////////////////////////////////