Issue #300 - rework of inflater and deflater pools

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2019-06-12 14:21:40 +10:00
parent e41906fbdb
commit e8115268d4
9 changed files with 165 additions and 248 deletions

View File

@ -21,7 +21,7 @@ package org.eclipse.jetty.server.jmh;
import java.util.concurrent.TimeUnit;
import java.util.zip.Deflater;
import org.eclipse.jetty.util.DeflaterPool;
import org.eclipse.jetty.util.compression.DeflaterPool;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Level;

View File

@ -26,15 +26,21 @@ import java.util.ListIterator;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.zip.Deflater;
import javax.servlet.DispatcherType;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.*;
import org.eclipse.jetty.http.CompressedContentFormat;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.PreEncodedHttpField;
import org.eclipse.jetty.http.pathmap.PathSpecSet;
import org.eclipse.jetty.util.DeflaterPool;
import org.eclipse.jetty.server.HttpOutput;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.HandlerWrapper;
@ -42,6 +48,7 @@ import org.eclipse.jetty.util.IncludeExclude;
import org.eclipse.jetty.util.RegexSet;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.compression.DeflaterPool;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;

View File

@ -91,10 +91,6 @@
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
</dependency>
<!--
This dependency is used to test Slf4jLog.
Due to the introduction of src/test/resource/jetty-logging.properties (and the Log.static{} block)

View File

@ -1,167 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.PoolUtils;
import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
import java.util.concurrent.TimeUnit;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
public class CompressionPool
{
private CompressionPool()
{
}
public static ObjectPool<Inflater> limitedInflaterPool(int capacity, boolean nowrap)
{
return new GenericObjectPool<>(new InflaterPoolFactory(nowrap), blockingBorrowPoolConfig(capacity));
}
public static ObjectPool<Inflater> growingInflaterPool(boolean nowrap)
{
GenericObjectPool<Inflater> objectPool = new GenericObjectPool<>(
new InflaterPoolFactory(nowrap), growingPoolConfig());
return PoolUtils.erodingPool(objectPool);
}
public static ObjectPool<Deflater> limitedDeflaterPool(int capacity, int compressionLevel, boolean nowrap)
{
return new GenericObjectPool<>(new DeflaterPoolFactory(compressionLevel, nowrap),
blockingBorrowPoolConfig(capacity));
}
public static ObjectPool<Deflater> growingDeflaterPool(int compressionLevel, boolean nowrap)
{
GenericObjectPool<Deflater> objectPool = new GenericObjectPool<>(
new DeflaterPoolFactory(compressionLevel, nowrap), growingPoolConfig());
return PoolUtils.erodingPool(objectPool);
}
private static GenericObjectPool.Config blockingBorrowPoolConfig(int capacity)
{
GenericObjectPool.Config config = new GenericObjectPool.Config();
config.maxActive = capacity;
config.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_BLOCK;
config.minEvictableIdleTimeMillis = TimeUnit.SECONDS.toMillis(1);
config.timeBetweenEvictionRunsMillis = TimeUnit.SECONDS.toMillis(5);
return config;
}
private static GenericObjectPool.Config growingPoolConfig()
{
GenericObjectPool.Config config = new GenericObjectPool.Config();
config.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW;
return config;
}
private static class DeflaterPoolFactory implements PoolableObjectFactory<Deflater>
{
private final int compressionLevel;
private final boolean nowrap;
DeflaterPoolFactory(int compressionLevel, boolean nowrap)
{
this.compressionLevel = compressionLevel;
this.nowrap = nowrap;
}
@Override
public Deflater makeObject() throws Exception
{
return new Deflater(compressionLevel, nowrap);
}
@Override
public void destroyObject(Deflater obj) throws Exception
{
obj.end();
}
@Override
public boolean validateObject(Deflater obj)
{
// currently it's not possible to understand if deflater had been finalized.
return true;
}
@Override
public void activateObject(Deflater obj) throws Exception
{
}
@Override
public void passivateObject(Deflater obj) throws Exception
{
obj.reset();
}
}
private static class InflaterPoolFactory implements PoolableObjectFactory<Inflater>
{
private final boolean nowrap;
InflaterPoolFactory(boolean nowrap)
{
this.nowrap = nowrap;
}
@Override
public Inflater makeObject() throws Exception
{
return new Inflater(nowrap);
}
@Override
public void destroyObject(Inflater obj) throws Exception
{
obj.end();
}
@Override
public boolean validateObject(Inflater obj)
{
// currently it's not possible to understand if inflater had been finalized.
return true;
}
@Override
public void activateObject(Inflater obj) throws Exception
{
}
@Override
public void passivateObject(Inflater obj) throws Exception
{
obj.reset();
}
}
}

View File

