INT-2419 Thread Starvation Detection

Previously, it was possible to run out of threads in
a fixed thread pool, and this could cause an indefinite
deadlock.

With this change, the deadlock is detected causing the
current message to fail, but freeing up the stuck
threads.

This was only seen with very small thread pools but
the potential was there for the condition to occur
under extreme conditions.

INT-2419 Deprecate poolSize Property

INT-2419 Polishing

Add note about OOM possibility now that an
unbounded task executor is used by default.
This commit is contained in:
Gary Russell
2012-05-22 20:24:31 -04:00
committed by Oleg Zhurakousky
parent 01225b8a48
commit 90fe92ae29
17 changed files with 420 additions and 183 deletions

View File

@@ -206,7 +206,6 @@
using-nio="#{props['use.nio']}"
single-use="true"
task-executor="externalTE"
pool-size="321"
using-direct-buffers="true"
interceptor-factory-chain="interceptors"
/>
@@ -232,11 +231,18 @@
using-nio="true"
single-use="true"
task-executor="externalTE"
pool-size="123"
backlog="123"
using-direct-buffers="true"
interceptor-factory-chain="interceptors"
/>
<ip:tcp-connection-factory
id="serverBackwardsCompatible"
type="server"
port="#{client1.port}"
pool-size="123"
/>
<ip:tcp-connection-factory
id="client2"
type="client"
@@ -254,7 +260,6 @@
using-nio="false"
single-use="true"
task-executor="externalTE"
pool-size="321"
interceptor-factory-chain="interceptors"
/>
@@ -275,7 +280,7 @@
using-nio="false"
single-use="true"
task-executor="externalTE"
pool-size="123"
backlog="123"
interceptor-factory-chain="interceptors"
/>

View File

