1
0
mirror of https://github.com/codership/wsrep-lib.git synced 2025-07-03 16:22:35 +03:00

Fixed assertion on server_state connected - disconnecting transition

Transition from server_state connected state to disconnecting must
be allowed to deal with errors during server startup.

Added SST first test cases for server_state transitions:
* Successful join via SST
* Error in connect state
* Error in joiner state
This commit is contained in:
Teemu Ollakka
2018-12-19 13:53:02 +02:00
parent 1776537765
commit e81c66cd59
4 changed files with 101 additions and 10 deletions

View File

@ -117,7 +117,7 @@ namespace wsrep
* *
* @todo Fix UML generation * @todo Fix UML generation
* *
* Server state diagram if the sst_before_init() returns false. * Server state diagram if initialization happens before SST.
* *
* [*] --> disconnected * [*] --> disconnected
* disconnected --> initializing * disconnected --> initializing
@ -129,7 +129,7 @@ namespace wsrep
* synced --> donor * synced --> donor
* donor --> joined * donor --> joined
* *
* Server state diagram if the sst_before_init() returns true. * Server state diagram if SST happens before initialization.
* *
* [*] --> disconnected * [*] --> disconnected
* disconnected --> connected * disconnected --> connected

View File

@ -531,6 +531,9 @@ void wsrep::server_state::sst_received(wsrep::client_service& cs,
if (init_initialized_ == false) if (init_initialized_ == false)
{ {
state(lock, s_initializing); state(lock, s_initializing);
lock.unlock();
server_service_.debug_sync("on_view_wait_initialized");
lock.lock();
wait_until_state(lock, s_initialized); wait_until_state(lock, s_initialized);
assert(init_initialized_); assert(init_initialized_);
} }
@ -1072,7 +1075,7 @@ void wsrep::server_state::state(
{ 0, 1, 0, 1, 0, 0, 0, 0, 0}, /* dis */ { 0, 1, 0, 1, 0, 0, 0, 0, 0}, /* dis */
{ 1, 0, 1, 0, 0, 0, 0, 0, 0}, /* ing */ { 1, 0, 1, 0, 0, 0, 0, 0, 0}, /* ing */
{ 1, 0, 0, 1, 0, 1, 0, 0, 0}, /* ized */ { 1, 0, 0, 1, 0, 1, 0, 0, 0}, /* ized */
{ 1, 0, 0, 1, 1, 0, 0, 1, 0}, /* cted */ { 1, 0, 0, 1, 1, 0, 0, 1, 1}, /* cted */
{ 1, 1, 0, 0, 0, 1, 0, 0, 0}, /* jer */ { 1, 1, 0, 0, 0, 1, 0, 0, 0}, /* jer */
{ 1, 0, 0, 1, 0, 0, 0, 1, 1}, /* jed */ { 1, 0, 0, 1, 0, 0, 0, 1, 1}, /* jed */
{ 1, 0, 0, 0, 0, 1, 0, 0, 1}, /* dor */ { 1, 0, 0, 0, 0, 1, 0, 0, 1}, /* dor */

View File

@ -186,6 +186,10 @@ namespace wsrep
} sync_point_action_; } sync_point_action_;
bool sst_before_init_; bool sst_before_init_;
void logged_view(const wsrep::view& view)
{
logged_view_ = view;
}
private: private:
wsrep::server_state& server_state_; wsrep::server_state& server_state_;
unsigned long long last_client_id_; unsigned long long last_client_id_;

View File

