423005 reuse gzipfilter buffers

This commit is contained in:
Greg Wilkins 2013-12-05 10:52:32 +11:00
parent 9c39b2e631
commit e9df551352
4 changed files with 111 additions and 21 deletions

View File

@ -20,13 +20,13 @@ package org.eclipse.jetty.servlets;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
@ -43,6 +43,7 @@ import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.servlets.gzip.AbstractCompressedStream;
import org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper;
import org.eclipse.jetty.servlets.gzip.DeflatedOutputStream;
import org.eclipse.jetty.servlets.gzip.GzipOutputStream;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log;
@ -142,6 +143,8 @@ public class GzipFilter extends UserAgentFilter
// non-static, as other GzipFilter instances may have different configurations
protected final ThreadLocal<Deflater> _deflater = new ThreadLocal<Deflater>();
protected final static ThreadLocal<byte[]> _buffer= new ThreadLocal<byte[]>();
protected final Set<String> _methods=new HashSet<String>();
protected Set<String> _excludedAgents;
protected Set<Pattern> _excludedAgentPatterns;
@ -464,9 +467,10 @@ public class GzipFilter extends UserAgentFilter
return new AbstractCompressedStream(compressionType,request,this,_vary)
{
private Deflater _allocatedDeflater;
private byte[] _allocatedBuffer;
@Override
protected DeflaterOutputStream createStream() throws IOException
protected OutputStream createStream() throws IOException
{
if (compressionType == null)
{
@ -483,12 +487,21 @@ public class GzipFilter extends UserAgentFilter
_allocatedDeflater.reset();
}
// acquire buffer
_allocatedBuffer = _buffer.get();
if (_allocatedBuffer==null)
_allocatedBuffer = new byte[_bufferSize];
else
{
_buffer.remove();
}
switch (compressionType)
{
case GZIP:
return new GzipOutputStream(_response.getOutputStream(),_allocatedDeflater,_bufferSize);
return new GzipOutputStream(_response.getOutputStream(),_allocatedDeflater,_allocatedBuffer);
case DEFLATE:
return new DeflaterOutputStream(_response.getOutputStream(),_allocatedDeflater,_bufferSize);
return new DeflatedOutputStream(_response.getOutputStream(),_allocatedDeflater,_allocatedBuffer);
}
throw new IllegalStateException(compressionType + " not supported");
}
@ -501,6 +514,10 @@ public class GzipFilter extends UserAgentFilter
{
_deflater.set(_allocatedDeflater);
}
if (_allocatedBuffer != null && _buffer.get() == null)
{
_buffer.set(_allocatedBuffer);
}
}
};
}

View File

@ -23,7 +23,6 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.zip.DeflaterOutputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
@ -46,7 +45,7 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
protected final HttpServletResponse _response;
protected OutputStream _out;
protected ByteArrayOutputStream2 _bOut;
protected DeflaterOutputStream _compressedOutputStream;
protected OutputStream _compressedOutputStream;
protected boolean _closed;
protected boolean _doNotCompress;
@ -392,7 +391,7 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
* @throws IOException
* Signals that an I/O exception has occurred.
*/
protected abstract DeflaterOutputStream createStream() throws IOException;
protected abstract OutputStream createStream() throws IOException;
}

View File

@ -0,0 +1,83 @@
package org.eclipse.jetty.servlets.gzip;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.Deflater;
/**
* Reimplementation of {@link java.util.zip.DeflaterOutputStream} that supports reusing the buffer.
*/
public class DeflatedOutputStream extends FilterOutputStream
{
protected final Deflater _def;
protected final byte[] _buf;
protected boolean closed = false;
public DeflatedOutputStream(OutputStream out, Deflater deflater, byte[] buffer)
{
super(out);
_def = deflater;
_buf = buffer;
}
@Override
public void write(int b) throws IOException
{
byte[] buf = new byte[1];
buf[0] = (byte)(b & 0xff);
write(buf,0,1);
}
@Override
public void write(byte[] b, int off, int len) throws IOException
{
if (_def.finished())
throw new IOException("Stream already finished");
if ((off | len | (off + len) | (b.length - (off + len))) < 0)
throw new IndexOutOfBoundsException();
if (len == 0)
return;
if (!_def.finished())
{
_def.setInput(b,off,len);
while (!_def.needsInput())
{
deflate();
}
}
}
private void deflate() throws IOException
{
int len = _def.deflate(_buf,0,_buf.length);
if (len > 0)
{
out.write(_buf,0,len);
}
}
public synchronized void finish() throws IOException
{
if (!_def.finished())
{
_def.finish();
while (!_def.finished())
{
deflate();
}
}
}
@Override
public synchronized void close() throws IOException
{
if (!closed)
{
finish();
out.close();
closed = true;
}
}
}

View File

@ -22,12 +22,11 @@ import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.CRC32;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
/**
* Reimplementation of {@link java.util.zip.GZIPOutputStream} that supports reusing a {@link Deflater} instance.
*/
public class GzipOutputStream extends DeflaterOutputStream
public class GzipOutputStream extends DeflatedOutputStream
{
private final static byte[] GZIP_HEADER = new byte[]
@ -35,9 +34,9 @@ public class GzipOutputStream extends DeflaterOutputStream
private final CRC32 _crc = new CRC32();
public GzipOutputStream(OutputStream out, Deflater deflater, int size) throws IOException
public GzipOutputStream(OutputStream out, Deflater deflater, byte[] buffer) throws IOException
{
super(out,deflater,size);
super(out,deflater,buffer);
out.write(GZIP_HEADER);
}
@ -51,24 +50,16 @@ public class GzipOutputStream extends DeflaterOutputStream
@Override
public synchronized void finish() throws IOException
{
if (!def.finished())
if (!_def.finished())
{
super.finish();
byte[] trailer = new byte[8];
writeInt((int)_crc.getValue(),trailer,0);
writeInt(def.getTotalIn(),trailer,4);
writeInt(_def.getTotalIn(),trailer,4);
out.write(trailer);
}
}
@Override
public synchronized void close() throws IOException
{
super.close();
}
private void writeInt(int i, byte[] buf, int offset)
{
int o = offset;