ZOOKEEPER-5088: Initialize ObserverMaster with pending follower proposals - #2454
Open
JHSUYU wants to merge 1 commit into
Open
ZOOKEEPER-5088: Initialize ObserverMaster with pending follower proposals#2454JHSUYU wants to merge 1 commit into
JHSUYU wants to merge 1 commit into
Conversation
Author
Author
|
The unit test is somewhat tricky and ugly. Happy to revise if you have better suggestions. |
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.
JIRA: ZOOKEEPER-5088
Description
A follower acting as an ObserverMaster can receive an uncommitted proposal while synchronizing with the leader.
The relevant lifecycle in
Follower.followLeader()is:During
syncWithLeader(), outstanding proposals are converted to requests and logged directly:FollowerZooKeeperServer.logRequest()adds these proposals to the follower's pending transaction queue:However, ObserverMaster is created only after synchronization completes. These proposals therefore do not pass through the normal
Follower.processPacket(PROPOSAL)path that populates both queues:This can leave the follower and its ObserverMaster with different views of the same in-flight transaction:
If Z3 remains uncommitted until after ObserverMaster starts, the later COMMIT(Z3) reaches:
The follower finds Z3 in
pendingTxnsand applies it locally.ObserverMaster.proposalCommitted(Z3), however, cannot find Z3 inproposedPkts:It consequently returns without sending INFORM(Z3) to its downstream observers.
The next proposal, Z4, follows the normal packet-processing path after ObserverMaster exists. It is added to
proposedPktsand forwarded successfully, causing the observer to receive Z4 directly after Z2:When the observer processes Z4, it reaches the continuity check in
ZKDatabase.addCommittedProposal():Because the observer's
maxCommittedLogis Z2 while the incoming transaction is Z4, it throws:This is treated as a severe unrecoverable error and terminates the observer's critical CommitProcessor thread.
Solution
Initialize the new
ObserverMasterwith the follower's existingpendingTxnsbefore it starts accepting observer connections.Each pending
Requestis serialized into the sameINFORMrepresentation used by the normal proposal path and added toObserverMaster.proposedPkts.This preserves the handoff between follower synchronization and normal broadcasting:
Tests
Added
ObserverMasterPendingProposalTest, which runs three voting participants and one observer in a single JVM.The test:
ObserverMaster.CommitProcessorremains running.Without the fix, the observer skips the first proposal, receives an out-of-order zxid, throws
IllegalStateException, and terminates itsCommitProcessor.