Skip to content

MDEV-35940 Unallowed state transition: donor -> synced in galera_wan - #266

Open
plampio wants to merge 1 commit into
masterfrom
MDEV-35940
Open

plampio wants to merge 1 commit into
masterfrom
MDEV-35940

Conversation

@plampio

@plampio plampio commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Problem

In a debug build, galera.galera_wan (and galera_vote_rejoin_ddl) can abort with:

server: unallowed state transition: donor -> synced
Assertion `0' failed. // wsrep-lib/src/server_state.cpp:1371

The donor exit path is donor -> joined -> synced. The donor -> joined step is synthesized in sst_sent() / return_from_donor_state() because the v26 provider API has no JOINED event. But the provider's SYNCED callback (on_sync()) can arrive before sst_sent() runs, while the server is still s_donor, and the post-init branch of on_sync() then attempts the forbidden donor -> synced.

It is a race between two threads, serialized by server_state::mutex_ for atomicity but not for ordering:

  • donor SST thread (sst_donor_thread) → sst_sent()
    return_from_donor_state()donor -> joined
  • provider receive thread (wsrep_->recv()) → synced_cb
    on_sync()... -> synced

Fix

In the post-init branch of on_sync(), anticipate JOINED before going to synced, reusing the existing helper (mirrors what the initial-sync branch already does):

if (state_ == s_donor)
{
    return_from_donor_state(lock);   // donor -> joined
}
if (state_ != s_synced && state_ != s_disconnecting)
{
    state(lock, s_synced);           // joined -> synced
}

return_from_donor_state() only acts when state == s_donor, so it is a no-op in every other case.

Testing

  • New wsrep-lib unit test server_state_sst_first_sync_on_donor: drives start_sst (→ donor) then on_sync(), asserting it ends in synced. Reaching synced proves it routed through joined, since the state machine forbids a direct hop.
  • Verified the test aborts without the fix (SIGABRT at server_state.cpp:1371) and passes with it; full wsrep-lib suite green (162 cases).

When the provider delivers the SYNCED event while the server is still
in donor state, on_sync() attempted a direct donor -> synced transition,
which is not allowed and aborts in a debug build. This happens when
SYNCED arrives before sst_sent() had a chance to return the server from
donor to joined.

Anticipate JOINED in on_sync() via return_from_donor_state() so the
transition goes donor -> joined -> synced, mirroring what the initial
sync branch already does.

Add a wsrep-lib unit test covering on_sync() in donor state.
@plampio plampio self-assigned this Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant