Issue #5198 - GzipHandler should use InflaterPool as well as DeflaterPool

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2020-09-08 15:27:21 +10:00
parent 17ec87f51c
commit 3bdd82eb5e
6 changed files with 78 additions and 24 deletions

View File

@ -29,6 +29,7 @@ import java.util.zip.ZipException;
import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.component.Destroyable; import org.eclipse.jetty.util.component.Destroyable;
import org.eclipse.jetty.util.compression.InflaterPool;
/** /**
* <p>Decoder for the "gzip" content encoding.</p> * <p>Decoder for the "gzip" content encoding.</p>
@ -41,9 +42,10 @@ public class GZIPContentDecoder implements Destroyable
private static final long UINT_MAX = 0xFFFFFFFFL; private static final long UINT_MAX = 0xFFFFFFFFL;
private final List<ByteBuffer> _inflateds = new ArrayList<>(); private final List<ByteBuffer> _inflateds = new ArrayList<>();
private final Inflater _inflater = new Inflater(true); private final InflaterPool _inflaterPool;
private final ByteBufferPool _pool; private final ByteBufferPool _pool;
private final int _bufferSize; private final int _bufferSize;
private Inflater _inflater;
private State _state; private State _state;
private int _size; private int _size;
private long _value; private long _value;
@ -62,6 +64,13 @@ public class GZIPContentDecoder implements Destroyable
public GZIPContentDecoder(ByteBufferPool pool, int bufferSize) public GZIPContentDecoder(ByteBufferPool pool, int bufferSize)
{ {
this(null, pool, bufferSize);
}
public GZIPContentDecoder(InflaterPool inflaterPool, ByteBufferPool pool, int bufferSize)
{
_inflaterPool = inflaterPool;
_inflater = (inflaterPool == null) ? new Inflater(true) : inflaterPool.acquire();
_bufferSize = bufferSize; _bufferSize = bufferSize;
_pool = pool; _pool = pool;
reset(); reset();
@ -420,7 +429,12 @@ public class GZIPContentDecoder implements Destroyable
@Override @Override
public void destroy() public void destroy()
{ {
if (_inflaterPool == null)
_inflater.end(); _inflater.end();
else
_inflaterPool.release(_inflater);
_inflater = null;
} }
public boolean isFinished() public boolean isFinished()

View File

@ -16,6 +16,7 @@
<Set name="checkGzExists" property="jetty.gzip.checkGzExists"/> <Set name="checkGzExists" property="jetty.gzip.checkGzExists"/>
<Set name="compressionLevel" property="jetty.gzip.compressionLevel"/> <Set name="compressionLevel" property="jetty.gzip.compressionLevel"/>
<Set name="inflateBufferSize" property="jetty.gzip.inflateBufferSize"/> <Set name="inflateBufferSize" property="jetty.gzip.inflateBufferSize"/>
<Set name="inflaterPoolCapacity" property="jetty.gzip.inflaterPoolCapacity"/>
<Set name="deflaterPoolCapacity" property="jetty.gzip.deflaterPoolCapacity"/> <Set name="deflaterPoolCapacity" property="jetty.gzip.deflaterPoolCapacity"/>
<Set name="syncFlush" property="jetty.gzip.syncFlush"/> <Set name="syncFlush" property="jetty.gzip.syncFlush"/>
<Set name="dispatcherTypes" property="jetty.gzip.dispatcherTypes"/> <Set name="dispatcherTypes" property="jetty.gzip.dispatcherTypes"/>

View File

@ -26,9 +26,12 @@ etc/jetty-gzip.xml
## Inflate request buffer size, or 0 for no request inflation ## Inflate request buffer size, or 0 for no request inflation
# jetty.gzip.inflateBufferSize=0 # jetty.gzip.inflateBufferSize=0
## Deflater pool max size (-1 for unlimited, 0 for no pool) ## Deflater pool max size (-1 for unlimited, 0 for no pooling)
# jetty.gzip.deflaterPoolCapacity=-1 # jetty.gzip.deflaterPoolCapacity=-1
## Inflater pool max size (-1 for unlimited, 0 for no pooling)
# jetty.gzip.inflaterPoolCapacity=-1
## Set the {@link Deflater} flush mode to use. ## Set the {@link Deflater} flush mode to use.
# jetty.gzip.syncFlush=false # jetty.gzip.syncFlush=false

View File

@ -46,7 +46,9 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.util.IncludeExclude; import org.eclipse.jetty.util.IncludeExclude;
import org.eclipse.jetty.util.StringUtil; 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.DeflaterPool;
import org.eclipse.jetty.util.compression.InflaterPool;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -160,8 +162,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 HttpField TE_CHUNKED = new PreEncodedHttpField(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED.asString());
private static final Pattern COMMA_GZIP = Pattern.compile(".*, *gzip"); private static final Pattern COMMA_GZIP = Pattern.compile(".*, *gzip");
private int poolCapacity = -1; private final InflaterPool _inflaterPool;
private DeflaterPool _deflaterPool = null; private final DeflaterPool _deflaterPool;
private int _minGzipSize = DEFAULT_MIN_GZIP_SIZE; private int _minGzipSize = DEFAULT_MIN_GZIP_SIZE;
private boolean _syncFlush = false; private boolean _syncFlush = false;
@ -199,6 +201,11 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("{} mime types {}", this, _mimeTypes); LOG.debug("{} mime types {}", this, _mimeTypes);
_deflaterPool = newDeflaterPool();
_inflaterPool = newInflaterPool();
addBean(_deflaterPool);
addBean(_inflaterPool);
} }
/** /**
@ -409,13 +416,6 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
} }
} }
@Override
protected void doStart() throws Exception
{
_deflaterPool = newDeflaterPool(poolCapacity);
super.doStart();
}
@Override @Override
public Deflater getDeflater(Request request, long contentLength) public Deflater getDeflater(Request request, long contentLength)
{ {
@ -566,7 +566,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("{} inflate {}", this, request); LOG.debug("{} inflate {}", this, request);
baseRequest.getHttpInput().addInterceptor(new GzipHttpInputInterceptor(baseRequest.getHttpChannel().getByteBufferPool(), _inflateBufferSize)); baseRequest.getHttpInput().addInterceptor(new GzipHttpInputInterceptor(_inflaterPool, baseRequest.getHttpChannel().getByteBufferPool(), _inflateBufferSize));
} }
// Are we already being gzipped? // Are we already being gzipped?
@ -891,7 +891,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
*/ */
public int getDeflaterPoolCapacity() public int getDeflaterPoolCapacity()
{ {
return poolCapacity; return _deflaterPool.getCapacity();
} }
/** /**
@ -902,12 +902,38 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
if (isStarted()) if (isStarted())
throw new IllegalStateException(getState()); throw new IllegalStateException(getState());
poolCapacity = capacity; _deflaterPool.setCapacity(capacity);
} }
protected DeflaterPool newDeflaterPool(int capacity) /**
* Gets the maximum number of Inflators that the DeflaterPool can hold.
*
* @return the Deflater pool capacity
*/
public int getInflaterPoolCapacity()
{ {
return new DeflaterPool(capacity, Deflater.DEFAULT_COMPRESSION, true); return _inflaterPool.getCapacity();
}
/**
* Sets the maximum number of Inflators that the DeflaterPool can hold.
*/
public void setInflaterPoolCapacity(int capacity)
{
if (isStarted())
throw new IllegalStateException(getState());
_inflaterPool.setCapacity(capacity);
}
protected InflaterPool newInflaterPool()
{
return new InflaterPool(CompressionPool.INFINITE_CAPACITY, true);
}
protected DeflaterPool newDeflaterPool()
{
return new DeflaterPool(CompressionPool.INFINITE_CAPACITY, Deflater.DEFAULT_COMPRESSION, true);
} }
@Override @Override

