Fix intermittent GenerationIdTest.testMultiRS by re-advertising genId on change#725
Merged
vharseko merged 2 commits intoJul 11, 2026
Conversation
… on change The generationId gossip between replication servers is event-driven with no periodic re-advertisement: changeGenerationId() updated the field silently and relied on a single topology broadcast from the surrounding connect/status event. A peer RS that missed or raced that broadcast stayed stuck on a stale generationId (-1), which is the intermittent testMultiRS failure (expected:<48> but was:<-1>). Re-advertise the topology (sendTopoInfoToAll) on every real generationId transition so the gossip is self-healing and every connected peer converges.
maximthomas
approved these changes
Jul 10, 2026
maximthomas
reviewed
Jul 10, 2026
Comment on lines
+1726
to
+1736
|
|
||
| // The generationId gossip between replication servers is purely | ||
| // event-driven: it is carried in the topology messages sent on | ||
| // connect/disconnect/status events, and there is no periodic | ||
| // re-advertisement. A peer RS that misses (or races) the single | ||
| // topology broadcast following a generationId change would otherwise | ||
| // stay stuck with a stale generationId (typically -1) indefinitely - | ||
| // the intermittent GenerationIdTest.testMultiRS failure. Re-advertising | ||
| // the topology on every real generationId transition makes the gossip | ||
| // self-healing so every connected peer converges on the new value. | ||
| sendTopoInfoToAll(); |
Contributor
There was a problem hiding this comment.
Suggested change
| // The generationId gossip between replication servers is purely | |
| // event-driven: it is carried in the topology messages sent on | |
| // connect/disconnect/status events, and there is no periodic | |
| // re-advertisement. A peer RS that misses (or races) the single | |
| // topology broadcast following a generationId change would otherwise | |
| // stay stuck with a stale generationId (typically -1) indefinitely - | |
| // the intermittent GenerationIdTest.testMultiRS failure. Re-advertising | |
| // the topology on every real generationId transition makes the gossip | |
| // self-healing so every connected peer converges on the new value. | |
| sendTopoInfoToAll(); | |
| // generationId gossip is purely event-driven: it only travels in the | |
| // topology messages sent on connect/disconnect/status events. Re-advertise | |
| // on every real transition so a peer that missed one converges on the next. | |
| if (generationId > 0) | |
| { | |
| sendTopoInfoToAll(); | |
| } |
Edit: less verbose comment message
Member
Author
There was a problem hiding this comment.
Applied verbatim in 17d2ae1. The generationId > 0 guard is safe for both -1 paths: mayResetGenerationId() is a local cleanup each RS performs independently, and the ResetGenerationIdMsg path already forwards the reset to every connected RS itself. GenerationIdTest 4/4 green locally with the guard.
…erationIds Transitions to -1 need no topology re-advertisement: mayResetGenerationId() is a local cleanup each RS performs independently, and the ResetGenerationIdMsg path already forwards the reset to all connected RSs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
GenerationIdTest.testMultiRSintermittently fails on CI (e.g. the ubuntu-latest/17 leg of PR #720's run, unrelated to that PR) with:48=GenerationIdChecksum.EMPTY_BACKEND_GENERATION_ID;-1= "generationId not set". One replication server (replServer3) never converges on the common genId within the 120s wait.Root cause
The generationId gossip between replication servers is purely event-driven — it is carried in the topology messages sent on connect/disconnect/status events, and there is no periodic re-advertisement.
ReplicationServerDomain.changeGenerationId()silently updated the field and relied on a separate topology broadcast triggered by the surrounding event (e.g.register(DataServerHandler)→enqueueTopoInfoToAllExcept).If a peer RS misses or races that single broadcast — it finished joining the RS mesh in the narrow window where the origin RS had not yet adopted the new genId (so the RS↔RS handshake advertised
-1), and the one DS-register broadcast did not latch on it — nothing ever re-sends the value, so the peer stays stuck on the stale genId indefinitely (within the test window). That is exactly the observedexpected:<48> but was:<-1>.Prior fixes (#615 domain-ready wait, #618 timeout 60→120s, #622 wait for
getNumRSs()>=2) only narrowed the window; they cannot cover a missed broadcast because a missed broadcast is never retried.Fix
Re-advertise the topology (
sendTopoInfoToAll) on every real generationId transition inchangeGenerationId, so the gossip is self-healing: any peer that missed the first broadcast gets the next one, and every connected peer converges on the new value.Why it is safe
sendTopoInfoToAllonly enqueues topology messages ontopendingStatusMessagesand wakes theStatusAnalyzer; delivery is async. genId changes are rare in steady state, so the extra traffic is negligible. The reset path (resetGenerationId) already re-broadcasts; a second idempotent enqueue is harmless.changeGenerationIdholds onlygenerationIDLock;sendTopoInfoToAllacquirespendingStatusMessagesLock+ the analyzereventMonitor, neither of which is ever held while acquiringgenerationIDLock, so no new lock-ordering/deadlock risk.pendingStatusMessagesis initialised at field declaration andstatusAnalyzeris started in the constructor, both before anychangeGenerationIdcall.Tests
GenerationIdTest(failsafe) locally:Tests run: 4, Failures: 0, Errors: 0— BUILD SUCCESS.Being a timing flake, a green local run confirms no regression but cannot by itself prove the race is gone — the safety argument above is the primary evidence. A CI soak (re-running the job repeatedly) is recommended to build confidence.