INT-3433 Delay Failed IOs

JIRA: https://jira.spring.io/browse/INT-3433`

If a read fails due to insufficient threads, delay the read
for (default 100ms) - do not re-enable OP_READ until that
time has elapsed. Avoids spinning the CPU.

INT-3433 More Polishing

If the assembler couldn't execute a new assembler after assembling
the current message (when it detected there is more data), in the
finally block it would "continue" only if the socket was still
open.

The test case closes the socket after sending 4 messages so when
this condition occurred, the assembler failed to continue and
data was left in the buffer.

Remove the `isOpen()` check in the finally block and always continue
if there's not another assembler running and there's data available.

INT-3433 More Polishing

We can still get starvation if the selector is in a long
wait (in select()) when a read is delayed.

Whenever a read is delayed, wake the selector so its next
select will use the readDelay timeout.

INT-3433 Reference Docs

Also remove Thread.yield().

Revert redundant boolean return from `TcpNioConnection#checkForAssembler()`
This commit is contained in:
Gary Russell
2014-06-14 11:24:38 -04:00
committed by Artem Bilan
parent 69e20fc7db
commit 3c063a265b
6 changed files with 243 additions and 84 deletions

View File

@@ -73,7 +73,6 @@ import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.support.converter.MapMessageConverter;
import org.springframework.integration.test.util.SocketUtils;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.integration.util.CallerBlocksPolicy;
import org.springframework.integration.util.CompositeExecutor;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.ErrorMessage;
@@ -85,6 +84,7 @@ import org.springframework.util.ReflectionUtils.FieldFilter;
/**
* @author Gary Russell
* @author John Anderson
* @since 2.0
*
*/
@@ -608,7 +608,7 @@ public class TcpNioConnectionTests {
@Test
public void testAllMessagesDelivered() throws Exception {
final int numberOfSockets = 25;
final int numberOfSockets = 100;
final int port = SocketUtils.findAvailableServerSocket();
TcpNioServerConnectionFactory factory = new TcpNioServerConnectionFactory(port);
factory.setApplicationEventPublisher(mock(ApplicationEventPublisher.class));
@@ -616,7 +616,7 @@ public class TcpNioConnectionTests {
CompositeExecutor compositeExec = compositeExecutor();
factory.setTaskExecutor(compositeExec);
final CountDownLatch latch = new CountDownLatch(numberOfSockets);
final CountDownLatch latch = new CountDownLatch(numberOfSockets * 4);
factory.registerListener(new TcpListener() {
@Override
@@ -629,7 +629,7 @@ public class TcpNioConnectionTests {
});
factory.start();
Socket[] sockets = new Socket[numberOfSockets];
for (int i = 0; i < numberOfSockets; i++) {
Socket socket = null;
@@ -651,11 +651,28 @@ public class TcpNioConnectionTests {
}
Thread.sleep(100);
for (int i = 0; i < numberOfSockets; i++) {
sockets[i].getOutputStream().write(("...foo2\r\n").getBytes());
sockets[i].getOutputStream().write(("...foo2\r\nbar1 and...").getBytes());
sockets[i].getOutputStream().flush();
}
for (int i = 0; i < numberOfSockets; i++) {
sockets[i].getOutputStream().write(("...bar2\r\n").getBytes());
sockets[i].getOutputStream().flush();
}
for (int i = 0; i < numberOfSockets; i++) {
sockets[i].getOutputStream().write("foo3 and...".getBytes());
sockets[i].getOutputStream().flush();
}
Thread.sleep(100);
for (int i = 0; i < numberOfSockets; i++) {
sockets[i].getOutputStream().write(("...foo4\r\nbar3 and...").getBytes());
sockets[i].getOutputStream().flush();
}
for (int i = 0; i < numberOfSockets; i++) {
sockets[i].getOutputStream().write(("...bar4\r\n").getBytes());
sockets[i].close();
}
assertTrue(latch.await(10, TimeUnit.SECONDS));
assertTrue("latch is still " + latch.getCount(), latch.await(60, TimeUnit.SECONDS));
factory.stop();
}
@@ -666,7 +683,7 @@ public class TcpNioConnectionTests {
ioExec.setMaxPoolSize(4);
ioExec.setQueueCapacity(0);
ioExec.setThreadNamePrefix("io-");
ioExec.setRejectedExecutionHandler(new CallerBlocksPolicy(5000));
ioExec.setRejectedExecutionHandler(new AbortPolicy());
ioExec.initialize();
ThreadPoolTaskExecutor assemblerExec = new ThreadPoolTaskExecutor();
assemblerExec.setCorePoolSize(2);