From 76424ad5157b52d1b61e082ef8d6ab857dd42f0b Mon Sep 17 00:00:00 2001 From: Teemu Ollakka Date: Fri, 14 Dec 2018 13:03:37 +0200 Subject: [PATCH] codership/wsrep-lib#34 Unit test for sync-disconnect-sync Added unit test for sync-disconnect-sync transition without SST. --- include/wsrep/server_state.hpp | 11 ++++++ src/server_state.cpp | 8 ++++ test/server_context_test.cpp | 71 +++++++++++++++++++++++++++++++--- 3 files changed, 85 insertions(+), 5 deletions(-) diff --git a/include/wsrep/server_state.hpp b/include/wsrep/server_state.hpp index 96226e4..ce58dca 100644 --- a/include/wsrep/server_state.hpp +++ b/include/wsrep/server_state.hpp @@ -286,6 +286,16 @@ namespace wsrep return *provider_; } + /** + * Initialize connection to cluster. + * + * @param cluster_name A string containing the name of the cluster + * @param cluster_address Cluster address string + * @param state_donor String containing a list of desired donors + * @param bootstrap Bootstrap option + * + * @return Zero in case of success, non-zero on error. + */ int connect(const std::string& cluster_name, const std::string& cluster_address, const std::string& state_donor, @@ -598,6 +608,7 @@ namespace wsrep // Close transactions when handling disconnect from the group. void close_transactions_at_disconnect(wsrep::high_priority_service&); + // Common actions on final view void go_final(wsrep::unique_lock&, const wsrep::view&, wsrep::high_priority_service*); diff --git a/src/server_state.cpp b/src/server_state.cpp index 1cb11d0..3e67f65 100644 --- a/src/server_state.cpp +++ b/src/server_state.cpp @@ -686,6 +686,7 @@ void wsrep::server_state::on_view(const wsrep::view& view, wsrep::log_info() << "================================================\nView:\n" << " id: " << view.state_id() << "\n" + << " seqno: " << view.view_seqno() << "\n" << " status: " << view.status() << "\n" << " prococol_version: " << view.protocol_version() << "\n" << " own_index: " << view.own_index() << "\n" @@ -722,6 +723,13 @@ void wsrep::server_state::on_view(const wsrep::view& view, { state(lock, s_joiner); state(lock, s_initializing); + if (init_initialized_) + { + // If storage engines have already been initialized, + // skip directly to s_joined. + state(lock, s_initialized); + state(lock, s_joined); + } } else if (state_ == s_joiner) { diff --git a/test/server_context_test.cpp b/test/server_context_test.cpp index 703d448..119e76c 100644 --- a/test/server_context_test.cpp +++ b/test/server_context_test.cpp @@ -65,6 +65,20 @@ namespace wsrep::ws_meta ws_meta; wsrep::id cluster_id; wsrep::view bootstrap_view; + + void final_view() + { + BOOST_REQUIRE(ss.state() != wsrep::server_state::s_disconnected); + wsrep::view view(wsrep::gtid(), // state_id + wsrep::seqno::undefined(), // view seqno + wsrep::view::disconnected, // status + 0, // capabilities + -1, // own_index + 0, // protocol ver + std::vector() // members + ); + ss.on_view(view, &hps); + } }; struct applying_server_fixture : server_fixture_base @@ -83,6 +97,22 @@ namespace { server_service.sst_before_init_ = true; } + + // Helper method to bootstrap the server with bootstrap view + void bootstrap() + { + BOOST_REQUIRE(ss.connect("cluster", "local", "0", false) == 0); + ss.on_connect(bootstrap_view); + BOOST_REQUIRE(ss.state() == wsrep::server_state::s_connected); + server_service.sync_point_enabled_ = "on_view_wait_initialized"; + server_service.sync_point_action_ = server_service.spa_initialize; + ss.on_view(bootstrap_view, &hps); + server_service.sync_point_enabled_ = ""; + BOOST_REQUIRE(ss.state() == wsrep::server_state::s_joined); + ss.on_sync(); + BOOST_REQUIRE(ss.state() == wsrep::server_state::s_synced); + } + }; struct init_first_server_fixture : server_fixture_base @@ -210,18 +240,49 @@ BOOST_AUTO_TEST_CASE(server_state_state_strings) BOOST_FIXTURE_TEST_CASE(server_state_sst_first_boostrap, sst_first_server_fixture) { + bootstrap(); + BOOST_REQUIRE(ss.state() == wsrep::server_state::s_synced); +} + +// Cycle from synced state to disconnected and back to synced. Server +// storage engines remain initialized. +BOOST_FIXTURE_TEST_CASE( + server_state_sst_first_synced_disconnected_synced_no_sst, + sst_first_server_fixture) +{ + bootstrap(); + ss.disconnect(); + BOOST_REQUIRE(ss.state() == wsrep::server_state::s_disconnecting); + final_view(); + BOOST_REQUIRE(ss.state() == wsrep::server_state::s_disconnected); + + // Connect back as a sole member in the cluster BOOST_REQUIRE(ss.connect("cluster", "local", "0", false) == 0); - ss.on_connect(bootstrap_view); + // @todo: s_connecting state would be good to have + BOOST_REQUIRE(ss.state() == wsrep::server_state::s_disconnected); + // Server state must keep the initialized state + BOOST_REQUIRE(ss.is_initialized() == true); + std::vector members; + members.push_back(wsrep::view::member(wsrep::id("s1"), "name", "")); + wsrep::view view(wsrep::gtid(cluster_id, wsrep::seqno(1)), + wsrep::seqno(2), + wsrep::view::primary, + 0, // capabilities + 0, // own index + 1, // protocol version + members); + ss.on_connect(view); BOOST_REQUIRE(ss.state() == wsrep::server_state::s_connected); - server_service.sync_point_enabled_ = "on_view_wait_initialized"; - server_service.sync_point_action_ = server_service.spa_initialize; - ss.on_view(bootstrap_view, &hps); - server_service.sync_point_enabled_ = ""; + // As storage engines have been initialized, there should not be + // any reason to wait for initialization. State should jump directly + // to s_joined after handling the view. + ss.on_view(view, &hps); BOOST_REQUIRE(ss.state() == wsrep::server_state::s_joined); ss.on_sync(); BOOST_REQUIRE(ss.state() == wsrep::server_state::s_synced); } + /////////////////////////////////////////////////////////////////////////////// // Test cases for init first // ///////////////////////////////////////////////////////////////////////////////