Repository navigation
Conversation
… 10 seconds
AuditorElector.shutdown() closed the ledger auditor manager on the
elector thread and waited up to 10 seconds for it. On a bookie that is
not the auditor, that thread waits in
LedgerAuditorManager.tryToBecomeAuditor() until the bookie becomes the
auditor, so the shutdown always timed out ("Failed to close auditor
manager in 10 seconds") before it interrupted the election and closed
the manager from the calling thread.
shutdown() now closes the auditor manager first, from the calling
thread, then waits for the election task to end (still interrupting it
after 10 seconds). ZkLedgerAuditorManager.close() releases a candidate
waiting for the previous one in line, and tryToBecomeAuditor() fails on
a closed manager instead of returning as if the bookie had been
elected; a vote the candidate created while close() ran is deleted too.
Once the elector is shutting down, its election task neither starts an
Auditor nor logs an error.
close() can now run while tryToBecomeAuditor() runs. When it deleted the vote after the candidate created it, the candidate could find its vote missing among the children and fail with "My vote has disappeared" (IllegalArgumentException). It now fails like any other call on a closed manager.
There was a problem hiding this comment.
🟡 Changes recommended
Critical shutdown and election issues can cause indefinite blocking, skip resource cleanup after interruption, and allow a closed candidate to overwrite a replacement auditor’s ID.
3 open issues
What changed in this PR
This PR reduces auto-recovery shutdown delays for non-auditor bookies by releasing waiting election candidates rather than queuing cleanup behind the election task.
Changes:
- Close the auditor manager before waiting for the election executor to stop.
- Wake waiting ZooKeeper candidates on close and handle concurrent vote creation and deletion.
- Add regression tests for follower shutdown and closing a waiting candidate.
| File | Description |
|---|---|
bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorBookieTest.java |
Tests prompt shutdown, candidate failure, and vote cleanup. |
bookkeeper-server/src/main/java/org/apache/bookkeeper/replication/AuditorElector.java |
Reorders shutdown and suppresses expected shutdown-related election errors. |
bookkeeper-server/src/main/java/org/apache/bookkeeper/meta/ZkLedgerAuditorManager.java |
Releases waiting candidates and adds closure checks and vote cleanup. |
Review effort: Balanced
…tdown - AuditorElector.shutdown() closes the auditor manager on a separate thread and gives it 10 seconds before interrupting it: closing deletes the vote, which waits for ZooKeeper to be reachable, and before, the close queued on the auditor's elector thread was interrupted after 10 seconds too. - An interrupted shutdown() stops the election, and still shuts the auditor down and closes the owned client before rethrowing the InterruptedException. It left them running, and a later shutdown() returned right away since the executor was shut down. - ZkLedgerAuditorManager checks that it isn't closed and publishes the id of an elected candidate under the lock close() takes before deleting the vote: a candidate closed after it listed the votes published its id, possibly after the next auditor, and returned as elected.
codelipenghui
left a comment
There was a problem hiding this comment.
Reviewed head 158e0b74122f006563390d8c3346e33754b5bc2b.
The change addresses the blocked election-queue shutdown and fits the existing architecture. Please address the P2 cleanup issue noted inline: interrupting the shutdown caller can leave the new manager-close thread uncancelled.
Validation limitations: the focused Maven test invocation stopped in an upstream module because the selected server tests did not match there. A separate compilation attempt stopped at the native dependency because no default Rust toolchain was configured. The server tests did not execute; the finding is based on source analysis, not a runtime reproduction.
When the thread calling AuditorElector.shutdown() was interrupted while it waited for the auditor manager to close, the join threw before the closer was interrupted, and nothing else could interrupt it: during a ZooKeeper outage the close kept retrying the vote deletion past the 10 seconds it is given, holding on to the elector, and a later shutdown() returned right away. The closer is now interrupted before the InterruptedException propagates. testInterruptedShutdownInterruptsManagerClose interrupts a shutdown while the manager's close blocks, and asserts that shutdown() throws InterruptedException and that the close is interrupted.
codelipenghui
left a comment
There was a problem hiding this comment.
Code Review approval for commit a6fda44.
Summary:
The previous P2 is addressed: interrupted join now cancels the closer before propagating, with a latch-controlled regression test for that path. No actionable findings identified within the reviewed scope. Recommend approval of the code change; replication CI passed, but integration CI remains red and local tests were not rerun.

Problem
AuditorElector.shutdown()runs the close of the ledger auditor manager on the elector's single thread and waits upto 10 seconds for it. On a bookie that is not the auditor, that thread is waiting in
LedgerAuditorManager.tryToBecomeAuditor()until the bookie becomes the auditor, so the close never runs there: everyshutdown of a non-auditor elector waits the full 10 seconds (
Failed to close auditor manager in 10 seconds), theninterrupts the election (
Interrupted while performing auditor election, logged at ERROR) and closes the manager fromthe calling thread. All the bookies but the auditor pay this whenever their auto recovery stops, e.g. at each step of
a rolling restart.
ZkLedgerAuditorManager.close()doesn't release a waiting candidate either, andtryToBecomeAuditor()returnsnormally when its loop sees the manager closed, as if the bookie had been elected.
Example
Change
AuditorElector.shutdown()closes the auditor manager first, on a separate thread, then shuts the executor downand waits up to 10 seconds for the election task to end (and interrupts it after that, as before). On the auditor's
own elector the election task has already returned, so nothing changes there. Closing the manager deletes the vote,
which waits for ZooKeeper to be reachable, so like the close queued on the elector's thread before, it gets
10 seconds before being interrupted, and is interrupted right away when the shutdown itself is (fourth commit).
An interrupted
shutdown()stops the election, and still shuts the auditor down and closes its own BookKeeperclient before rethrowing the
InterruptedException.The election task doesn't start an
AuditoriftryToBecomeAuditor()returns after the shutdown began, and whenthe shutdown ends the election it neither logs an error nor submits another shutdown task.
ZkLedgerAuditorManager.close()releases a candidate waiting for the previous vote in line, andtryToBecomeAuditor()throwsIllegalStateException("Auditor manager closed, give up to become auditor")on aclosed manager instead of returning. Since
close()can now run while the candidate creates its vote, the candidatechecks again after creating it and deletes a vote
close()might have missed (myVoteis now volatile), and a votethat
close()deleted under it no longer fails asMy vote has disappeared(second commit). An elected candidatechecks that the manager isn't closed and publishes its id in the election path under the lock
close()takesbefore deleting the vote, so that a closed candidate neither overwrites the id of the next auditor nor returns as
elected (third commit, with the separate thread and the interrupted shutdown).
Another
LedgerAuditorManagerwhoseclose()doesn't release a waiting candidate keeps the old behavior: 10 seconds,then an interrupt.
Testing
AuditorBookieTest.testShutdownFollowerElector: stops the elector of a bookie that isn't the auditor.shutdown()must return within 5 seconds, the elector's vote must be gone and the auditor unchanged. Fails on master(
TimeoutException).AuditorBookieTest.testCloseReleasesWaitingCandidate: closes aZkLedgerAuditorManagerwhosetryToBecomeAuditor()waits behind the running electors. The call must fail withIllegalStateExceptionwithin5 seconds, and its vote must be gone. Fails on master (
TimeoutException: the call keeps waiting).AuditorBookieTest.testCloseWhileCandidateIsElected: closes aZkLedgerAuditorManagerwhose only candidatehas listed the votes, its own first, but not yet published itself. The call must fail with
IllegalStateException,and the election path must not hold the candidate's id. Fails on master and without the third commit
(
A closed candidate became the auditor).AuditorBookieTest.testInterruptedShutdownStopsAuditor: shuts the auditor's elector down from an interruptedthread.
shutdown()must throwInterruptedExceptionafter stopping the auditor, and the vote must be gone. Failson master and without the third commit (
Auditor still running).AuditorBookieTest.testInterruptedShutdownInterruptsManagerClose: interrupts a shutdown while the auditormanager's close blocks, as for an unreachable ZooKeeper.
shutdown()must throwInterruptedException, and theclose must be interrupted within 5 seconds. Fails without the fourth commit (
TimeoutException: the close is neverinterrupted).
org.apache.bookkeeper.replicationtests (19 classes) plusBookKeeperAdminTest,BookieDecommissionTest,TestHttpServiceandBookieInitializationTestpass, except 4BookieInitializationTesttests that fail locallyon master too (they can't resolve the machine's hostname).
AuditorBookieTestandAutoRecoveryMainTestpassed3 more times after the second commit, and all of them again with the third (198 tests; the 23 classes took
1,172 s), and
AuditorBookieTestagain with the fourth (10 tests). Checkstyle and SpotBugs pass.Those 23 classes on master and with this change, one run each (other test runs were going on at the same time; the
waits removed have fixed lengths):
AuditorBookieTestAuditorLedgerCheckerTestBookieAutoRecoveryTestBookieDecommissionTestAuditorPeriodicCheckTestBookKeeperAdminTestTestAutoRecoveryAlongWithBookieServersFailed to close auditor manager in 10 secondsappears 68 times in master's logs of these classes, and never withthis change.