Fixes #2828 - AbstractHTTP2ServerConnectionFactory concurrent connect low performance.

Now HTTP/2 sessions are not added to the Jetty component tree,
but rather just held by HTTP2SessionContainer that is added to
the Jetty container tree at startup.

HTTP2SessionContainer uses a concurrent Set to hold HTTP/2 sessions
to have good add/remove performance.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2018-08-19 14:54:14 +02:00
parent ddd80deeb9
commit d3e75c5936
1 changed files with 37 additions and 5 deletions

View File

@ -18,13 +18,17 @@
package org.eclipse.jetty.http2.server;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jetty.http2.BufferingFlowControlStrategy;
import org.eclipse.jetty.http2.FlowControlStrategy;
import org.eclipse.jetty.http2.HTTP2Connection;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.api.server.ServerSessionListener;
import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.SettingsFrame;
@ -38,12 +42,14 @@ import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.component.LifeCycle;
@ManagedObject
public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConnectionFactory
{
private final Connection.Listener connectionListener = new ConnectionListener();
private final HTTP2SessionContainer sessionContainer = new HTTP2SessionContainer();
private final HttpConfiguration httpConfiguration;
private int maxDynamicTableSize = 4096;
private int initialSessionRecvWindow = 1024 * 1024;
@ -66,6 +72,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
for (String p:protocols)
if (!HTTP2ServerConnection.isSupportedProtocol(p))
throw new IllegalArgumentException("Unsupported HTTP2 Protocol variant: "+p);
addBean(sessionContainer);
this.httpConfiguration = Objects.requireNonNull(httpConfiguration);
addBean(httpConfiguration);
setInputBufferSize(Frame.DEFAULT_MAX_LENGTH + Frame.HEADER_LENGTH);
@ -234,7 +241,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(),
endPoint, httpConfiguration, parser, session, getInputBufferSize(), listener);
connection.addListener(connectionListener);
connection.addListener(sessionContainer);
return configure(connection, connector, endPoint);
}
@ -245,18 +252,43 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
return new ServerParser(connector.getByteBufferPool(), listener, getMaxDynamicTableSize(), getHttpConfiguration().getRequestHeaderSize());
}
private class ConnectionListener implements Connection.Listener
private class HTTP2SessionContainer implements Connection.Listener, Dumpable
{
private final Set<Session> sessions = ConcurrentHashMap.newKeySet();
@Override
public void onOpened(Connection connection)
{
addManaged((LifeCycle)((HTTP2Connection)connection).getSession());
Session session = ((HTTP2Connection)connection).getSession();
sessions.add(session);
LifeCycle.start(session);
}
@Override
public void onClosed(Connection connection)
{
removeBean(((HTTP2Connection)connection).getSession());
Session session = ((HTTP2Connection)connection).getSession();
if (sessions.remove(session))
LifeCycle.stop(session);
}
@Override
public String dump()
{
return ContainerLifeCycle.dump(this);
}
@Override
public void dump(Appendable out, String indent) throws IOException
{
ContainerLifeCycle.dumpObject(out, this);
ContainerLifeCycle.dump(out, indent, sessions);
}
@Override
public String toString()
{
return String.format("%s@%x[size=%d]", getClass().getSimpleName(), hashCode(), sessions.size());
}
}
}