This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 0623082c0e5a7383fcb91294c36c1e9c1f9ad7b5 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 fb91d76997..b9409f88f5 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(); @@ -178,13 +182,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) { @@ -193,7 +197,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]
