mirror of
https://github.com/codership/wsrep-lib.git
synced 2025-07-30 07:23:07 +03:00
Allow server_state joiner - disconnecting transition.
Transition joiner - disconnecting may happen when the joiner failed to receive SST succesfully. Because the system is at undefined state at this point, skip most of the processing in sst_received() and return control to caller after notifying the provider about failure.
This commit is contained in:
@ -520,12 +520,26 @@ void wsrep::server_state::sst_sent(const wsrep::gtid& gtid, int error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void wsrep::server_state::sst_received(wsrep::client_service& cs,
|
void wsrep::server_state::sst_received(wsrep::client_service& cs,
|
||||||
const wsrep::gtid& gtid, int error)
|
const wsrep::gtid& gtid,
|
||||||
|
int const error)
|
||||||
{
|
{
|
||||||
wsrep::log_info() << "SST received: " << gtid;
|
wsrep::log_info() << "SST received: " << gtid;
|
||||||
wsrep::unique_lock<wsrep::mutex> lock(mutex_);
|
wsrep::unique_lock<wsrep::mutex> lock(mutex_);
|
||||||
assert(state_ == s_joiner || state_ == s_initialized);
|
assert(state_ == s_joiner || state_ == s_initialized);
|
||||||
|
|
||||||
|
// Deal with error case first. If the SST failed, the system
|
||||||
|
// may be in unrecoverable state. There is no point of doing
|
||||||
|
// anything else then notifying the provider about failure
|
||||||
|
// and returning control back to caller.
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
if (provider().sst_received(gtid, error))
|
||||||
|
{
|
||||||
|
throw wsrep::runtime_error("wsrep::sst_received() failed");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (server_service_.sst_before_init())
|
if (server_service_.sst_before_init())
|
||||||
{
|
{
|
||||||
if (init_initialized_ == false)
|
if (init_initialized_ == false)
|
||||||
@ -548,30 +562,27 @@ void wsrep::server_state::sst_received(wsrep::client_service& cs,
|
|||||||
"wsrep::sst_received() called before connection to cluster");
|
"wsrep::sst_received() called before connection to cluster");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 == error) /* SST was a success, recover view */
|
wsrep::view const v(server_service_.get_view(cs, id_));
|
||||||
|
wsrep::log_info() << "Recovered view from SST:\n" << v;
|
||||||
|
|
||||||
|
if (v.state_id().id() != gtid.id() ||
|
||||||
|
v.state_id().seqno() > gtid.seqno())
|
||||||
{
|
{
|
||||||
wsrep::view const v(server_service_.get_view(cs, id_));
|
/* Since IN GENERAL we may not be able to recover SST GTID from
|
||||||
wsrep::log_info() << "Recovered view from SST:\n" << v;
|
* the state data, we have to rely on SST script passing the GTID
|
||||||
|
* value explicitly.
|
||||||
if (v.state_id().id() != gtid.id() ||
|
* Here we check if the passed GTID makes any sense: it should
|
||||||
v.state_id().seqno() > gtid.seqno())
|
* have the same UUID and greater or equal seqno than the last
|
||||||
{
|
* logged view. */
|
||||||
/* Since IN GENERAL we may not be able to recover SST GTID from
|
std::ostringstream msg;
|
||||||
* the state data, we have to rely on SST script passing the GTID
|
msg << "SST script passed bogus GTID: " << gtid
|
||||||
* value explicitly.
|
<< ". Preceeding view GTID: " << v.state_id();
|
||||||
* Here we check if the passed GTID makes any sense: it should
|
throw wsrep::runtime_error(msg.str());
|
||||||
* have the same UUID and greater or equal seqno than the last
|
|
||||||
* logged view. */
|
|
||||||
std::ostringstream msg;
|
|
||||||
msg << "SST script passed bogus GTID: " << gtid
|
|
||||||
<< ". Preceeding view GTID: " << v.state_id();
|
|
||||||
throw wsrep::runtime_error(msg.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
current_view_ = v;
|
|
||||||
server_service_.log_view(NULL /* this view is stored already */, v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current_view_ = v;
|
||||||
|
server_service_.log_view(NULL /* this view is stored already */, v);
|
||||||
|
|
||||||
if (provider().sst_received(gtid, error))
|
if (provider().sst_received(gtid, error))
|
||||||
{
|
{
|
||||||
throw wsrep::runtime_error("wsrep::sst_received() failed");
|
throw wsrep::runtime_error("wsrep::sst_received() failed");
|
||||||
@ -1076,7 +1087,7 @@ void wsrep::server_state::state(
|
|||||||
{ 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, 1}, /* 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, 1}, /* 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 */
|
||||||
{ 1, 0, 0, 1, 0, 1, 1, 0, 1}, /* sed */
|
{ 1, 0, 0, 1, 0, 1, 1, 0, 1}, /* sed */
|
||||||
|
@ -371,7 +371,7 @@ BOOST_FIXTURE_TEST_CASE(
|
|||||||
disconnect();
|
disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error during SST.q
|
// Error during SST.
|
||||||
BOOST_FIXTURE_TEST_CASE(
|
BOOST_FIXTURE_TEST_CASE(
|
||||||
server_state_sst_first_error_on_joiner,
|
server_state_sst_first_error_on_joiner,
|
||||||
sst_first_server_fixture)
|
sst_first_server_fixture)
|
||||||
@ -379,6 +379,9 @@ BOOST_FIXTURE_TEST_CASE(
|
|||||||
connect_in_view(second_view);
|
connect_in_view(second_view);
|
||||||
ss.prepare_for_sst();
|
ss.prepare_for_sst();
|
||||||
BOOST_REQUIRE(ss.state() == wsrep::server_state::s_joiner);
|
BOOST_REQUIRE(ss.state() == wsrep::server_state::s_joiner);
|
||||||
|
ss.sst_received(cc, wsrep::gtid(wsrep::id::undefined(),
|
||||||
|
wsrep::seqno::undefined()), 1);
|
||||||
|
disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Reference in New Issue
Block a user