use of java.util.concurrent.Exchanger in project jetty.project by eclipse.
the class FlowControlStrategyTest method testServerFlowControlOneBigWrite.
@Test
public void testServerFlowControlOneBigWrite() throws Exception {
final int windowSize = 1536;
final int length = 5 * windowSize;
final CountDownLatch settingsLatch = new CountDownLatch(1);
start(new ServerSessionListener.Adapter() {
@Override
public void onSettings(Session session, SettingsFrame frame) {
settingsLatch.countDown();
}
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) {
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false);
CompletableFuture<Void> completable = new CompletableFuture<>();
stream.headers(responseFrame, Callback.from(completable));
completable.thenRun(() -> {
DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(length), true);
stream.data(dataFrame, Callback.NOOP);
});
return null;
}
});
Session session = newClient(new Session.Listener.Adapter());
Map<Integer, Integer> settings = new HashMap<>();
settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, windowSize);
session.settings(new SettingsFrame(settings, false), Callback.NOOP);
Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
final CountDownLatch dataLatch = new CountDownLatch(1);
final Exchanger<Callback> exchanger = new Exchanger<>();
MetaData.Request metaData = newRequest("GET", new HttpFields());
HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
session.newStream(requestFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter() {
private AtomicInteger dataFrames = new AtomicInteger();
@Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
try {
int dataFrames = this.dataFrames.incrementAndGet();
if (dataFrames == 1 || dataFrames == 2) {
// Do not consume the data frame.
// We should then be flow-control stalled.
exchanger.exchange(callback);
} else if (dataFrames == 3 || dataFrames == 4 || dataFrames == 5) {
// Consume totally.
callback.succeeded();
if (frame.isEndStream())
dataLatch.countDown();
} else {
Assert.fail();
}
} catch (InterruptedException x) {
callback.failed(x);
}
}
});
Callback callback = exchanger.exchange(null, 5, TimeUnit.SECONDS);
checkThatWeAreFlowControlStalled(exchanger);
// Consume the first chunk.
callback.succeeded();
callback = exchanger.exchange(null, 5, TimeUnit.SECONDS);
checkThatWeAreFlowControlStalled(exchanger);
// Consume the second chunk.
callback.succeeded();
Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
}
use of java.util.concurrent.Exchanger in project jetty.project by eclipse.
the class FlowControlStrategyTest method testClientFlowControlOneBigWrite.
@Test
public void testClientFlowControlOneBigWrite() throws Exception {
final int windowSize = 1536;
final Exchanger<Callback> exchanger = new Exchanger<>();
final CountDownLatch settingsLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(1);
start(new ServerSessionListener.Adapter() {
@Override
public Map<Integer, Integer> onPreface(Session session) {
Map<Integer, Integer> settings = new HashMap<>();
settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, windowSize);
return settings;
}
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) {
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
stream.headers(responseFrame, Callback.NOOP);
return new Stream.Listener.Adapter() {
private AtomicInteger dataFrames = new AtomicInteger();
@Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
try {
int dataFrames = this.dataFrames.incrementAndGet();
if (dataFrames == 1 || dataFrames == 2) {
// Do not consume the data frame.
// We should then be flow-control stalled.
exchanger.exchange(callback);
} else if (dataFrames == 3 || dataFrames == 4 || dataFrames == 5) {
// Consume totally.
callback.succeeded();
if (frame.isEndStream())
dataLatch.countDown();
} else {
Assert.fail();
}
} catch (InterruptedException x) {
callback.failed(x);
}
}
};
}
});
Session session = newClient(new Session.Listener.Adapter() {
@Override
public void onSettings(Session session, SettingsFrame frame) {
settingsLatch.countDown();
}
});
Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
MetaData.Request metaData = newRequest("GET", new HttpFields());
HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
FuturePromise<Stream> streamPromise = new FuturePromise<>();
session.newStream(requestFrame, streamPromise, null);
Stream stream = streamPromise.get(5, TimeUnit.SECONDS);
final int length = 5 * windowSize;
DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(length), true);
stream.data(dataFrame, Callback.NOOP);
Callback callback = exchanger.exchange(null, 5, TimeUnit.SECONDS);
checkThatWeAreFlowControlStalled(exchanger);
// Consume the first chunk.
callback.succeeded();
callback = exchanger.exchange(null, 5, TimeUnit.SECONDS);
checkThatWeAreFlowControlStalled(exchanger);
// Consume the second chunk.
callback.succeeded();
Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
}
use of java.util.concurrent.Exchanger in project jetty.project by eclipse.
the class ConnectorTimeoutTest method testMaxIdleWithRequest10NoClientClose.
@Test(timeout = 60000)
public void testMaxIdleWithRequest10NoClientClose() throws Exception {
final Exchanger<EndPoint> exchanger = new Exchanger<>();
configureServer(new HelloWorldHandler() {
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
try {
exchanger.exchange(baseRequest.getHttpChannel().getEndPoint());
} catch (Exception e) {
e.printStackTrace();
}
super.handle(target, baseRequest, request, response);
}
});
Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort());
client.setSoTimeout(10000);
Assert.assertFalse(client.isClosed());
OutputStream os = client.getOutputStream();
InputStream is = client.getInputStream();
os.write(("GET / HTTP/1.0\r\n" + "host: " + _serverURI.getHost() + ":" + _serverURI.getPort() + "\r\n" + "connection: close\r\n" + "\r\n").getBytes("utf-8"));
os.flush();
// Get the server side endpoint
EndPoint endPoint = exchanger.exchange(null, 10, TimeUnit.SECONDS);
if (endPoint instanceof SslConnection.DecryptedEndPoint)
endPoint = endPoint.getConnection().getEndPoint();
// read the response
String result = IO.toString(is);
Assert.assertThat("OK", result, Matchers.containsString("200 OK"));
// check client reads EOF
Assert.assertEquals(-1, is.read());
// wait for idle timeout
TimeUnit.MILLISECONDS.sleep(3 * MAX_IDLE_TIME);
// further writes will get broken pipe or similar
try {
for (int i = 0; i < 1000; i++) {
os.write(("GET / HTTP/1.0\r\n" + "host: " + _serverURI.getHost() + ":" + _serverURI.getPort() + "\r\n" + "connection: keep-alive\r\n" + "\r\n").getBytes("utf-8"));
os.flush();
}
Assert.fail("half close should have timed out");
} catch (SocketException e) {
// expected
}
// check the server side is closed
Assert.assertFalse(endPoint.isOpen());
}
use of java.util.concurrent.Exchanger in project jetty.project by eclipse.
the class ThreadStarvationTest method testDefaultServletSuccess.
@Test
@Slow
public void testDefaultServletSuccess() throws Exception {
int maxThreads = 10;
QueuedThreadPool threadPool = new QueuedThreadPool(maxThreads, maxThreads);
threadPool.setDetailedDump(true);
_server = new Server(threadPool);
// Prepare a big file to download.
File directory = MavenTestingUtils.getTargetTestingDir();
Files.createDirectories(directory.toPath());
String resourceName = "resource.bin";
Path resourcePath = Paths.get(directory.getPath(), resourceName);
try (OutputStream output = Files.newOutputStream(resourcePath, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
byte[] chunk = new byte[1024];
Arrays.fill(chunk, (byte) 'X');
chunk[chunk.length - 2] = '\r';
chunk[chunk.length - 1] = '\n';
for (int i = 0; i < 256 * 1024; ++i) output.write(chunk);
}
final CountDownLatch writePending = new CountDownLatch(1);
ServerConnector connector = new ServerConnector(_server, 0, 1) {
@Override
protected ChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException {
return new SocketChannelEndPoint(channel, selectSet, key, getScheduler()) {
@Override
protected void onIncompleteFlush() {
super.onIncompleteFlush();
writePending.countDown();
}
};
}
};
connector.setIdleTimeout(Long.MAX_VALUE);
_server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler(_server, "/");
context.setResourceBase(directory.toURI().toString());
context.addServlet(DefaultServlet.class, "/*").setAsyncSupported(false);
_server.setHandler(context);
_server.start();
List<Socket> sockets = new ArrayList<>();
for (int i = 0; i < maxThreads * 2; ++i) {
Socket socket = new Socket("localhost", connector.getLocalPort());
sockets.add(socket);
OutputStream output = socket.getOutputStream();
String request = "" + "GET /" + resourceName + " HTTP/1.1\r\n" + "Host: localhost\r\n" + "\r\n";
output.write(request.getBytes(StandardCharsets.UTF_8));
output.flush();
Thread.sleep(100);
}
// Wait for a the servlet to block.
Assert.assertTrue(writePending.await(5, TimeUnit.SECONDS));
long expected = Files.size(resourcePath);
byte[] buffer = new byte[48 * 1024];
List<Exchanger<Long>> totals = new ArrayList<>();
for (Socket socket : sockets) {
final Exchanger<Long> x = new Exchanger<>();
totals.add(x);
final InputStream input = socket.getInputStream();
new Thread() {
@Override
public void run() {
long total = 0;
try {
// look for CRLFCRLF
StringBuilder header = new StringBuilder();
int state = 0;
while (state < 4 && header.length() < 2048) {
int ch = input.read();
if (ch < 0)
break;
header.append((char) ch);
switch(state) {
case 0:
if (ch == '\r')
state = 1;
break;
case 1:
if (ch == '\n')
state = 2;
else
state = 0;
break;
case 2:
if (ch == '\r')
state = 3;
else
state = 0;
break;
case 3:
if (ch == '\n')
state = 4;
else
state = 0;
break;
}
}
while (total < expected) {
int read = input.read(buffer);
if (read < 0)
break;
total += read;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
x.exchange(total);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
for (Exchanger<Long> x : totals) {
Long total = x.exchange(-1L, 10000, TimeUnit.SECONDS);
Assert.assertEquals(expected, total.longValue());
}
// We could read everything, good.
for (Socket socket : sockets) socket.close();
}
use of java.util.concurrent.Exchanger in project camel by apache.
the class InOutProducer method sendMessage.
/**
* TODO time out is actually double as it waits for the producer and then
* waits for the response. Use an atomic long to manage the countdown
*/
@Override
public void sendMessage(final Exchange exchange, final AsyncCallback callback, final MessageProducerResources producer, final ReleaseProducerCallback releaseProducerCallback) throws Exception {
Message request = getEndpoint().getBinding().makeJmsMessage(exchange, producer.getSession());
String correlationId = exchange.getIn().getHeader(JmsConstants.JMS_CORRELATION_ID, String.class);
if (correlationId == null) {
// we append the 'Camel-' prefix to know it was generated by us
correlationId = GENERATED_CORRELATION_ID_PREFIX + getUuidGenerator().generateUuid();
}
Object responseObject = null;
Exchanger<Object> messageExchanger = new Exchanger<Object>();
JmsMessageHelper.setCorrelationId(request, correlationId);
EXCHANGERS.put(correlationId, messageExchanger);
MessageConsumerResources consumer = consumers.borrowObject();
JmsMessageHelper.setJMSReplyTo(request, consumer.getReplyToDestination());
consumers.returnObject(consumer);
producer.getMessageProducer().send(request);
// without waiting on us to complete the exchange
try {
releaseProducerCallback.release(producer);
} catch (Exception exception) {
// thrown if the pool is full. safe to ignore.
}
try {
responseObject = messageExchanger.exchange(null, getResponseTimeOut(), TimeUnit.MILLISECONDS);
EXCHANGERS.remove(correlationId);
} catch (InterruptedException e) {
log.debug("Exchanger was interrupted while waiting on response", e);
exchange.setException(e);
} catch (TimeoutException e) {
log.debug("Exchanger timed out while waiting on response", e);
exchange.setException(e);
}
if (exchange.getException() == null) {
if (responseObject instanceof Throwable) {
exchange.setException((Throwable) responseObject);
} else if (responseObject instanceof Message) {
Message message = (Message) responseObject;
SjmsMessage response = new SjmsMessage(message, consumer.getSession(), getEndpoint().getBinding());
// the JmsBinding is designed to be "pull-based": it will populate the Camel message on demand
// therefore, we link Exchange and OUT message before continuing, so that the JmsBinding has full access
// to everything it may need, and can populate headers, properties, etc. accordingly (solves CAMEL-6218).
exchange.setOut(response);
} else {
exchange.setException(new CamelException("Unknown response type: " + responseObject));
}
}
callback.done(isSynchronous());
}
Aggregations