GH-2837: TCP NIO Prioritize accept

See https://github.com/spring-projects/spring-integration/pull/2837

Give priority to accepting new connections over reading data from
existing connections.
Add a flag to allow users to revert to the previous behavior of
giving reads priority.

**cherry-pick to 5.1.x**
This commit is contained in:
Gary Russell
2019-03-28 11:57:06 -04:00
committed by Artem Bilan
parent 56c4458150
commit 9428e34ee0
5 changed files with 112 additions and 33 deletions

View File

@@ -41,6 +41,7 @@ import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -73,6 +74,7 @@ import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.integration.ip.event.IpIntegrationEvent;
import org.springframework.integration.ip.tcp.connection.TcpNioConnection.ChannelInputStream;
import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer;
import org.springframework.integration.ip.tcp.serializer.MapJsonSerializer;
@@ -506,7 +508,7 @@ public class TcpNioConnectionTests {
doAnswer(new Answer<Integer>() {
@Override
public Integer answer(InvocationOnMock invocation) throws Throwable {
public Integer answer(InvocationOnMock invocation) {
ByteBuffer buff = invocation.getArgument(0);
byte[] bytes = written.toByteArray();
buff.put(bytes);
@@ -837,6 +839,57 @@ public class TcpNioConnectionTests {
assertThat(watch.getLastTaskTimeMillis()).isLessThan(950L);
}
@Test
public void testMultiAccept() throws InterruptedException, IOException {
testMulti(true);
}
@Test
public void testNoMultiAccept() throws InterruptedException, IOException {
testMulti(false);
}
private void testMulti(boolean multiAccept) throws InterruptedException, IOException {
CountDownLatch serverReadyLatch = new CountDownLatch(1);
CountDownLatch latch = new CountDownLatch(21);
List<Socket> sockets = new ArrayList<>();
TcpNioServerConnectionFactory server = new TcpNioServerConnectionFactory(0);
try {
List<IpIntegrationEvent> events = Collections.synchronizedList(new ArrayList<>());
List<Message<?>> messages = Collections.synchronizedList(new ArrayList<>());
server.setMultiAccept(multiAccept);
server.setApplicationEventPublisher(e -> {
if (e instanceof TcpConnectionServerListeningEvent) {
serverReadyLatch.countDown();
}
events.add((IpIntegrationEvent) e);
latch.countDown();
});
server.registerListener(m -> {
messages.add(m);
latch.countDown();
return false;
});
server.afterPropertiesSet();
server.start();
assertThat(serverReadyLatch.await(10, TimeUnit.SECONDS)).isTrue();
for (int i = 0; i < 10; i++) {
Socket socket = SocketFactory.getDefault().createSocket("localhost", server.getPort());
socket.getOutputStream().write("foo\r\n".getBytes());
sockets.add(socket);
}
assertThat(latch.await(10, TimeUnit.SECONDS));
assertThat(events).hasSize(11); // server ready + 10 opens
assertThat(messages).hasSize(10);
}
finally {
for (Socket socket : sockets) {
socket.close();
}
server.stop();
}
}
private void readFully(InputStream is, byte[] buff) throws IOException {
for (int i = 0; i < buff.length; i++) {
buff[i] = (byte) is.read();