View File

@ -25,6 +25,7 @@ import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.server.HttpInput; import org.eclipse.jetty.server.HttpInput;
import org.eclipse.jetty.server.HttpInput.Content; import org.eclipse.jetty.server.HttpInput.Content;
import org.eclipse.jetty.util.component.Destroyable; import org.eclipse.jetty.util.component.Destroyable;
import org.eclipse.jetty.util.compression.InflaterPool;
/** /**
* An HttpInput Interceptor that inflates GZIP encoded request content. * An HttpInput Interceptor that inflates GZIP encoded request content.
@ -34,9 +35,9 @@ public class GzipHttpInputInterceptor implements HttpInput.Interceptor, Destroya
private final Decoder _decoder; private final Decoder _decoder;
private ByteBuffer _chunk; private ByteBuffer _chunk;
public GzipHttpInputInterceptor(ByteBufferPool pool, int bufferSize) public GzipHttpInputInterceptor(InflaterPool inflaterPool, ByteBufferPool pool, int bufferSize)
{ {
_decoder = new Decoder(pool, bufferSize); _decoder = new Decoder(inflaterPool, pool, bufferSize);
} }
@Override @Override
@ -66,9 +67,9 @@ public class GzipHttpInputInterceptor implements HttpInput.Interceptor, Destroya
private class Decoder extends GZIPContentDecoder private class Decoder extends GZIPContentDecoder
{ {
private Decoder(ByteBufferPool pool, int bufferSize) private Decoder(InflaterPool inflaterPool, ByteBufferPool bufferPool, int bufferSize)
{ {
super(pool, bufferSize); super(inflaterPool, bufferPool, bufferSize);
} }
@Override @Override

View File

@ -30,7 +30,7 @@ public abstract class CompressionPool<T> extends AbstractLifeCycle
private final Queue<T> _pool; private final Queue<T> _pool;
private final AtomicInteger _numObjects = new AtomicInteger(0); private final AtomicInteger _numObjects = new AtomicInteger(0);
private final int _capacity; private int _capacity;
/** /**
* Create a Pool of {@link T} instances. * Create a Pool of {@link T} instances.
@ -44,7 +44,17 @@ public abstract class CompressionPool<T> extends AbstractLifeCycle
public CompressionPool(int capacity) public CompressionPool(int capacity)
{ {
_capacity = capacity; _capacity = capacity;
_pool = (_capacity == 0) ? null : new ConcurrentLinkedQueue<>(); _pool = new ConcurrentLinkedQueue<>();
}
public int getCapacity()
{
return _capacity;
}
public void setCapacity(int capacity)
{
_capacity = capacity;
} }
protected abstract T newObject(); protected abstract T newObject();
@ -85,7 +95,6 @@ public abstract class CompressionPool<T> extends AbstractLifeCycle
if (_capacity == 0 || !isRunning()) if (_capacity == 0 || !isRunning())
{ {
end(object); end(object);
return;
} }
else if (_capacity < 0) else if (_capacity < 0)
{ {