@ -42,10 +42,12 @@ namespace
wsrep::provider::flag::commit) wsrep::provider::flag::commit)
, cluster_id("1") , cluster_id("1")
, bootstrap_view() , bootstrap_view()
, second_view()
{ {
wsrep::gtid state_id(cluster_id, wsrep::seqno(0)); wsrep::gtid state_id(cluster_id, wsrep::seqno(0));
std::vector<wsrep::view::member> members; std::vector<wsrep::view::member> members;
members.push_back(wsrep::view::member(wsrep::id("s1"), "name", "")); members.push_back(wsrep::view::member(
wsrep::id("s1"), "s1", ""));
bootstrap_view = wsrep::view(state_id, bootstrap_view = wsrep::view(state_id,
wsrep::seqno(1), wsrep::seqno(1),
wsrep::view::primary, wsrep::view::primary,
@ -54,6 +56,16 @@ namespace
1, // protocol version 1, // protocol version
members); members);
members.push_back(wsrep::view::member(
wsrep::id("s2"), "s2", ""));
second_view = wsrep::view(wsrep::gtid(cluster_id, wsrep::seqno(1)),
wsrep::seqno(2),
wsrep::view::primary,
0, // capabilities
1, // own index
1, // protocol version
members);
cc.open(cc.id()); cc.open(cc.id());
BOOST_REQUIRE(cc.before_command() == 0); BOOST_REQUIRE(cc.before_command() == 0);
} }
@ -65,6 +77,7 @@ namespace
wsrep::ws_meta ws_meta; wsrep::ws_meta ws_meta;
wsrep::id cluster_id; wsrep::id cluster_id;
wsrep::view bootstrap_view; wsrep::view bootstrap_view;
wsrep::view second_view;
void final_view() void final_view()
{ {
@ -79,6 +92,16 @@ namespace
); );
ss.on_view(view, &hps); ss.on_view(view, &hps);
} }
void disconnect()
{
BOOST_REQUIRE(ss.state() != wsrep::server_state::s_disconnecting);
ss.disconnect();
BOOST_REQUIRE(ss.state() == wsrep::server_state::s_disconnecting);
final_view();
BOOST_REQUIRE(ss.state() == wsrep::server_state::s_disconnected);
}
}; };
struct applying_server_fixture : server_fixture_base struct applying_server_fixture : server_fixture_base
@ -98,16 +121,37 @@ namespace
server_service.sst_before_init_ = true; server_service.sst_before_init_ = true;
} }
void connect_in_view(const wsrep::view& view)
{
BOOST_REQUIRE(ss.connect("cluster", "local", "0", false) == 0);
ss.on_connect(view);
BOOST_REQUIRE(ss.state() == wsrep::server_state::s_connected);
}
void prepare_for_sst()
{
ss.prepare_for_sst();
BOOST_REQUIRE(ss.state() == wsrep::server_state::s_joiner);
}
void sst_received_action()
{
server_service.sync_point_enabled_ = "on_view_wait_initialized";
server_service.sync_point_action_ = server_service.spa_initialize;
}
void clear_sst_received_action()
{
server_service.sync_point_enabled_ = "";
}
// Helper method to bootstrap the server with bootstrap view // Helper method to bootstrap the server with bootstrap view
void bootstrap() void bootstrap()
{ {
BOOST_REQUIRE(ss.connect("cluster", "local", "0", false) == 0); connect_in_view(bootstrap_view);
ss.on_connect(bootstrap_view);
BOOST_REQUIRE(ss.state() == wsrep::server_state::s_connected); sst_received_action();
server_service.sync_point_enabled_ = "on_view_wait_initialized";
server_service.sync_point_action_ = server_service.spa_initialize;
ss.on_view(bootstrap_view, &hps); ss.on_view(bootstrap_view, &hps);
server_service.sync_point_enabled_ = ""; clear_sst_received_action();
BOOST_REQUIRE(ss.state() == wsrep::server_state::s_joined); BOOST_REQUIRE(ss.state() == wsrep::server_state::s_joined);
ss.on_sync(); ss.on_sync();
BOOST_REQUIRE(ss.state() == wsrep::server_state::s_synced); BOOST_REQUIRE(ss.state() == wsrep::server_state::s_synced);
@ -258,6 +302,24 @@ BOOST_FIXTURE_TEST_CASE(server_state_sst_first_boostrap,
BOOST_REQUIRE(ss.state() == wsrep::server_state::s_synced); BOOST_REQUIRE(ss.state() == wsrep::server_state::s_synced);
} }
BOOST_FIXTURE_TEST_CASE(server_state_sst_first_join_with_sst,
sst_first_server_fixture)
{
connect_in_view(second_view);
prepare_for_sst();
sst_received_action();
// Mock server service get_view() gets view from logged_view_.
// Get_view() is called from sst_received(). This emulates the
// case where SST contains the view in which SST happens.
server_service.logged_view(second_view);
ss.sst_received(cc, wsrep::gtid(cluster_id, wsrep::seqno(2)), 0);
clear_sst_received_action();
BOOST_REQUIRE(ss.state() == wsrep::server_state::s_joined);
ss.on_sync();
BOOST_REQUIRE(ss.state() == wsrep::server_state::s_synced);
}
// Cycle from synced state to disconnected and back to synced. Server // Cycle from synced state to disconnected and back to synced. Server
// storage engines remain initialized. // storage engines remain initialized.
BOOST_FIXTURE_TEST_CASE( BOOST_FIXTURE_TEST_CASE(
@ -296,6 +358,28 @@ BOOST_FIXTURE_TEST_CASE(
BOOST_REQUIRE(ss.state() == wsrep::server_state::s_synced); BOOST_REQUIRE(ss.state() == wsrep::server_state::s_synced);
} }
//
// Error after connecting to cluster. This scenario may happen if SST
// request preparation fails.
//
BOOST_FIXTURE_TEST_CASE(
server_state_sst_first_error_on_connect,
sst_first_server_fixture)
{
connect_in_view(second_view);
BOOST_REQUIRE(ss.state() == wsrep::server_state::s_connected);
disconnect();
}
// Error during SST.q
BOOST_FIXTURE_TEST_CASE(
server_state_sst_first_error_on_joiner,
sst_first_server_fixture)
{
connect_in_view(second_view);
ss.prepare_for_sst();
BOOST_REQUIRE(ss.state() == wsrep::server_state::s_joiner);
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Test cases for init first // // Test cases for init first //