@@ -154,6 +154,9 @@ public class ParserUnitTests {
@Autowired
AbstractConnectionFactory server1;
@Autowired
AbstractConnectionFactory serverBackwardsCompatible;
@Autowired
AbstractConnectionFactory server2;
@@ -404,7 +407,6 @@ public class ParserUnitTests {
assertEquals(true, dfa.getPropertyValue("soTcpNoDelay"));
assertEquals(true, dfa.getPropertyValue("singleUse"));
assertSame(taskExecutor, dfa.getPropertyValue("taskExecutor"));
assertEquals(321, dfa.getPropertyValue("poolSize"));
assertEquals(true, dfa.getPropertyValue("usingDirectBuffers"));
assertNotNull(dfa.getPropertyValue("interceptorFactoryChain"));
}
@@ -424,11 +426,18 @@ public class ParserUnitTests {
assertEquals(true, dfa.getPropertyValue("soTcpNoDelay"));
assertEquals(true, dfa.getPropertyValue("singleUse"));
assertSame(taskExecutor, dfa.getPropertyValue("taskExecutor"));
assertEquals(123, dfa.getPropertyValue("poolSize"));
assertEquals(123, dfa.getPropertyValue("backlog"));
assertEquals(true, dfa.getPropertyValue("usingDirectBuffers"));
assertNotNull(dfa.getPropertyValue("interceptorFactoryChain"));
}
@Test
public void testConnDeprecatedPoolSize() {
assertTrue(serverBackwardsCompatible instanceof TcpNetServerConnectionFactory);
DirectFieldAccessor dfa = new DirectFieldAccessor(serverBackwardsCompatible);
assertEquals(123, dfa.getPropertyValue("backlog"));
}
@Test
public void testConnClient2() {
assertTrue(client2 instanceof TcpNetClientConnectionFactory);
@@ -445,7 +454,6 @@ public class ParserUnitTests {
assertEquals(true, dfa.getPropertyValue("soTcpNoDelay"));
assertEquals(true, dfa.getPropertyValue("singleUse"));
assertSame(taskExecutor, dfa.getPropertyValue("taskExecutor"));
assertEquals(321, dfa.getPropertyValue("poolSize"));
assertNotNull(dfa.getPropertyValue("interceptorFactoryChain"));
}
@@ -464,7 +472,7 @@ public class ParserUnitTests {
assertEquals(true, dfa.getPropertyValue("soTcpNoDelay"));
assertEquals(true, dfa.getPropertyValue("singleUse"));
assertSame(taskExecutor, dfa.getPropertyValue("taskExecutor"));
assertEquals(123, dfa.getPropertyValue("poolSize"));
assertEquals(123, dfa.getPropertyValue("backlog"));
assertNotNull(dfa.getPropertyValue("interceptorFactoryChain"));
}

View File

@@ -37,7 +37,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import javax.net.ServerSocketFactory;
import org.junit.Test;
import org.springframework.core.serializer.DefaultDeserializer;
import org.springframework.core.serializer.DefaultSerializer;
import org.springframework.integration.Message;
@@ -54,7 +53,7 @@ import org.springframework.integration.support.MessageBuilder;
*/
public class TcpOutboundGatewayTests {
@Test
@Test
public void testGoodNetSingle() throws Exception {
final int port = SocketTestUtils.findAvailableServerSocket();
AbstractConnectionFactory ccf = new TcpNetClientConnectionFactory("localhost", port);
@@ -84,7 +83,6 @@ public class TcpOutboundGatewayTests {
ccf.setDeserializer(new DefaultDeserializer());
ccf.setSoTimeout(10000);
ccf.setSingleUse(true);
ccf.setPoolSize(10);
ccf.start();
assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));
TcpOutboundGateway gateway = new TcpOutboundGateway();
@@ -98,7 +96,7 @@ public class TcpOutboundGatewayTests {
gateway.handleMessage(MessageBuilder.withPayload("Test" + i).build());
}
Set<String> replies = new HashSet<String>();
for (int i = 100; i < 200; i++) {
for (int i = 100; i < 200; i++) {
Message<?> m = replyChannel.receive(10000);
assertNotNull(m);
replies.add((String) m.getPayload());
@@ -108,7 +106,7 @@ public class TcpOutboundGatewayTests {
}
}
@Test
@Test
public void testGoodNetMultiplex() throws Exception {
final int port = SocketTestUtils.findAvailableServerSocket();
final CountDownLatch latch = new CountDownLatch(1);
@@ -149,7 +147,7 @@ public class TcpOutboundGatewayTests {
gateway.handleMessage(MessageBuilder.withPayload("Test" + i).build());
}
Set<String> replies = new HashSet<String>();
for (int i = 100; i < 110; i++) {
for (int i = 100; i < 110; i++) {
Message<?> m = replyChannel.receive(10000);
assertNotNull(m);
replies.add((String) m.getPayload());
@@ -160,7 +158,7 @@ public class TcpOutboundGatewayTests {
done.set(true);
}
@Test
@Test
public void testGoodNetTimeout() throws Exception {
final int port = SocketTestUtils.findAvailableServerSocket();
final CountDownLatch latch = new CountDownLatch(1);
@@ -212,11 +210,11 @@ public class TcpOutboundGatewayTests {
}
Set<String> replies = new HashSet<String>();
int timeouts = 0;
for (int i = 0; i < 2; i++) {
for (int i = 0; i < 2; i++) {
try {
results[i].get();
} catch (InterruptedException e) {
} catch (ExecutionException e) {
if (timeouts > 0) {
fail("Unexpected " + e.getMessage());

View File

@@ -151,7 +151,7 @@ public class TcpReceivingChannelAdapterTests {
TcpNioServerConnectionFactory scf = new TcpNioServerConnectionFactory(port);
ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer();
scf.setSerializer(serializer);
scf.setDeserializer(serializer);
scf.setDeserializer(serializer);
scf.setSoTimeout(5000);
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
adapter.setConnectionFactory(scf);
@@ -168,7 +168,7 @@ public class TcpReceivingChannelAdapterTests {
Socket socket = SocketFactory.getDefault().createSocket("localhost", port);
for (int i = 0; i < 1000; i++) {
socket.getOutputStream().write(("Test" + i + "\r\n").getBytes());
}
}
Set<String> results = new HashSet<String>();
for (int i = 0; i < 1000; i++) {
Message<?> message = channel.receive(10000);
@@ -210,14 +210,14 @@ public class TcpReceivingChannelAdapterTests {
handler.handleMessage(message);
message = channel.receive(10000);
assertNotNull(message);
handler.handleMessage(message);
handler.handleMessage(message);
byte[] b = new byte[6];
readFully(socket.getInputStream(), b);
assertEquals("Test\r\n", new String(b));
readFully(socket.getInputStream(), b);
assertEquals("Test\r\n", new String(b));
}
@Test
public void testNioShared() throws Exception {
final int port = SocketTestUtils.findAvailableServerSocket();
@@ -248,14 +248,14 @@ public class TcpReceivingChannelAdapterTests {
handler.handleMessage(message);
message = channel.receive(10000);
assertNotNull(message);
handler.handleMessage(message);
handler.handleMessage(message);
byte[] b = new byte[6];
readFully(socket.getInputStream(), b);
assertEquals("Test\r\n", new String(b));
readFully(socket.getInputStream(), b);
assertEquals("Test\r\n", new String(b));
}
@Test
public void testNetSingleNoOutbound() throws Exception {
final int port = SocketTestUtils.findAvailableServerSocket();
@@ -316,7 +316,7 @@ public class TcpReceivingChannelAdapterTests {
socket.getOutputStream().write("Test1\r\n".getBytes());
socket = SocketFactory.getDefault().createSocket("localhost", port);
socket.getOutputStream().write("Test2\r\n".getBytes());
Message<?> message = channel.receive(10000);
Message<?> message = channel.receive(60000);
assertNotNull(message);
// with single use, results may come back in a different order
Set<String> results = new HashSet<String>();
@@ -371,15 +371,15 @@ public class TcpReceivingChannelAdapterTests {
handler.handleMessage(message);
message = channel.receive(10000);
assertNotNull(message);
handler.handleMessage(message);
handler.handleMessage(message);
byte[] b = new byte[7];
readFully(socket1.getInputStream(), b);
assertEquals("Test1\r\n", new String(b));
readFully(socket2.getInputStream(), b);
assertEquals("Test2\r\n", new String(b));
}
@Test
@Test
public void testNioSingleShared() throws Exception {
final int port = SocketTestUtils.findAvailableServerSocket();
TcpNioServerConnectionFactory scf = new TcpNioServerConnectionFactory(port);
@@ -412,15 +412,15 @@ public class TcpReceivingChannelAdapterTests {
handler.handleMessage(message);
message = channel.receive(10000);
assertNotNull(message);
handler.handleMessage(message);
handler.handleMessage(message);
byte[] b = new byte[7];
readFully(socket1.getInputStream(), b);
assertEquals("Test1\r\n", new String(b));
readFully(socket2.getInputStream(), b);
assertEquals("Test2\r\n", new String(b));
}
@Test
@Test
public void testNioSingleSharedMany() throws Exception {
final int port = SocketTestUtils.findAvailableServerSocket();
TcpNioServerConnectionFactory scf = new TcpNioServerConnectionFactory(port);
@@ -428,12 +428,12 @@ public class TcpReceivingChannelAdapterTests {
scf.setSerializer(serializer);
scf.setDeserializer(serializer);
scf.setSingleUse(true);
scf.setPoolSize(100);
scf.setBacklog(100);
TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
handler.setConnectionFactory(scf);
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
adapter.setConnectionFactory(scf);
Executor te = Executors.newFixedThreadPool(10);
Executor te = Executors.newCachedThreadPool();
scf.setTaskExecutor(te);
scf.start();
QueueChannel channel = new QueueChannel();
@@ -453,17 +453,17 @@ public class TcpReceivingChannelAdapterTests {
sockets.add(socket1);
}
for (int i = 100; i < 200; i++) {
Message<?> message = channel.receive(10000);
Message<?> message = channel.receive(60000);
assertNotNull(message);
handler.handleMessage(message);
}
byte[] b = new byte[9];
for (int i = 100; i < 200; i++) {
for (int i = 100; i < 200; i++) {
readFully(sockets.remove(0).getInputStream(), b);
assertEquals("Test" + i + "\r\n", new String(b));
}
}
@Test
public void testNetInterceptors() throws Exception {
final int port = SocketTestUtils.findAvailableServerSocket();
@@ -484,7 +484,7 @@ public class TcpReceivingChannelAdapterTests {
AbstractServerConnectionFactory scf = new TcpNetServerConnectionFactory(port);
singleSharedInterceptorsGuts(port, scf);
}
@Test
public void testNioInterceptors() throws Exception {
final int port = SocketTestUtils.findAvailableServerSocket();
@@ -509,11 +509,11 @@ public class TcpReceivingChannelAdapterTests {
private void interceptorsGuts(final int port, AbstractServerConnectionFactory scf) throws Exception {
scf.setSerializer(new DefaultSerializer());
scf.setDeserializer(new DefaultDeserializer());
scf.setSingleUse(false);
scf.setSingleUse(false);
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
adapter.setConnectionFactory(scf);
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
{new HelloWorldInterceptorFactory(),
new HelloWorldInterceptorFactory()});
scf.setInterceptorFactoryChain(fc);
@@ -553,7 +553,7 @@ public class TcpReceivingChannelAdapterTests {
scf.setSingleUse(true);
scf.setSoTimeout(10000);
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
{new HelloWorldInterceptorFactory(),
new HelloWorldInterceptorFactory()});
scf.setInterceptorFactoryChain(fc);
@@ -576,7 +576,7 @@ public class TcpReceivingChannelAdapterTests {
new ObjectOutputStream(socket.getOutputStream()).writeObject("Hello");
assertEquals("world!", new ObjectInputStream(socket.getInputStream()).readObject());
new ObjectOutputStream(socket.getOutputStream()).writeObject("Test1");
socket = SocketFactory.getDefault().createSocket("localhost", port);
new ObjectOutputStream(socket.getOutputStream()).writeObject("Hello");
assertEquals("world!", new ObjectInputStream(socket.getInputStream()).readObject());
@@ -601,7 +601,7 @@ public class TcpReceivingChannelAdapterTests {
scf.setSingleUse(true);
scf.setSoTimeout(60000);
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
{new HelloWorldInterceptorFactory(),
new HelloWorldInterceptorFactory()});
scf.setInterceptorFactoryChain(fc);
@@ -641,7 +641,7 @@ public class TcpReceivingChannelAdapterTests {
message = channel.receive(10000);
assertNotNull(message);
handler.handleMessage(message);
assertEquals("Test1", new ObjectInputStream(socket1.getInputStream()).readObject());
assertEquals("Test2", new ObjectInputStream(socket2.getInputStream()).readObject());
}

View File

@@ -51,7 +51,6 @@ import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.ip.IpHeaders;
import org.springframework.integration.ip.tcp.connection.AbstractConnectionFactory;
import org.springframework.integration.ip.tcp.connection.HelloWorldInterceptorFactory;
import org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorFactory;
@@ -80,7 +79,7 @@ public class TcpSendingMessageHandlerTests {
buff[i] = (byte) is.read();
}
}
@Test
public void testNetCrLf() throws Exception {
final int port = SocketTestUtils.findAvailableServerSocket();
@@ -111,7 +110,7 @@ public class TcpSendingMessageHandlerTests {
ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer();
ccf.setSerializer(serializer);
ccf.setDeserializer(serializer);
ccf.setSoTimeout(10000);
ccf.setSoTimeout(10000);
ccf.start();
TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
handler.setConnectionFactory(ccf);
@@ -119,7 +118,7 @@ public class TcpSendingMessageHandlerTests {
adapter.setConnectionFactory(ccf);
QueueChannel channel = new QueueChannel();
adapter.setOutputChannel(channel);
assertTrue(latch.await(10, TimeUnit.SECONDS));
assertTrue(latch.await(10, TimeUnit.SECONDS));
handler.handleMessage(MessageBuilder.withPayload("Test").build());
handler.handleMessage(MessageBuilder.withPayload("Test").build());
Message<?> mOut = channel.receive(10000);
@@ -239,7 +238,7 @@ public class TcpSendingMessageHandlerTests {
assertTrue(results.remove("Reply2"));
done.set(true);
}
@Test
public void testNetStxEtx() throws Exception {
final int port = SocketTestUtils.findAvailableServerSocket();
@@ -277,7 +276,7 @@ public class TcpSendingMessageHandlerTests {
adapter.setConnectionFactory(ccf);
QueueChannel channel = new QueueChannel();
adapter.setOutputChannel(channel);
assertTrue(latch.await(10, TimeUnit.SECONDS));
assertTrue(latch.await(10, TimeUnit.SECONDS));
handler.handleMessage(MessageBuilder.withPayload("Test").build());
handler.handleMessage(MessageBuilder.withPayload("Test").build());
Message<?> mOut = channel.receive(10000);
@@ -381,7 +380,7 @@ public class TcpSendingMessageHandlerTests {
adapter.setConnectionFactory(ccf);
QueueChannel channel = new QueueChannel();
adapter.setOutputChannel(channel);
assertTrue(latch.await(10, TimeUnit.SECONDS));
assertTrue(latch.await(10, TimeUnit.SECONDS));
handler.handleMessage(MessageBuilder.withPayload("Test").build());
handler.handleMessage(MessageBuilder.withPayload("Test").build());
Message<?> mOut = channel.receive(10000);
@@ -484,7 +483,7 @@ public class TcpSendingMessageHandlerTests {
adapter.setConnectionFactory(ccf);
QueueChannel channel = new QueueChannel();
adapter.setOutputChannel(channel);
assertTrue(latch.await(10, TimeUnit.SECONDS));
assertTrue(latch.await(10, TimeUnit.SECONDS));
handler.handleMessage(MessageBuilder.withPayload("Test").build());
handler.handleMessage(MessageBuilder.withPayload("Test").build());
Message<?> mOut = channel.receive(10000);
@@ -679,7 +678,7 @@ public class TcpSendingMessageHandlerTests {
assertTrue(latch.await(10, TimeUnit.SECONDS));
handler.handleMessage(MessageBuilder.withPayload("Test").build());
handler.handleMessage(MessageBuilder.withPayload("Test").build());
assertTrue(semaphore.tryAcquire(2, 10000, TimeUnit.MILLISECONDS));
assertTrue(semaphore.tryAcquire(2, 10000, TimeUnit.MILLISECONDS));
Set<String> replies = new HashSet<String>();
for (int i = 0; i < 2; i++) {
Message<?> mOut = channel.receive(10000);
@@ -736,7 +735,7 @@ public class TcpSendingMessageHandlerTests {
assertTrue(latch.await(10, TimeUnit.SECONDS));
handler.handleMessage(MessageBuilder.withPayload("Test").build());
handler.handleMessage(MessageBuilder.withPayload("Test").build());
assertTrue(semaphore.tryAcquire(2, 10000, TimeUnit.MILLISECONDS));
assertTrue(semaphore.tryAcquire(2, 10000, TimeUnit.MILLISECONDS));
Set<String> replies = new HashSet<String>();
for (int i = 0; i < 2; i++) {
Message<?> mOut = channel.receive(10000);
@@ -859,9 +858,9 @@ public class TcpSendingMessageHandlerTests {
AbstractConnectionFactory ccf = new TcpNetClientConnectionFactory("localhost", port);
ccf.setSerializer(new DefaultSerializer());
ccf.setDeserializer(new DefaultDeserializer());
ccf.setSoTimeout(10000);
ccf.setSoTimeout(10000);
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
{new HelloWorldInterceptorFactory(),
new HelloWorldInterceptorFactory()});
ccf.setInterceptorFactoryChain(fc);
@@ -872,7 +871,7 @@ public class TcpSendingMessageHandlerTests {
adapter.setConnectionFactory(ccf);
QueueChannel channel = new QueueChannel();
adapter.setOutputChannel(channel);
assertTrue(latch.await(10, TimeUnit.SECONDS));
assertTrue(latch.await(10, TimeUnit.SECONDS));
handler.handleMessage(MessageBuilder.withPayload("Test").build());
handler.handleMessage(MessageBuilder.withPayload("Test").build());
Message<?> mOut = channel.receive(10000);
@@ -921,7 +920,7 @@ public class TcpSendingMessageHandlerTests {
AbstractConnectionFactory ccf = new TcpNioClientConnectionFactory("localhost", port);
ccf.setSerializer(new DefaultSerializer());
ccf.setDeserializer(new DefaultDeserializer());
ccf.setSoTimeout(10000);
ccf.setSoTimeout(10000);
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
fc.setInterceptors(new TcpConnectionInterceptorFactory[] {new HelloWorldInterceptorFactory()});
ccf.setInterceptorFactoryChain(fc);
@@ -932,7 +931,7 @@ public class TcpSendingMessageHandlerTests {
adapter.setConnectionFactory(ccf);
QueueChannel channel = new QueueChannel();
adapter.setOutputChannel(channel);
assertTrue(latch.await(10, TimeUnit.SECONDS));
assertTrue(latch.await(10, TimeUnit.SECONDS));
for (int i = 0; i < 1000; i++) {
handler.handleMessage(MessageBuilder.withPayload("Test").build());
}
@@ -991,9 +990,9 @@ public class TcpSendingMessageHandlerTests {
AbstractConnectionFactory ccf = new TcpNetClientConnectionFactory("localhost", port);
ccf.setSerializer(new DefaultSerializer());
ccf.setDeserializer(new DefaultDeserializer());
ccf.setSoTimeout(10000);
ccf.setSoTimeout(10000);
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
{new HelloWorldInterceptorFactory(),
new HelloWorldInterceptorFactory()});
ccf.setInterceptorFactoryChain(fc);
@@ -1001,7 +1000,7 @@ public class TcpSendingMessageHandlerTests {
ccf.start();
TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
handler.setConnectionFactory(ccf);
assertTrue(latch.await(10, TimeUnit.SECONDS));
assertTrue(latch.await(10, TimeUnit.SECONDS));
handler.handleMessage(MessageBuilder.withPayload("Test").build());
done.set(true);
}
@@ -1047,9 +1046,9 @@ public class TcpSendingMessageHandlerTests {
AbstractConnectionFactory ccf = new TcpNioClientConnectionFactory("localhost", port);
ccf.setSerializer(new DefaultSerializer());
ccf.setDeserializer(new DefaultDeserializer());
ccf.setSoTimeout(10000);
ccf.setSoTimeout(10000);
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
{new HelloWorldInterceptorFactory(),
new HelloWorldInterceptorFactory()});
ccf.setInterceptorFactoryChain(fc);
@@ -1057,7 +1056,7 @@ public class TcpSendingMessageHandlerTests {
ccf.start();
TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
handler.setConnectionFactory(ccf);
assertTrue(latch.await(10, TimeUnit.SECONDS));
assertTrue(latch.await(10, TimeUnit.SECONDS));
handler.handleMessage(MessageBuilder.withPayload("Test").build());
done.set(true);
}

View File

@@ -32,7 +32,6 @@ import java.util.concurrent.TimeUnit;
import javax.net.SocketFactory;
import org.junit.Test;
import org.springframework.integration.Message;
import org.springframework.integration.ip.tcp.serializer.AbstractByteArraySerializer;
import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer;
@@ -47,12 +46,12 @@ import org.springframework.integration.ip.util.SocketTestUtils;
public class TcpNioConnectionReadTests {
private CountDownLatch latch = new CountDownLatch(1);
private AbstractServerConnectionFactory getConnectionFactory(int port,
AbstractByteArraySerializer serializer, TcpListener listener) throws Exception {
return getConnectionFactory(port, serializer, listener, null);
}
private AbstractServerConnectionFactory getConnectionFactory(int port,
AbstractByteArraySerializer serializer, TcpListener listener, TcpSender sender) throws Exception {
AbstractServerConnectionFactory scf = new TcpNioServerConnectionFactory(port);
@@ -72,7 +71,7 @@ public class TcpNioConnectionReadTests {
}
return scf;
}
/**
* Test method for {@link org.springframework.integration.ip.tcp.NioSocketReader}.
*/
@@ -90,17 +89,17 @@ public class TcpNioConnectionReadTests {
return false;
}
});
// Fire up the sender.
SocketTestUtils.testSendLength(port, latch);
latch.countDown();
assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS));
assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS));
assertEquals("Did not receive data", 2, responses.size());
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
new String(((Message<byte[]>) responses.get(0)).getPayload()));
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
new String(((Message<byte[]>) responses.get(1)).getPayload()));
scf.close();
}
@@ -124,20 +123,20 @@ public class TcpNioConnectionReadTests {
return false;
}
});
int howMany = 2;
scf.setPoolSize(howMany + 5);
scf.setBacklog(howMany + 5);
// Fire up the sender.
SocketTestUtils.testSendFragmented(port, howMany, false);
assertTrue(semaphore.tryAcquire(howMany, 20000, TimeUnit.MILLISECONDS));
assertEquals("Expected", howMany, responses.size());
for (int i = 0; i < howMany; i++) {
assertEquals("Data", "xx",
assertEquals("Data", "xx",
new String(((Message<byte[]>) responses.get(0)).getPayload()));
}
scf.close();
}
/**
* Test method for {@link org.springframework.integration.ip.tcp.NioSocketReader}.
*/
@@ -155,17 +154,17 @@ public class TcpNioConnectionReadTests {
return false;
}
});
// Fire up the sender.
SocketTestUtils.testSendStxEtx(port, latch);
latch.countDown();
assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS));
assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS));
assertEquals("Did not receive data", 2, responses.size());
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
new String(((Message<byte[]>) responses.get(0)).getPayload()));
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
new String(((Message<byte[]>) responses.get(1)).getPayload()));
scf.close();
}
@@ -187,17 +186,17 @@ public class TcpNioConnectionReadTests {
return false;
}
});
// Fire up the sender.
SocketTestUtils.testSendCrLf(port, latch);
latch.countDown();
assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS));
assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS));
assertEquals("Did not receive data", 2, responses.size());
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
new String(((Message<byte[]>) responses.get(0)).getPayload()));
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
new String(((Message<byte[]>) responses.get(1)).getPayload()));
scf.close();
}
@@ -229,9 +228,9 @@ public class TcpNioConnectionReadTests {
semaphore.release();
}
});
// Fire up the sender.
SocketTestUtils.testSendLengthOverflow(port);
whileOpen(semaphore, added);
assertEquals(1, added.size());
@@ -268,9 +267,9 @@ public class TcpNioConnectionReadTests {
semaphore.release();
}
});
// Fire up the sender.
SocketTestUtils.testSendStxEtxOverflow(port);
whileOpen(semaphore, added);
assertEquals(1, added.size());
@@ -307,9 +306,9 @@ public class TcpNioConnectionReadTests {
semaphore.release();
}
});
// Fire up the sender.
SocketTestUtils.testSendCrLfOverflow(port);
whileOpen(semaphore, added);
assertEquals(1, added.size());
@@ -320,7 +319,7 @@ public class TcpNioConnectionReadTests {
/**
* Tests socket closure when no data received.
*
*
* @throws Exception
*/
@Test
@@ -359,7 +358,7 @@ public class TcpNioConnectionReadTests {
/**
* Tests socket closure when no data received.
*
*
* @throws Exception
*/
@Test
@@ -399,7 +398,7 @@ public class TcpNioConnectionReadTests {
/**
* Tests socket closure when mid-message
*
*
* @throws Exception
*/
@Test
@@ -407,10 +406,10 @@ public class TcpNioConnectionReadTests {
ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer();
testClosureMidMessageGuts(serializer, "xx");
}
/**
* Tests socket closure when mid-message
*
*
* @throws Exception
*/
@@ -422,7 +421,7 @@ public class TcpNioConnectionReadTests {
/**
* Tests socket closure when mid-message
*
*
* @throws Exception
*/

View File

@@ -19,15 +19,19 @@ package org.springframework.integration.ip.tcp.connection;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
@@ -36,19 +40,30 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.net.ServerSocketFactory;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.integration.Message;
import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer;
import org.springframework.integration.ip.util.SocketTestUtils;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;
import org.springframework.util.ReflectionUtils.FieldFilter;
import org.springframework.util.ReflectionUtils.MethodCallback;
import org.springframework.util.ReflectionUtils.MethodFilter;
/**
@@ -84,7 +99,7 @@ public class TcpNioConnectionTests {
TcpConnection connection = factory.getConnection();
connection.send(MessageBuilder.withPayload(new byte[1000000]).build());
} catch (Exception e) {
assertTrue("Expected SocketTimeoutException, got " + e.getClass().getSimpleName() +
assertTrue("Expected SocketTimeoutException, got " + e.getClass().getSimpleName() +
":" + e.getMessage(), e instanceof SocketTimeoutException);
}
}
@@ -102,7 +117,7 @@ public class TcpNioConnectionTests {
ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port);
latch.countDown();
Socket socket = server.accept();
byte[] b = new byte[6];
byte[] b = new byte[6];
readFully(socket.getInputStream(), b);
// block to cause timeout on read.
server.accept();
@@ -127,7 +142,7 @@ public class TcpNioConnectionTests {
fail("Unexpected exception " + e);
}
}
@Test
public void testMemoryLeak() throws Exception {
final int port = SocketTestUtils.findAvailableServerSocket();
@@ -234,10 +249,108 @@ public class TcpNioConnectionTests {
assertEquals(0, TestUtils.getPropertyValue(factory, "connections", List.class).size());
}
@Test
public void testInsufficientThreads() throws Exception {
final ExecutorService exec = Executors.newFixedThreadPool(2);
Future<Object> future = exec.submit(new Callable<Object>() {
public Object call() throws Exception {
SocketChannel channel = mock(SocketChannel.class);
Socket socket = mock(Socket.class);
Mockito.when(channel.socket()).thenReturn(socket);
doAnswer(new Answer<Integer>() {
public Integer answer(InvocationOnMock invocation) throws Throwable {
ByteBuffer buffer = (ByteBuffer) invocation.getArguments()[0];
buffer.position(1025);
return 1025;
}
}).when(channel).read(Mockito.any(ByteBuffer.class));
final TcpNioConnection connection = new TcpNioConnection(channel, false, false);
connection.setTaskExecutor(exec);
connection.setPipeTimeout(200);
ReflectionUtils.doWithMethods(TcpNioConnection.class, new MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
method.setAccessible(true);
try {
method.invoke(connection, (Object[]) null);
}
catch (InvocationTargetException e) {
throw (RuntimeException) e.getCause();
}
}
}, new MethodFilter() {
public boolean matches(Method method) {
return method.getName().equals("doRead");
}
});
return null;
}
});
try {
Object o = future.get(10, TimeUnit.SECONDS);
fail("Expected exception, got " + o);
}
catch (ExecutionException e) {
assertEquals("Timed out writing to pipe, probably due to insufficient threads in " +
"a fixed thread pool; consider increasing this task executor pool size", e.getCause()
.getMessage());
}
}
@Test
public void testSufficientThreads() throws Exception {
final ExecutorService exec = Executors.newFixedThreadPool(3);
final CountDownLatch messageLatch = new CountDownLatch(1);
Future<Object> future = exec.submit(new Callable<Object>() {
public Object call() throws Exception {
SocketChannel channel = mock(SocketChannel.class);
Socket socket = mock(Socket.class);
Mockito.when(channel.socket()).thenReturn(socket);
doAnswer(new Answer<Integer>() {
public Integer answer(InvocationOnMock invocation) throws Throwable {
ByteBuffer buffer = (ByteBuffer) invocation.getArguments()[0];
buffer.position(1025);
buffer.put((byte) '\r');
buffer.put((byte) '\n');
return 1027;
}
}).when(channel).read(Mockito.any(ByteBuffer.class));
final TcpNioConnection connection = new TcpNioConnection(channel, false, false);
connection.setTaskExecutor(exec);
connection.registerListener(new TcpListener(){
public boolean onMessage(Message<?> message) {
System.out.println(message);
messageLatch.countDown();
return false;
}
});
connection.setMapper(new TcpMessageMapper());
connection.setDeserializer(new ByteArrayCrLfSerializer());
ReflectionUtils.doWithMethods(TcpNioConnection.class, new MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
method.setAccessible(true);
try {
method.invoke(connection, (Object[]) null);
}
catch (InvocationTargetException e) {
throw (RuntimeException) e.getCause();
}
}
}, new MethodFilter() {
public boolean matches(Method method) {
return method.getName().equals("doRead");
}
});
return null;
}
});
future.get(60, TimeUnit.SECONDS);
assertTrue(messageLatch.await(10, TimeUnit.SECONDS));
}
private void readFully(InputStream is, byte[] buff) throws IOException {
for (int i = 0; i < buff.length; i++) {
buff[i] = (byte) is.read();
}
}
}