Skip to content

Commit bb1a7cb

Browse files
authored
[FIX] Avoid killing the Auditor leader in BookieAutoRecoveryTest (apache#4769)
Three tests in BookieAutoRecoveryTest were flaking in CI because they sometimes killed the bookie that happened to be the Auditor leader, and the leader-failover chain (10s AuditorElector shutdown timeout + ZK session expiry + new election + first audit cycle) routinely exceeded the tests' 20s/90s latch timeouts under CI load. Make the bookie-to-kill choice deterministic w.r.t. the Auditor: - testOpenLedgers, testClosedLedgers, testStopWhileReplicationInProgress, testNoSuchLedgerExists: pick a non-Auditor bookie from the ensemble. - testEmptyLedgerLosesQuorumEventually needs to kill ensemble[2] then ensemble[1] specifically (it tests non-write-quorum bookie loss). Pin the Auditor onto ensemble[0] by stopping AutoRecovery on the two bookies the test will kill. Any slow failover happens in pre-flight, outside the timed assertions.
1 parent 354cc54 commit bb1a7cb

1 file changed

Lines changed: 51 additions & 14 deletions

File tree

bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/BookieAutoRecoveryTest.java

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public void testOpenLedgers() throws Exception {
157157
List<LedgerHandle> listOfLedgerHandle = createLedgersAndAddEntries(1, 5);
158158
LedgerHandle lh = listOfLedgerHandle.get(0);
159159
int ledgerReplicaIndex = 0;
160-
BookieId replicaToKillAddr = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(0);
160+
BookieId replicaToKillAddr = pickReplicaNotAuditor(lh);
161161

162162
final String urLedgerZNode = getUrLedgerZNode(lh);
163163
ledgerReplicaIndex = getReplicaIndexInLedger(lh, replicaToKillAddr);
@@ -211,7 +211,7 @@ public void testClosedLedgers() throws Exception {
211211
closeLedgers(listOfLedgerHandle);
212212
LedgerHandle lhandle = listOfLedgerHandle.get(0);
213213
int ledgerReplicaIndex = 0;
214-
BookieId replicaToKillAddr = lhandle.getLedgerMetadata().getAllEnsembles().get(0L).get(0);
214+
BookieId replicaToKillAddr = pickReplicaNotAuditor(lhandle);
215215

216216
CountDownLatch latch = new CountDownLatch(listOfLedgerHandle.size());
217217
for (LedgerHandle lh : listOfLedgerHandle) {
@@ -277,8 +277,7 @@ public void testStopWhileReplicationInProgress() throws Exception {
277277
List<LedgerHandle> listOfLedgerHandle = createLedgersAndAddEntries(
278278
numberOfLedgers, 5);
279279
closeLedgers(listOfLedgerHandle);
280-
LedgerHandle handle = listOfLedgerHandle.get(0);
281-
BookieId replicaToKillAddr = handle.getLedgerMetadata().getAllEnsembles().get(0L).get(0);
280+
BookieId replicaToKillAddr = pickReplicaNotAuditor(listOfLedgerHandle.get(0));
282281
LOG.info("Killing Bookie:" + replicaToKillAddr);
283282

284283
// Each ledger, there will be two events : create urLedger and after
@@ -362,13 +361,7 @@ public void testNoSuchLedgerExists() throws Exception {
362361
assertNull("UrLedger already exists!",
363362
watchUrLedgerNode(getUrLedgerZNode(lh), latch));
364363
}
365-
BookieId replicaToKillAddr = listOfLedgerHandle.get(0)
366-
.getLedgerMetadata().getAllEnsembles()
367-
.get(0L).get(0);
368-
killBookie(replicaToKillAddr);
369-
replicaToKillAddr = listOfLedgerHandle.get(0)
370-
.getLedgerMetadata().getAllEnsembles()
371-
.get(0L).get(0);
364+
BookieId replicaToKillAddr = pickReplicaNotAuditor(listOfLedgerHandle.get(0));
372365
killBookie(replicaToKillAddr);
373366
// waiting to publish urLedger znode by Auditor
374367
assertTrue("Ledgers should be marked as underreplicated",
@@ -405,13 +398,34 @@ public void testNoSuchLedgerExists() throws Exception {
405398
public void testEmptyLedgerLosesQuorumEventually() throws Exception {
406399
LOG.info("Start testEmptyLedgerLosesQuorumEventually");
407400
LedgerHandle lh = bkc.createLedger(3, 2, 2, DigestType.CRC32, PASSWD);
401+
List<BookieId> ensembleBookies = lh.getLedgerMetadata().getAllEnsembles().get(0L);
402+
403+
// Pin the Auditor onto ensemble[0] by stopping AutoRecovery on the bookies
404+
// the test will kill (ensemble[1] and ensemble[2]). Otherwise the slow ZK
405+
// leader-failover path blows past the 20s assertion timeouts in CI.
406+
for (int i = 1; i <= 2; i++) {
407+
BookieId killTarget = ensembleBookies.get(i);
408+
for (ServerTester t : servers) {
409+
if (t.getServer().getBookieId().equals(killTarget)) {
410+
t.stopAutoRecovery();
411+
}
412+
}
413+
}
414+
BookieId safeBookie = ensembleBookies.get(0);
415+
long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(30);
416+
while (!safeBookie.equals(getAuditorBookieId())) {
417+
if (System.nanoTime() > deadline) {
418+
throw new IllegalStateException("Auditor did not settle on ensemble[0]: " + safeBookie);
419+
}
420+
Thread.sleep(200);
421+
}
422+
408423
CountDownLatch latch = new CountDownLatch(1);
409424
String urZNode = getUrLedgerZNode(lh);
410425
watchUrLedgerNode(urZNode, latch);
411426

412-
BookieId replicaToKill = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(2);
413-
LOG.info("Killing last bookie, {}, in ensemble {}", replicaToKill,
414-
lh.getLedgerMetadata().getAllEnsembles().get(0L));
427+
BookieId replicaToKill = ensembleBookies.get(2);
428+
LOG.info("Killing last bookie, {}, in ensemble {}", replicaToKill, ensembleBookies);
415429
killBookie(replicaToKill);
416430
startNewBookie();
417431

@@ -618,6 +632,29 @@ private int getReplicaIndexInLedger(LedgerHandle lh, BookieId replicaToKill) {
618632
return ledgerReplicaIndex;
619633
}
620634

635+
private BookieId getAuditorBookieId() throws Exception {
636+
Auditor auditor = getAuditor(10, TimeUnit.SECONDS);
637+
for (ServerTester t : servers) {
638+
if (t.getAuditor() == auditor) {
639+
return t.getServer().getBookieId();
640+
}
641+
}
642+
throw new IllegalStateException("Auditor not found in cluster");
643+
}
644+
645+
// Killing the Auditor leader triggers a slow ZK leader-failover path that
646+
// routinely exceeds these tests' latch timeouts in CI; pick a non-Auditor
647+
// bookie from the ensemble instead.
648+
private BookieId pickReplicaNotAuditor(LedgerHandle lh) throws Exception {
649+
BookieId auditorId = getAuditorBookieId();
650+
for (BookieId addr : lh.getLedgerMetadata().getAllEnsembles().get(0L)) {
651+
if (!addr.equals(auditorId)) {
652+
return addr;
653+
}
654+
}
655+
throw new IllegalStateException("All ensemble bookies are the Auditor");
656+
}
657+
621658
private void verifyLedgerEnsembleMetadataAfterReplication(
622659
BookieServer newBookieServer, LedgerHandle lh,
623660
int ledgerReplicaIndex) throws Exception {

0 commit comments

Comments
 (0)