mirror of
https://github.com/jetty/jetty.project.git
synced 2025-03-04 04:49:12 +00:00
Compression pool for PermessageDeflate extensions for websockets
- Implements Compression Pool (based on apache Commons Pool) - Implements Inflater Pool - Plugs Compression Pools usage in Permessage-Deflate Signed-off-by: bkmz <ilya.cherkasov@gmail.com>
This commit is contained in:
parent
d0a5ba8d5a
commit
c14bf735a2
@ -21,7 +21,7 @@ package org.eclipse.jetty.server.jmh;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
import org.eclipse.jetty.server.DeflaterPool;
|
||||
import org.eclipse.jetty.util.DeflaterPool;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Level;
|
||||
|
@ -1,129 +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.server;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
public class DeflaterPool
|
||||
{
|
||||
private final Queue<Deflater> _pool;
|
||||
private final int _compressionLevel;
|
||||
private final boolean _nowrap;
|
||||
private final AtomicInteger _numDeflaters = new AtomicInteger(0);
|
||||
private final int _capacity;
|
||||
|
||||
|
||||
/**
|
||||
* Create a Pool of {@link Deflater} instances.
|
||||
*
|
||||
* If given a capacity equal to zero the Deflaters 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 DeflaterPool
|
||||
*
|
||||
* @param capacity maximum number of Deflaters which can be contained in the pool
|
||||
* @param compressionLevel the default compression level for new Deflater objects
|
||||
* @param nowrap if true then use GZIP compatible compression for all new Deflater objects
|
||||
*/
|
||||
public DeflaterPool(int capacity, int compressionLevel, boolean nowrap)
|
||||
{
|
||||
_capacity = capacity;
|
||||
_compressionLevel = compressionLevel;
|
||||
_nowrap = nowrap;
|
||||
|
||||
if (_capacity != 0)
|
||||
_pool = new ConcurrentLinkedQueue<>();
|
||||
else
|
||||
_pool = null;
|
||||
}
|
||||
|
||||
protected Deflater newDeflater()
|
||||
{
|
||||
return new Deflater(_compressionLevel, _nowrap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Deflater taken from the pool if it is not empty or a newly created Deflater
|
||||
*/
|
||||
public Deflater acquire()
|
||||
{
|
||||
Deflater deflater;
|
||||
|
||||
if (_capacity == 0)
|
||||
deflater = newDeflater();
|
||||
else if (_capacity < 0)
|
||||
{
|
||||
deflater = _pool.poll();
|
||||
if (deflater == null)
|
||||
deflater = newDeflater();
|
||||
}
|
||||
else
|
||||
{
|
||||
deflater = _pool.poll();
|
||||
if (deflater == null)
|
||||
deflater = newDeflater();
|
||||
else
|
||||
_numDeflaters.decrementAndGet();
|
||||
}
|
||||
|
||||
return deflater;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param deflater returns this Deflater to the pool or calls deflater.end() if the pool is full.
|
||||
*/
|
||||
public void release(Deflater deflater)
|
||||
{
|
||||
if (deflater == null)
|
||||
return;
|
||||
|
||||
if (_capacity == 0)
|
||||
{
|
||||
deflater.end();
|
||||
return;
|
||||
}
|
||||
else if (_capacity < 0)
|
||||
{
|
||||
deflater.reset();
|
||||
_pool.add(deflater);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
int d = _numDeflaters.get();
|
||||
|
||||
if (d >= _capacity)
|
||||
{
|
||||
deflater.end();
|
||||
break;
|
||||
}
|
||||
|
||||
if (_numDeflaters.compareAndSet(d, d + 1))
|
||||
{
|
||||
deflater.reset();
|
||||
_pool.add(deflater);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -34,7 +34,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.*;
|
||||
import org.eclipse.jetty.http.pathmap.PathSpecSet;
|
||||
import org.eclipse.jetty.server.DeflaterPool;
|
||||
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;
|
||||
|
@ -91,6 +91,10 @@
|
||||
<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)
|
||||
|
@ -0,0 +1,170 @@
|
||||
//
|
||||
// ========================================================================
|
||||
// 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.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)
|
||||
{
|
||||
return new GenericObjectPool<>(new InflaterPoolFactory(nowrap), defaultPoolConfig());
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return new GenericObjectPool<>(new DeflaterPoolFactory(compressionLevel, nowrap),
|
||||
defaultPoolConfig());
|
||||
}
|
||||
|
||||
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);
|
||||
config.testOnBorrow = true;
|
||||
config.testOnReturn = false;
|
||||
config.testWhileIdle = false;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
private static GenericObjectPool.Config defaultPoolConfig()
|
||||
{
|
||||
GenericObjectPool.Config config = new GenericObjectPool.Config();
|
||||
|
||||
config.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW;
|
||||
config.minEvictableIdleTimeMillis = TimeUnit.SECONDS.toMillis(5);
|
||||
config.timeBetweenEvictionRunsMillis = TimeUnit.SECONDS.toMillis(30);
|
||||
config.testOnBorrow = true;
|
||||
config.testOnReturn = false;
|
||||
config.testWhileIdle = false;
|
||||
|
||||
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.reset();
|
||||
obj.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateObject(Deflater obj)
|
||||
{
|
||||
return !obj.finished();
|
||||
}
|
||||
|
||||
@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.reset();
|
||||
obj.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateObject(Inflater obj)
|
||||
{
|
||||
return !obj.finished();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activateObject(Inflater obj) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivateObject(Inflater obj) throws Exception
|
||||
{
|
||||
obj.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
//
|
||||
// ========================================================================
|
||||
// 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 java.util.zip.Deflater;
|
||||
|
||||
public class DeflaterPool
|
||||
{
|
||||
private final ObjectPool<Deflater> deflaterPool;
|
||||
|
||||
/**
|
||||
* Create a Pool of {@link Deflater} instances.
|
||||
* <p>
|
||||
* If given a capacity equal to zero the Deflaters 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 DeflaterPool
|
||||
*
|
||||
* @param capacity maximum number of Deflaters which can be contained in the pool
|
||||
* @param compressionLevel the default compression level for new Deflater objects
|
||||
* @param nowrap if true then use GZIP compatible compression for all new Deflater objects
|
||||
*/
|
||||
public DeflaterPool(int capacity, int compressionLevel, boolean nowrap)
|
||||
{
|
||||
deflaterPool = capacity <= 0
|
||||
? CompressionPool.growingDeflaterPool(compressionLevel, nowrap)
|
||||
: CompressionPool.limitedDeflaterPool(capacity, compressionLevel, nowrap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Deflater taken from the pool if it is not empty or a newly created Deflater
|
||||
*/
|
||||
public Deflater acquire()
|
||||
{
|
||||
try
|
||||
{
|
||||
return deflaterPool.borrowObject();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param deflater returns this Deflater to the pool or calls deflater.end() if the pool is full.
|
||||
*/
|
||||
public void release(Deflater deflater)
|
||||
{
|
||||
if (deflater == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
deflaterPool.returnObject(deflater);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
//
|
||||
// ========================================================================
|
||||
// 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 java.util.zip.Inflater;
|
||||
|
||||
public class InflaterPool
|
||||
{
|
||||
|
||||
private final ObjectPool<Inflater> inflaterPool;
|
||||
|
||||
/**
|
||||
* Create a Pool of {@link Inflater} instances.
|
||||
* <p>
|
||||
* If given a capacity equal to zero the Inflaters 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 InflaterPool
|
||||
*
|
||||
* @param capacity maximum number of Inflaters which can be contained in the pool
|
||||
* @param nowrap if true then use GZIP compatible compression for all new Inflater objects
|
||||
*/
|
||||
public InflaterPool(int capacity, boolean nowrap)
|
||||
{
|
||||
inflaterPool = (capacity <= 0)
|
||||
? CompressionPool.growingInflaterPool(nowrap)
|
||||
: CompressionPool.limitedInflaterPool(capacity, nowrap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Inflater taken from the pool if it is not empty or a newly created Inflater
|
||||
*/
|
||||
public Inflater acquire()
|
||||
{
|
||||
try
|
||||
{
|
||||
return inflaterPool.borrowObject();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param inflater returns this Inflater to the pool or calls inflater.end() if the pool is full.
|
||||
*/
|
||||
public void release(Inflater inflater)
|
||||
{
|
||||
try
|
||||
{
|
||||
inflaterPool.returnObject(inflater);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -29,6 +29,8 @@ 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.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
@ -71,6 +73,11 @@ public abstract class CompressExtension extends AbstractExtension
|
||||
private static final int DECOMPRESS_BUF_SIZE = 8 * 1024;
|
||||
|
||||
private final static boolean NOWRAP = true;
|
||||
private final static int POOL_CAPACITY = -1;
|
||||
|
||||
private static final DeflaterPool deflaterPool = new DeflaterPool(POOL_CAPACITY,
|
||||
Deflater.DEFAULT_COMPRESSION, NOWRAP);
|
||||
private static final InflaterPool inflaterPool = new InflaterPool(POOL_CAPACITY, NOWRAP);
|
||||
|
||||
private final Queue<FrameEntry> entries = new ArrayDeque<>();
|
||||
private final IteratingCallback flusher = new Flusher();
|
||||
@ -90,7 +97,7 @@ public abstract class CompressExtension extends AbstractExtension
|
||||
{
|
||||
if (deflaterImpl == null)
|
||||
{
|
||||
deflaterImpl = new Deflater(Deflater.DEFAULT_COMPRESSION,NOWRAP);
|
||||
deflaterImpl = deflaterPool.acquire();
|
||||
}
|
||||
return deflaterImpl;
|
||||
}
|
||||
@ -99,7 +106,7 @@ public abstract class CompressExtension extends AbstractExtension
|
||||
{
|
||||
if (inflaterImpl == null)
|
||||
{
|
||||
inflaterImpl = new Inflater(NOWRAP);
|
||||
inflaterImpl = inflaterPool.acquire();
|
||||
}
|
||||
return inflaterImpl;
|
||||
}
|
||||
@ -370,14 +377,14 @@ public abstract class CompressExtension extends AbstractExtension
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
if(deflaterImpl != null)
|
||||
deflaterImpl.end();
|
||||
deflaterPool.release(deflaterImpl);
|
||||
if(inflaterImpl != null)
|
||||
inflaterImpl.end();
|
||||
inflaterPool.release(inflaterImpl);
|
||||
super.doStop();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user