Issue #5287 - share compression pools and size with max num threads

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2020-10-02 18:35:27 +10:00
parent 7cac3d76bb
commit 0e3cfe8fc2
13 changed files with 93 additions and 41 deletions

View File

@ -43,11 +43,11 @@ import org.eclipse.jetty.http.PreEncodedHttpField;
import org.eclipse.jetty.http.pathmap.PathSpecSet;
import org.eclipse.jetty.server.HttpOutput;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.util.AsciiLowerCaseSet;
import org.eclipse.jetty.util.IncludeExclude;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.compression.CompressionPool;
import org.eclipse.jetty.util.compression.DeflaterPool;
import org.eclipse.jetty.util.compression.InflaterPool;
import org.slf4j.Logger;
@ -163,9 +163,8 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
private static final HttpField TE_CHUNKED = new PreEncodedHttpField(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED.asString());
private static final Pattern COMMA_GZIP = Pattern.compile(".*, *gzip");
private final InflaterPool _inflaterPool;
private final DeflaterPool _deflaterPool;
private InflaterPool _inflaterPool;
private DeflaterPool _deflaterPool;
private int _minGzipSize = DEFAULT_MIN_GZIP_SIZE;
private boolean _syncFlush = false;
private int _inflateBufferSize = -1;
@ -202,11 +201,15 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
if (LOG.isDebugEnabled())
LOG.debug("{} mime types {}", this, _mimeTypes);
}
_deflaterPool = newDeflaterPool();
_inflaterPool = newInflaterPool();
addBean(_deflaterPool);
addBean(_inflaterPool);
@Override
protected void doStart() throws Exception
{
Server server = getServer();
_inflaterPool = InflaterPool.ensurePool(server);
_deflaterPool = DeflaterPool.ensurePool(server);
super.doStart();
}
/**
@ -921,16 +924,6 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
_inflaterPool.setCapacity(capacity);
}
protected InflaterPool newInflaterPool()
{
return new InflaterPool(CompressionPool.DEFAULT_CAPACITY, true);
}
protected DeflaterPool newDeflaterPool()
{
return new DeflaterPool(CompressionPool.DEFAULT_CAPACITY, Deflater.DEFAULT_COMPRESSION, true);
}
@Override
public String toString()
{

View File

@ -20,6 +20,9 @@ package org.eclipse.jetty.util.compression;
import java.util.zip.Deflater;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.thread.ThreadPool;
public class DeflaterPool extends CompressionPool<Deflater>
{
private final int compressionLevel;
@ -60,4 +63,20 @@ public class DeflaterPool extends CompressionPool<Deflater>
{
deflater.reset();
}
public static DeflaterPool ensurePool(ContainerLifeCycle containerLifeCycle)
{
DeflaterPool pool = containerLifeCycle.getBean(DeflaterPool.class);
if (pool != null)
return pool;
int capacity = CompressionPool.DEFAULT_CAPACITY;
ThreadPool.SizedThreadPool threadPool = containerLifeCycle.getBean(ThreadPool.SizedThreadPool.class);
if (threadPool != null)
capacity = threadPool.getMaxThreads();
pool = new DeflaterPool(capacity, Deflater.DEFAULT_COMPRESSION, true);
containerLifeCycle.addBean(pool);
return pool;
}
}

View File

@ -20,6 +20,9 @@ package org.eclipse.jetty.util.compression;
import java.util.zip.Inflater;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.thread.ThreadPool;
public class InflaterPool extends CompressionPool<Inflater>
{
private final boolean nowrap;
@ -57,4 +60,20 @@ public class InflaterPool extends CompressionPool<Inflater>
{
inflater.reset();
}
public static InflaterPool ensurePool(ContainerLifeCycle containerLifeCycle)
{
InflaterPool pool = containerLifeCycle.getBean(InflaterPool.class);
if (pool != null)
return pool;
int capacity = CompressionPool.DEFAULT_CAPACITY;
ThreadPool.SizedThreadPool threadPool = containerLifeCycle.getBean(ThreadPool.SizedThreadPool.class);
if (threadPool != null)
capacity = threadPool.getMaxThreads();
pool = new InflaterPool(capacity, true);
containerLifeCycle.addBean(pool);
return pool;
}
}

View File

@ -23,6 +23,7 @@ import java.util.zip.Deflater;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.compression.CompressionPool;
import org.eclipse.jetty.util.compression.DeflaterPool;
import org.eclipse.jetty.util.compression.InflaterPool;
@ -31,7 +32,7 @@ import org.eclipse.jetty.util.compression.InflaterPool;
* A collection of components which are the resources needed for websockets such as
* {@link ByteBufferPool}, {@link WebSocketExtensionRegistry}, and {@link DecoratedObjectFactory}.
*/
public class WebSocketComponents
public class WebSocketComponents extends ContainerLifeCycle
{
private final DecoratedObjectFactory objectFactory;
private final WebSocketExtensionRegistry extensionRegistry;
@ -41,19 +42,20 @@ public class WebSocketComponents
public WebSocketComponents()
{
this(new WebSocketExtensionRegistry(), new DecoratedObjectFactory(), new MappedByteBufferPool(),
new InflaterPool(CompressionPool.DEFAULT_CAPACITY, true),
new DeflaterPool(CompressionPool.DEFAULT_CAPACITY, Deflater.DEFAULT_COMPRESSION, true));
this(null, null, null, null, null);
}
public WebSocketComponents(WebSocketExtensionRegistry extensionRegistry, DecoratedObjectFactory objectFactory,
ByteBufferPool bufferPool, InflaterPool inflaterPool, DeflaterPool deflaterPool)
{
this.extensionRegistry = extensionRegistry;
this.objectFactory = objectFactory;
this.bufferPool = bufferPool;
this.deflaterPool = deflaterPool;
this.inflaterPool = inflaterPool;
this.extensionRegistry = (extensionRegistry == null) ? new WebSocketExtensionRegistry() : extensionRegistry;
this.objectFactory = (objectFactory == null) ? new DecoratedObjectFactory() : objectFactory;
this.bufferPool = (bufferPool == null) ? new MappedByteBufferPool() : bufferPool;
this.inflaterPool = (inflaterPool == null) ? new InflaterPool(CompressionPool.DEFAULT_CAPACITY, true) : inflaterPool;
this.deflaterPool = (deflaterPool == null) ? new DeflaterPool(CompressionPool.DEFAULT_CAPACITY, Deflater.DEFAULT_COMPRESSION, true) : deflaterPool;
addBean(inflaterPool);
addBean(deflaterPool);
}
public ByteBufferPool getBufferPool()

View File

@ -21,7 +21,10 @@ package org.eclipse.jetty.websocket.core.server;
import javax.servlet.ServletContext;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.compression.DeflaterPool;
import org.eclipse.jetty.util.compression.InflaterPool;
import org.eclipse.jetty.websocket.core.WebSocketComponents;
import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry;
@ -29,23 +32,39 @@ import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry;
* A collection of components which are the resources needed for websockets such as
* {@link ByteBufferPool}, {@link WebSocketExtensionRegistry}, and {@link DecoratedObjectFactory}.
*
* These components should be accessed through {@link WebSocketServerComponents#ensureWebSocketComponents} so that
* These components should be accessed through {@link WebSocketServerComponents#getWebSocketComponents} so that
* the instance can be shared by being stored as a bean on the ContextHandler.
*/
public class WebSocketServerComponents extends WebSocketComponents
{
public static final String WEBSOCKET_COMPONENTS_ATTRIBUTE = WebSocketComponents.class.getName();
public static WebSocketComponents ensureWebSocketComponents(ServletContext servletContext)
WebSocketServerComponents(InflaterPool inflaterPool, DeflaterPool deflaterPool)
{
// Ensure a mapping exists
WebSocketComponents components = (WebSocketComponents)servletContext.getAttribute(WEBSOCKET_COMPONENTS_ATTRIBUTE);
super(null, null, null, inflaterPool, deflaterPool);
}
public static WebSocketComponents ensureWebSocketComponents(Server server, ServletContext servletContext)
{
WebSocketComponents components = server.getBean(WebSocketComponents.class);
if (components == null)
{
components = new WebSocketServerComponents();
servletContext.setAttribute(WEBSOCKET_COMPONENTS_ATTRIBUTE, components);
InflaterPool inflaterPool = InflaterPool.ensurePool(server);
DeflaterPool deflaterPool = DeflaterPool.ensurePool(server);
components = new WebSocketServerComponents(inflaterPool, deflaterPool);
server.addBean(components);
}
servletContext.setAttribute(WEBSOCKET_COMPONENTS_ATTRIBUTE, components);
return components;
}
public static WebSocketComponents getWebSocketComponents(ServletContext servletContext)
{
WebSocketComponents components = (WebSocketComponents)servletContext.getAttribute(WEBSOCKET_COMPONENTS_ATTRIBUTE);
if (components == null)
throw new IllegalStateException("WebSocketComponents has not been created");
return components;
}
}

View File

@ -148,7 +148,7 @@ public class JavaxWebSocketServletContainerInitializer implements ServletContain
JavaxWebSocketServerContainer serverContainer = JavaxWebSocketServerContainer.getContainer(context.getServletContext());
if (serverContainer == null)
{
WebSocketComponents components = WebSocketServerComponents.ensureWebSocketComponents(context.getServletContext());
WebSocketComponents components = WebSocketServerComponents.ensureWebSocketComponents(context.getServer(), context.getServletContext());
FilterHolder filterHolder = WebSocketUpgradeFilter.ensureFilter(context.getServletContext());
WebSocketMapping mapping = WebSocketMapping.ensureMapping(context.getServletContext(), WebSocketMapping.DEFAULT_KEY);
serverContainer = JavaxWebSocketServerContainer.ensureContainer(context.getServletContext());

View File

@ -99,7 +99,7 @@ public class JavaxWebSocketServerContainer extends JavaxWebSocketClientContainer
// Create the Jetty ServerContainer implementation
container = new JavaxWebSocketServerContainer(
WebSocketMapping.ensureMapping(servletContext, WebSocketMapping.DEFAULT_KEY),
WebSocketServerComponents.ensureWebSocketComponents(servletContext),
WebSocketServerComponents.getWebSocketComponents(servletContext),
coreClientSupplier);
contextHandler.addManaged(container);
contextHandler.addEventListener(container);

View File

@ -78,7 +78,7 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
container = new JettyWebSocketServerContainer(
contextHandler,
WebSocketMapping.ensureMapping(servletContext, WebSocketMapping.DEFAULT_KEY),
WebSocketServerComponents.ensureWebSocketComponents(servletContext), executor);
WebSocketServerComponents.getWebSocketComponents(servletContext), executor);
servletContext.setAttribute(JETTY_WEBSOCKET_CONTAINER_ATTRIBUTE, container);
contextHandler.addManaged(container);
contextHandler.addEventListener(container);

View File

@ -132,7 +132,7 @@ public abstract class JettyWebSocketServlet extends HttpServlet
{
ServletContext servletContext = getServletContext();
components = WebSocketServerComponents.ensureWebSocketComponents(servletContext);
components = WebSocketServerComponents.getWebSocketComponents(servletContext);
mapping = new WebSocketMapping(components);
String max = getInitParameter("idleTimeout");

View File

@ -88,7 +88,7 @@ public class JettyWebSocketServletContainerInitializer implements ServletContain
*/
private static JettyWebSocketServerContainer initialize(ServletContextHandler context)
{
WebSocketComponents components = WebSocketServerComponents.ensureWebSocketComponents(context.getServletContext());
WebSocketComponents components = WebSocketServerComponents.ensureWebSocketComponents(context.getServer(), context.getServletContext());
WebSocketMapping mapping = WebSocketMapping.ensureMapping(context.getServletContext(), WebSocketMapping.DEFAULT_KEY);
JettyWebSocketServerContainer container = JettyWebSocketServerContainer.ensureContainer(context.getServletContext());

View File

@ -73,7 +73,7 @@ public class MaxOutgoingFramesTest
JettyWebSocketServletContainerInitializer.configure(contextHandler, (context, container) ->
{
container.addMapping("/", (req, resp) -> serverSocket);
WebSocketComponents components = WebSocketServerComponents.ensureWebSocketComponents(context);
WebSocketComponents components = WebSocketServerComponents.getWebSocketComponents(context);
components.getExtensionRegistry().register(BlockingOutgoingExtension.class.getName(), BlockingOutgoingExtension.class);
});

View File

@ -177,7 +177,7 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
if (mappingKey != null)
mapping = WebSocketMapping.ensureMapping(context, mappingKey);
else
mapping = new WebSocketMapping(WebSocketServerComponents.ensureWebSocketComponents(context));
mapping = new WebSocketMapping(WebSocketServerComponents.getWebSocketComponents(context));
String max = config.getInitParameter("idleTimeout");
if (max == null)

View File

@ -89,7 +89,7 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener
if (mapping == null)
{
mapping = new WebSocketMapping(WebSocketServerComponents.ensureWebSocketComponents(servletContext));
mapping = new WebSocketMapping(WebSocketServerComponents.getWebSocketComponents(servletContext));
servletContext.setAttribute(mappingKey, mapping);
}