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

rmaucher pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 7b21f72d4a8e7c74fbbbcddf2bf9589ccadf94de
Author: opencode <[email protected]>
AuthorDate: Fri Oct 9 14:39:40 2026 +0200

    Fix inverted comparison in NonBlockingCoordinator.hasHigherPriority
    
    The method's contract is to return true when the complete membership
    has a higher priority leader than the local membership. With the
    AbsoluteOrder comparator, a lower value means a higher rank, so the
    comparison against the two sorted leaders must be smaller than zero.
    The inverted larger-than comparison made the only call site in
    handleViewConf() dead: mergeOnArrive() seeds the merged membership
    with the complete local membership, so the merged leader can never
    outrank the local one and the re-election triggered when a confirmed
    view contained a higher priority leader never fired.
    
    With the comparison fixed, the branch fires exactly when the local
    member outranks every other known member and a view was confirmed
    under a lower priority leader, letting the highest priority member
    assert its leadership immediately, as intended by the algorithm and
    consistent with the isHighest() gated elections on member events and
    heartbeats. The existing election guards keep this from causing
    election storms.
---
 .../group/interceptors/NonBlockingCoordinator.java |  2 +-
 .../TestNonBlockingCoordinatorPriority.java        | 48 ++++++++++++++++++++++
 2 files changed, 49 insertions(+), 1 deletion(-)

diff --git 
a/java/org/apache/catalina/tribes/group/interceptors/NonBlockingCoordinator.java
 
b/java/org/apache/catalina/tribes/group/interceptors/NonBlockingCoordinator.java
index 5e65d41719..baada05d1f 100644
--- 
a/java/org/apache/catalina/tribes/group/interceptors/NonBlockingCoordinator.java
+++ 
b/java/org/apache/catalina/tribes/group/interceptors/NonBlockingCoordinator.java
@@ -606,7 +606,7 @@ public class NonBlockingCoordinator extends 
ChannelInterceptorBase {
         }
         AbsoluteOrder.absoluteOrder(complete);
         AbsoluteOrder.absoluteOrder(local);
-        return (AbsoluteOrder.comp.compare(complete[0], local[0]) > 0);
+        return (AbsoluteOrder.comp.compare(complete[0], local[0]) < 0);
 
     }
 
diff --git 
a/test/org/apache/catalina/tribes/group/interceptors/TestNonBlockingCoordinatorPriority.java
 
b/test/org/apache/catalina/tribes/group/interceptors/TestNonBlockingCoordinatorPriority.java
new file mode 100644
index 0000000000..5716e87971
--- /dev/null
+++ 
b/test/org/apache/catalina/tribes/group/interceptors/TestNonBlockingCoordinatorPriority.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.catalina.tribes.group.interceptors;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.membership.MemberImpl;
+
+public class TestNonBlockingCoordinatorPriority {
+
+    @Test
+    public void testHasHigherPriority() throws Exception {
+        NonBlockingCoordinator coordinator = new NonBlockingCoordinator();
+
+        // Under absolute ordering, lower host bytes mean a higher rank
+        Member high = new MemberImpl("10.0.0.1", 4000, -1);
+        Member low = new MemberImpl("10.0.0.2", 4000, -1);
+
+        Assert.assertTrue("A membership with the higher priority member must 
win",
+                coordinator.hasHigherPriority(new Member[] { low, high }, new 
Member[] { low }));
+        Assert.assertFalse("A membership with the lower priority member must 
not win",
+                coordinator.hasHigherPriority(new Member[] { low }, new 
Member[] { high, low }));
+        Assert.assertFalse("Identical leaders must not win",
+                coordinator.hasHigherPriority(new Member[] { high }, new 
Member[] { high }));
+        Assert.assertFalse("An empty local membership must never be outranked",
+                coordinator.hasHigherPriority(new Member[] { high }, new 
Member[0]));
+        Assert.assertTrue("An empty complete membership is treated as higher 
priority",
+                coordinator.hasHigherPriority(null, new Member[] { high }));
+        Assert.assertFalse("A null local membership must never be outranked",
+                coordinator.hasHigherPriority(new Member[] { high }, null));
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to