@ -0,0 +1,118 @@
//
// ========================================================================
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util.compression;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class CompressionPool<T>
{
private final Queue<T> _pool;
private final AtomicInteger _numObjects = new AtomicInteger(0);
private final int _capacity;
/**
* Create a Pool of {@link T} instances.
*
* If given a capacity equal to zero the Objects will not be pooled
* and will be created on acquire and ended on release.
* If given a negative capacity equal to zero there will be no size restrictions on the Pool
*
* @param capacity maximum number of Objects which can be contained in the pool
*/
public CompressionPool(int capacity)
{
_capacity = capacity;
_pool = (_capacity==0) ? null : new ConcurrentLinkedQueue<>();
}
abstract protected T newObject();
abstract protected void end(T object);
abstract protected void reset(T object);
/**
* @return Object taken from the pool if it is not empty or a newly created Object
*/
public T acquire()
{
T object;
if (_capacity == 0)
object = newObject();
else if (_capacity < 0)
{
object = _pool.poll();
if (object == null)
object = newObject();
}
else
{
object = _pool.poll();
if (object == null)
object = newObject();
else
_numObjects.decrementAndGet();
}
return object;
}
/**
* @param object returns this Object to the pool or calls {@link #end(T)} if the pool is full.
*/
public void release(T object)
{
if (object == null)
return;
if (_capacity == 0)
{
end(object);
return;
}
else if (_capacity < 0)
{
reset(object);
_pool.add(object);
}
else
{
while (true)
{
int d = _numObjects.get();
if (d >= _capacity)
{
end(object);
break;
}
if (_numObjects.compareAndSet(d, d + 1))
{
reset(object);
_pool.add(object);
break;
}
}
}
}
}

View File

@ -16,15 +16,14 @@
// ========================================================================
//
package org.eclipse.jetty.util;
import org.apache.commons.pool.ObjectPool;
package org.eclipse.jetty.util.compression;
import java.util.zip.Deflater;
public class DeflaterPool
public class DeflaterPool extends CompressionPool<Deflater>
{
private final ObjectPool<Deflater> deflaterPool;
private final int compressionLevel;
private final boolean nowrap;
/**
* Create a Pool of {@link Deflater} instances.
@ -39,41 +38,26 @@ public class DeflaterPool
*/
public DeflaterPool(int capacity, int compressionLevel, boolean nowrap)
{
deflaterPool = capacity <= 0
? CompressionPool.growingDeflaterPool(compressionLevel, nowrap)
: CompressionPool.limitedDeflaterPool(capacity, compressionLevel, nowrap);
super(capacity);
this.compressionLevel = compressionLevel;
this.nowrap = nowrap;
}
/**
* @return Deflater taken from the pool if it is not empty or a newly created Deflater
*/
public Deflater acquire()
@Override
protected Deflater newObject()
{
try
{
return deflaterPool.borrowObject();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
return new Deflater(compressionLevel, nowrap);
}
/**
* @param deflater returns this Deflater to the pool or calls deflater.end() if the pool is full.
*/
public void release(Deflater deflater)
@Override
protected void end(Deflater deflater)
{
if (deflater == null)
return;
deflater.end();
}
try
{
deflaterPool.returnObject(deflater);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
@Override
protected void reset(Deflater deflater)
{
deflater.reset();
}
}

View File

@ -16,16 +16,13 @@
// ========================================================================
//
package org.eclipse.jetty.util;
import org.apache.commons.pool.ObjectPool;
package org.eclipse.jetty.util.compression;
import java.util.zip.Inflater;
public class InflaterPool
public class InflaterPool extends CompressionPool<Inflater>
{
private final ObjectPool<Inflater> inflaterPool;
private final boolean nowrap;
/**
* Create a Pool of {@link Inflater} instances.
@ -39,38 +36,25 @@ public class InflaterPool
*/
public InflaterPool(int capacity, boolean nowrap)
{
inflaterPool = (capacity <= 0)
? CompressionPool.growingInflaterPool(nowrap)
: CompressionPool.limitedInflaterPool(capacity, nowrap);
super(capacity);
this.nowrap = nowrap;
}
/**
* @return Inflater taken from the pool if it is not empty or a newly created Inflater
*/
public Inflater acquire()
@Override
protected Inflater newObject()
{
try
{
return inflaterPool.borrowObject();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
return new Inflater(nowrap);
}
/**
* @param inflater returns this Inflater to the pool or calls inflater.end() if the pool is full.
*/
public void release(Inflater inflater)
@Override
protected void end(Inflater inflater)
{
try
{
inflaterPool.returnObject(inflater);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
inflater.end();
}
@Override
protected void reset(Inflater inflater)
{
inflater.reset();
}
}

View File

@ -29,9 +29,9 @@ import java.util.zip.Inflater;
import java.util.zip.ZipException;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.DeflaterPool;
import org.eclipse.jetty.util.InflaterPool;
import org.eclipse.jetty.util.IteratingCallback;
import org.eclipse.jetty.util.compression.DeflaterPool;
import org.eclipse.jetty.util.compression.InflaterPool;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.BatchMode;

View File

@ -1068,11 +1068,6 @@
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
</dependencies>
</dependencyManagement>