Conversation
Author
kezhuw
reviewed
Sep 17, 2026
kezhuw
left a comment
Member
There was a problem hiding this comment.
On the next connection, getLastLoggedZxid() reads Z2 from the initialized in-memory database. The leader assumes Z2 is already durable and can continue with Z3. Once Z3 is persisted, the follower's transaction log contains a gap:
After a process restart, transaction-log replay detects the gap in ZKDatabase.addCommittedProposal() and throws:
It would be nice for tests to assert above.
Comment on lines
+406
to
+407
| assertFalse(zkDb.isInitialized()); | ||
| assertEquals(1, zkDb.loadDataBase()); |
Member
There was a problem hiding this comment.
Suggested change
| assertFalse(zkDb.isInitialized()); | |
| assertEquals(1, zkDb.loadDataBase()); | |
| if (!zkDb.isInitialized()) { | |
| zkDb.loadDataBase(); | |
| } |
I think we can treat zkDb.isInitialized() as implementation details, so we can assert what important.
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-5094
Description
A follower interrupted during
TRUNCsynchronization can retain an in-memory database that is ahead of its transaction log.For
TRUNCsynchronization,syncWithLeader()setssnapshotNeededtotrue. Committed transactions received beforeNEWLEADERare therefore applied directly to memory:The normal path persists this state by taking a snapshot when
NEWLEADERarrives:If the quorum connection fails before
NEWLEADER, the follower can be left with:Learner.shutdown()previously requested a full database shutdown only for an incompleteSNAPsynchronization:An incomplete
TRUNCdatabase was therefore retained.On the next connection,
getLastLoggedZxid()reads Z2 from the initialized in-memory database. The leader assumes Z2 is already durable and can continue with Z3. Once Z3 is persisted, the follower's transaction log contains a gap:After a process restart, transaction-log replay detects the gap in
ZKDatabase.addCommittedProposal()and throws:The follower then fails during database loading and cannot rejoin the quorum.
Solution
Treat an incomplete
TRUNCsynchronization like an incompleteSNAPsynchronization during learner shutdown:This clears the incomplete in-memory database. On the next synchronization attempt, the follower reloads its durable zxid from disk and requests all missing transactions from the leader.
Completed synchronization is unaffected because
syncWithLeader()changes the mode toNONEafter the required snapshot and transaction persistence have completed.Tests
Added
LearnerTest.incompleteTruncSyncClearsInMemoryDatabase.The test:
TRUNC(Z1).PROPOSAL(Z2)andCOMMIT(Z2).NEWLEADER, simulating a quorum connection failure.Without the fix, the database remains initialized at Z2 and the test fails. With the fix, the database is reloaded from Z1 and can be synchronized correctly.