diff --git a/src/server_state.cpp b/src/server_state.cpp index 3d9a629..da62524 100644 --- a/src/server_state.cpp +++ b/src/server_state.cpp @@ -524,6 +524,15 @@ int wsrep::server_state::disconnect() { { wsrep::unique_lock lock(mutex_); + // In case of failure situations which are caused by provider + // being shut down some failing operation may also try to shut + // down the replication. Check the state here and + // return success if the provider disconnect is already in progress + // or has completed. + if (state(lock) == s_disconnecting || state(lock) == s_disconnected) + { + return 0; + } state(lock, s_disconnecting); interrupt_state_waiters(lock); } diff --git a/test/server_context_test.cpp b/test/server_context_test.cpp index 7ced77f..e10b926 100644 --- a/test/server_context_test.cpp +++ b/test/server_context_test.cpp @@ -615,3 +615,37 @@ BOOST_FIXTURE_TEST_CASE( ss.resume_and_resync(); BOOST_REQUIRE(ss.state() == wsrep::server_state::s_synced); } + +///////////////////////////////////////////////////////////////////////////// +// Disconnect // +///////////////////////////////////////////////////////////////////////////// + +BOOST_FIXTURE_TEST_CASE( + server_state_disconnect, + 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); +} + +// This test case verifies that the disconnect can be initiated +// concurrently by several callers. This may happen in failure situations +// where provider shutdown causes cascading failures and the failing operations +// try to disconnect the provider. +BOOST_FIXTURE_TEST_CASE( + server_state_disconnect_twice, + sst_first_server_fixture) +{ + bootstrap(); + ss.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); + ss.disconnect(); + BOOST_REQUIRE(ss.state() == wsrep::server_state::s_disconnected); +}