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]
