484818 - Expose interesting HTTP/2 attributes and operations via JMX.

Initial work to expose already existing attributes on the client.
This commit is contained in:
Simone Bordet 2015-12-23 11:02:03 +01:00
parent b7ab9e0a22
commit 14a3b2eab2
3 changed files with 91 additions and 2 deletions

View File

@ -29,6 +29,7 @@ import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory; import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory;
import org.eclipse.jetty.http2.FlowControlStrategy;
import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.ClientConnectionFactory;
@ -40,6 +41,8 @@ import org.eclipse.jetty.io.SelectChannelEndPoint;
import org.eclipse.jetty.io.SelectorManager; import org.eclipse.jetty.io.SelectorManager;
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.QueuedThreadPool;
@ -106,6 +109,7 @@ import org.eclipse.jetty.util.thread.Scheduler;
* client.stop(); * client.stop();
* </pre> * </pre>
*/ */
@ManagedObject
public class HTTP2Client extends ContainerLifeCycle public class HTTP2Client extends ContainerLifeCycle
{ {
private Executor executor; private Executor executor;
@ -116,7 +120,10 @@ public class HTTP2Client extends ContainerLifeCycle
private int selectors = 1; private int selectors = 1;
private long idleTimeout = 30000; private long idleTimeout = 30000;
private long connectTimeout = 10000; private long connectTimeout = 10000;
private int inputBufferSize = 8192;
private List<String> protocols = Arrays.asList("h2", "h2-17", "h2-16", "h2-15", "h2-14"); private List<String> protocols = Arrays.asList("h2", "h2-17", "h2-16", "h2-15", "h2-14");
private int initialSessionRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
private int initialStreamRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
@Override @Override
protected void doStart() throws Exception protected void doStart() throws Exception
@ -203,6 +210,7 @@ public class HTTP2Client extends ContainerLifeCycle
this.connectionFactory = connectionFactory; this.connectionFactory = connectionFactory;
} }
@ManagedAttribute("The number of selectors")
public int getSelectors() public int getSelectors()
{ {
return selectors; return selectors;
@ -213,6 +221,7 @@ public class HTTP2Client extends ContainerLifeCycle
this.selectors = selectors; this.selectors = selectors;
} }
@ManagedAttribute("The idle timeout in milliseconds")
public long getIdleTimeout() public long getIdleTimeout()
{ {
return idleTimeout; return idleTimeout;
@ -223,6 +232,7 @@ public class HTTP2Client extends ContainerLifeCycle
this.idleTimeout = idleTimeout; this.idleTimeout = idleTimeout;
} }
@ManagedAttribute("The connect timeout in milliseconds")
public long getConnectTimeout() public long getConnectTimeout()
{ {
return connectTimeout; return connectTimeout;
@ -236,6 +246,18 @@ public class HTTP2Client extends ContainerLifeCycle
selector.setConnectTimeout(connectTimeout); selector.setConnectTimeout(connectTimeout);
} }
@ManagedAttribute("The size of the buffer used to read from the network")
public int getInputBufferSize()
{
return inputBufferSize;
}
public void setInputBufferSize(int inputBufferSize)
{
this.inputBufferSize = inputBufferSize;
}
@ManagedAttribute("The ALPN protocol list")
public List<String> getProtocols() public List<String> getProtocols()
{ {
return protocols; return protocols;
@ -246,6 +268,28 @@ public class HTTP2Client extends ContainerLifeCycle
this.protocols = protocols; this.protocols = protocols;
} }
@ManagedAttribute("The initial size of session's flow control receive window")
public int getInitialSessionRecvWindow()
{
return initialSessionRecvWindow;
}
public void setInitialSessionRecvWindow(int initialSessionRecvWindow)
{
this.initialSessionRecvWindow = initialSessionRecvWindow;
}
@ManagedAttribute("The initial size of stream's flow control receive window")
public int getInitialStreamRecvWindow()
{
return initialStreamRecvWindow;
}
public void setInitialStreamRecvWindow(int initialStreamRecvWindow)
{
this.initialStreamRecvWindow = initialStreamRecvWindow;
}
public void connect(InetSocketAddress address, Session.Listener listener, Promise<Session> promise) public void connect(InetSocketAddress address, Session.Listener listener, Promise<Session> promise)
{ {
connect(null, address, listener, promise); connect(null, address, listener, promise);

View File

@ -39,6 +39,7 @@ import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.thread.Scheduler; import org.eclipse.jetty.util.thread.Scheduler;
public class HTTP2ClientConnectionFactory implements ClientConnectionFactory public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
@ -50,6 +51,7 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
public static final String SESSION_LISTENER_CONTEXT_KEY = "http2.client.sessionListener"; public static final String SESSION_LISTENER_CONTEXT_KEY = "http2.client.sessionListener";
public static final String SESSION_PROMISE_CONTEXT_KEY = "http2.client.sessionPromise"; public static final String SESSION_PROMISE_CONTEXT_KEY = "http2.client.sessionPromise";
private final Connection.Listener connectionListener = new ConnectionListener();
private int initialSessionRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE; private int initialSessionRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
@Override @Override
@ -67,7 +69,9 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
FlowControlStrategy flowControl = newFlowControlStrategy(); FlowControlStrategy flowControl = newFlowControlStrategy();
HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, flowControl); HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, flowControl);
Parser parser = new Parser(byteBufferPool, session, 4096, 8192); Parser parser = new Parser(byteBufferPool, session, 4096, 8192);
return new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, parser, session, 8192, promise, listener); HTTP2ClientConnection connection = new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, parser, session, client.getInputBufferSize(), promise, listener);
connection.addListener(connectionListener);
return connection;
} }
protected FlowControlStrategy newFlowControlStrategy() protected FlowControlStrategy newFlowControlStrategy()
@ -75,11 +79,19 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
return new BufferingFlowControlStrategy(0.5F); return new BufferingFlowControlStrategy(0.5F);
} }
/**
* @deprecated use {@link HTTP2Client#getInitialSessionRecvWindow()} instead
*/
@Deprecated
public int getInitialSessionRecvWindow() public int getInitialSessionRecvWindow()
{ {
return initialSessionRecvWindow; return initialSessionRecvWindow;
} }
/**
* @deprecated use {@link HTTP2Client#setInitialSessionRecvWindow(int)} instead
*/
@Deprecated
public void setInitialSessionRecvWindow(int initialSessionRecvWindow) public void setInitialSessionRecvWindow(int initialSessionRecvWindow)
{ {
this.initialSessionRecvWindow = initialSessionRecvWindow; this.initialSessionRecvWindow = initialSessionRecvWindow;
@ -108,8 +120,14 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
PrefaceFrame prefaceFrame = new PrefaceFrame(); PrefaceFrame prefaceFrame = new PrefaceFrame();
SettingsFrame settingsFrame = new SettingsFrame(settings, false); SettingsFrame settingsFrame = new SettingsFrame(settings, false);
ISession session = getSession(); ISession session = getSession();
int windowDelta = getInitialSessionRecvWindow() - FlowControlStrategy.DEFAULT_WINDOW_SIZE;
int sessionRecv = client.getInitialSessionRecvWindow();
if (sessionRecv == FlowControlStrategy.DEFAULT_WINDOW_SIZE)
sessionRecv = initialSessionRecvWindow;
int windowDelta = sessionRecv - FlowControlStrategy.DEFAULT_WINDOW_SIZE;
if (windowDelta > 0) if (windowDelta > 0)
{ {
session.updateRecvWindow(windowDelta); session.updateRecvWindow(windowDelta);
@ -138,4 +156,21 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
promise.failed(x); promise.failed(x);
} }
} }
private class ConnectionListener implements Connection.Listener
{
@Override
public void onOpened(Connection connection)
{
HTTP2ClientConnection http2Connection = (HTTP2ClientConnection)connection;
http2Connection.client.addManaged((LifeCycle)http2Connection.getSession());
}
@Override
public void onClosed(Connection connection)
{
HTTP2ClientConnection http2Connection = (HTTP2ClientConnection)connection;
http2Connection.client.removeBean(http2Connection.getSession());
}
}
} }

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.client.http;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory; import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory;
@ -71,6 +72,7 @@ public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements
client.setByteBufferPool(httpClient.getByteBufferPool()); client.setByteBufferPool(httpClient.getByteBufferPool());
client.setConnectTimeout(httpClient.getConnectTimeout()); client.setConnectTimeout(httpClient.getConnectTimeout());
client.setIdleTimeout(httpClient.getIdleTimeout()); client.setIdleTimeout(httpClient.getIdleTimeout());
client.setInputBufferSize(httpClient.getResponseBufferSize());
} }
addBean(client); addBean(client);
super.doStart(); super.doStart();
@ -160,6 +162,14 @@ public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements
promise.failed(failure); promise.failed(failure);
} }
@Override
public Map<Integer, Integer> onPreface(Session session)
{
Map<Integer, Integer> settings = new HashMap<>();
settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, client.getInitialStreamRecvWindow());
return settings;
}
@Override @Override
public void onSettings(Session session, SettingsFrame frame) public void onSettings(Session session, SettingsFrame frame)
{ {