This is an automated email from the ASF dual-hosted git repository.

lhotari pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git


The following commit(s) were added to refs/heads/master by this push:
     new bb1a7cbf9e [FIX] Avoid killing the Auditor leader in 
BookieAutoRecoveryTest (#4769)
bb1a7cbf9e is described below

commit bb1a7cbf9ec8aafbe2161dfdd5c95c1b046348ef
Author: Matteo Merli <[email protected]>
AuthorDate: Tue May 5 01:00:47 2026 -0700

    [FIX] Avoid killing the Auditor leader in BookieAutoRecoveryTest (#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.
---
 .../replication/BookieAutoRecoveryTest.java        | 65 +++++++++++++++++-----
 1 file changed, 51 insertions(+), 14 deletions(-)

diff --git 
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/BookieAutoRecoveryTest.java
 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/BookieAutoRecoveryTest.java
index ed9ca4e716..8bb7566295 100644
--- 
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/BookieAutoRecoveryTest.java
+++ 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/BookieAutoRecoveryTest.java
@@ -157,7 +157,7 @@ public class BookieAutoRecoveryTest extends 
BookKeeperClusterTestCase {
         List<LedgerHandle> listOfLedgerHandle = createLedgersAndAddEntries(1, 
5);
         LedgerHandle lh = listOfLedgerHandle.get(0);
         int ledgerReplicaIndex = 0;
-        BookieId replicaToKillAddr = 
lh.getLedgerMetadata().getAllEnsembles().get(0L).get(0);
+        BookieId replicaToKillAddr = pickReplicaNotAuditor(lh);
 
         final String urLedgerZNode = getUrLedgerZNode(lh);
         ledgerReplicaIndex = getReplicaIndexInLedger(lh, replicaToKillAddr);
@@ -211,7 +211,7 @@ public class BookieAutoRecoveryTest extends 
BookKeeperClusterTestCase {
         closeLedgers(listOfLedgerHandle);
         LedgerHandle lhandle = listOfLedgerHandle.get(0);
         int ledgerReplicaIndex = 0;
-        BookieId replicaToKillAddr = 
lhandle.getLedgerMetadata().getAllEnsembles().get(0L).get(0);
+        BookieId replicaToKillAddr = pickReplicaNotAuditor(lhandle);
 
         CountDownLatch latch = new CountDownLatch(listOfLedgerHandle.size());
         for (LedgerHandle lh : listOfLedgerHandle) {
@@ -277,8 +277,7 @@ public class BookieAutoRecoveryTest extends 
BookKeeperClusterTestCase {
         List<LedgerHandle> listOfLedgerHandle = createLedgersAndAddEntries(
                 numberOfLedgers, 5);
         closeLedgers(listOfLedgerHandle);
-        LedgerHandle handle = listOfLedgerHandle.get(0);
-        BookieId replicaToKillAddr = 
handle.getLedgerMetadata().getAllEnsembles().get(0L).get(0);
+        BookieId replicaToKillAddr = 
pickReplicaNotAuditor(listOfLedgerHandle.get(0));
         LOG.info("Killing Bookie:" + replicaToKillAddr);
 
         // Each ledger, there will be two events : create urLedger and after
@@ -362,13 +361,7 @@ public class BookieAutoRecoveryTest extends 
BookKeeperClusterTestCase {
             assertNull("UrLedger already exists!",
                     watchUrLedgerNode(getUrLedgerZNode(lh), latch));
         }
-        BookieId replicaToKillAddr = listOfLedgerHandle.get(0)
-            .getLedgerMetadata().getAllEnsembles()
-            .get(0L).get(0);
-        killBookie(replicaToKillAddr);
-        replicaToKillAddr = listOfLedgerHandle.get(0)
-            .getLedgerMetadata().getAllEnsembles()
-            .get(0L).get(0);
+        BookieId replicaToKillAddr = 
pickReplicaNotAuditor(listOfLedgerHandle.get(0));
         killBookie(replicaToKillAddr);
         // waiting to publish urLedger znode by Auditor
         assertTrue("Ledgers should be marked as underreplicated",
@@ -405,13 +398,34 @@ public class BookieAutoRecoveryTest extends 
BookKeeperClusterTestCase {
     public void testEmptyLedgerLosesQuorumEventually() throws Exception {
         LOG.info("Start testEmptyLedgerLosesQuorumEventually");
         LedgerHandle lh = bkc.createLedger(3, 2, 2, DigestType.CRC32, PASSWD);
+        List<BookieId> ensembleBookies = 
lh.getLedgerMetadata().getAllEnsembles().get(0L);
+
+        // Pin the Auditor onto ensemble[0] by stopping AutoRecovery on the 
bookies
+        // the test will kill (ensemble[1] and ensemble[2]). Otherwise the 
slow ZK
+        // leader-failover path blows past the 20s assertion timeouts in CI.
+        for (int i = 1; i <= 2; i++) {
+            BookieId killTarget = ensembleBookies.get(i);
+            for (ServerTester t : servers) {
+                if (t.getServer().getBookieId().equals(killTarget)) {
+                    t.stopAutoRecovery();
+                }
+            }
+        }
+        BookieId safeBookie = ensembleBookies.get(0);
+        long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(30);
+        while (!safeBookie.equals(getAuditorBookieId())) {
+            if (System.nanoTime() > deadline) {
+                throw new IllegalStateException("Auditor did not settle on 
ensemble[0]: " + safeBookie);
+            }
+            Thread.sleep(200);
+        }
+
         CountDownLatch latch = new CountDownLatch(1);
         String urZNode = getUrLedgerZNode(lh);
         watchUrLedgerNode(urZNode, latch);
 
-        BookieId replicaToKill = 
lh.getLedgerMetadata().getAllEnsembles().get(0L).get(2);
-        LOG.info("Killing last bookie, {}, in ensemble {}", replicaToKill,
-                 lh.getLedgerMetadata().getAllEnsembles().get(0L));
+        BookieId replicaToKill = ensembleBookies.get(2);
+        LOG.info("Killing last bookie, {}, in ensemble {}", replicaToKill, 
ensembleBookies);
         killBookie(replicaToKill);
         startNewBookie();
 
@@ -618,6 +632,29 @@ public class BookieAutoRecoveryTest extends 
BookKeeperClusterTestCase {
         return ledgerReplicaIndex;
     }
 
+    private BookieId getAuditorBookieId() throws Exception {
+        Auditor auditor = getAuditor(10, TimeUnit.SECONDS);
+        for (ServerTester t : servers) {
+            if (t.getAuditor() == auditor) {
+                return t.getServer().getBookieId();
+            }
+        }
+        throw new IllegalStateException("Auditor not found in cluster");
+    }
+
+    // Killing the Auditor leader triggers a slow ZK leader-failover path that
+    // routinely exceeds these tests' latch timeouts in CI; pick a non-Auditor
+    // bookie from the ensemble instead.
+    private BookieId pickReplicaNotAuditor(LedgerHandle lh) throws Exception {
+        BookieId auditorId = getAuditorBookieId();
+        for (BookieId addr : lh.getLedgerMetadata().getAllEnsembles().get(0L)) 
{
+            if (!addr.equals(auditorId)) {
+                return addr;
+            }
+        }
+        throw new IllegalStateException("All ensemble bookies are the 
Auditor");
+    }
+
     private void verifyLedgerEnsembleMetadataAfterReplication(
             BookieServer newBookieServer, LedgerHandle lh,
             int ledgerReplicaIndex) throws Exception {

Reply via email to