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

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

commit cb3dcda2973683795b1664aa6fa8234c538d8d3f
Author: opencode <[email protected]>
AuthorDate: Fri Oct 9 11:26:58 2026 +0200

    Do not re-start already started services on overlapping starts
    
    ChannelCoordinator.internalStart() only rejected a start request when
    all of the requested service flags were already started. For a request
    that partially overlapped with the started services, e.g. a start of
    Channel.DEFAULT after a start of Channel.SND_RX_SEQ, the already
    started services were started a second time. For the data receiver,
    that recreated the task pool and bound a second socket; for the
    membership receiver, it failed with an IllegalStateException, leaving
    the channel in a partially started state.
    
    Compute the flags that are not started yet and drive the individual
    service start blocks from those, keeping the existing behavior of
    throwing when the whole request has already been started. Add
    testOverlappingPartialStart to cover the overlapping case.
---
 .../catalina/tribes/group/ChannelCoordinator.java   | 14 +++++++++-----
 .../tribes/group/TestGroupChannelStartStop.java     | 21 +++++++++++++++++++++
 2 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/java/org/apache/catalina/tribes/group/ChannelCoordinator.java 
b/java/org/apache/catalina/tribes/group/ChannelCoordinator.java
index e67a4fbbd5..f107a5d9e5 100644
--- a/java/org/apache/catalina/tribes/group/ChannelCoordinator.java
+++ b/java/org/apache/catalina/tribes/group/ChannelCoordinator.java
@@ -152,13 +152,17 @@ public class ChannelCoordinator extends 
ChannelInterceptorBase implements Messag
                 return;// nothing to start
             }
 
-            if (svc == (svc & startLevel)) {
+            // only start the services that are not started yet, so that a 
request
+            // that partially overlaps with the started services does not 
start the
+            // already started ones a second time
+            int toStart = svc & ~startLevel;
+            if (toStart == 0) {
                 throw new 
ChannelException(sm.getString("channelCoordinator.alreadyStarted", 
Integer.toString(svc)));
             }
 
             // must start the receiver first so that we can coordinate the 
port it
             // listens to with the local membership settings
-            if (Channel.SND_RX_SEQ == (svc & Channel.SND_RX_SEQ)) {
+            if (Channel.SND_RX_SEQ == (toStart & Channel.SND_RX_SEQ)) {
                 clusterReceiver.setMessageListener(this);
                 clusterReceiver.setChannel(getChannel());
                 clusterReceiver.start();
@@ -177,13 +181,13 @@ public class ChannelCoordinator extends 
ChannelInterceptorBase implements Messag
                 }
                 valid = true;
             }
-            if (Channel.SND_TX_SEQ == (svc & Channel.SND_TX_SEQ)) {
+            if (Channel.SND_TX_SEQ == (toStart & Channel.SND_TX_SEQ)) {
                 clusterSender.setChannel(getChannel());
                 clusterSender.start();
                 valid = true;
             }
 
-            if (Channel.MBR_RX_SEQ == (svc & Channel.MBR_RX_SEQ)) {
+            if (Channel.MBR_RX_SEQ == (toStart & Channel.MBR_RX_SEQ)) {
                 membershipService.setMembershipListener(this);
                 membershipService.setChannel(getChannel());
                 if (membershipService instanceof McastService) {
@@ -192,7 +196,7 @@ public class ChannelCoordinator extends 
ChannelInterceptorBase implements Messag
                 membershipService.start(MembershipService.MBR_RX);
                 valid = true;
             }
-            if (Channel.MBR_TX_SEQ == (svc & Channel.MBR_TX_SEQ)) {
+            if (Channel.MBR_TX_SEQ == (toStart & Channel.MBR_TX_SEQ)) {
                 membershipService.setChannel(getChannel());
                 membershipService.start(MembershipService.MBR_TX);
                 valid = true;
diff --git 
a/test/org/apache/catalina/tribes/group/TestGroupChannelStartStop.java 
b/test/org/apache/catalina/tribes/group/TestGroupChannelStartStop.java
index 584b86e5e5..48bc9631f2 100644
--- a/test/org/apache/catalina/tribes/group/TestGroupChannelStartStop.java
+++ b/test/org/apache/catalina/tribes/group/TestGroupChannelStartStop.java
@@ -126,6 +126,27 @@ public class TestGroupChannelStartStop {
         channel.stop(Channel.DEFAULT);
     }
 
+    @Test
+    public void testOverlappingPartialStart() throws Exception {
+        // start one service, then start everything: the already
+        // started service must not be started a second time
+        ReceiverBase rb = (ReceiverBase) channel.getChannelReceiver();
+        rb.setPort(45588);
+        // one bind attempt only, so a second start on the same port fails
+        rb.setAutoBind(0);
+        int count = 0;
+        try {
+            channel.start(Channel.SND_RX_SEQ);
+            count++;
+        } catch ( Exception x){x.printStackTrace();}
+        try {
+            channel.start(Channel.DEFAULT);
+            count++;
+        } catch ( Exception x){x.printStackTrace();}
+        Assert.assertEquals(2,count);
+        channel.stop(Channel.DEFAULT);
+    }
+
     @Test
     public void testFalseOption() throws Exception {
         int flag = 0xFFF0;//should get ignored by the underlying components


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

Reply via email to