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.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.util.HashSet; import java.util.HashSet;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.zip.Deflater; import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import javax.servlet.AsyncEvent; import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener; import javax.servlet.AsyncListener;
@ -43,6 +43,7 @@ import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.servlets.gzip.AbstractCompressedStream; import org.eclipse.jetty.servlets.gzip.AbstractCompressedStream;
import org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper; 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.servlets.gzip.GzipOutputStream;
import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log; 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 // non-static, as other GzipFilter instances may have different configurations
protected final ThreadLocal<Deflater> _deflater = new ThreadLocal<Deflater>(); 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 final Set<String> _methods=new HashSet<String>();
protected Set<String> _excludedAgents; protected Set<String> _excludedAgents;
protected Set<Pattern> _excludedAgentPatterns; protected Set<Pattern> _excludedAgentPatterns;
@ -464,9 +467,10 @@ public class GzipFilter extends UserAgentFilter
return new AbstractCompressedStream(compressionType,request,this,_vary) return new AbstractCompressedStream(compressionType,request,this,_vary)
{ {
private Deflater _allocatedDeflater; private Deflater _allocatedDeflater;
private byte[] _allocatedBuffer;
@Override @Override
protected DeflaterOutputStream createStream() throws IOException protected OutputStream createStream() throws IOException
{ {
if (compressionType == null) if (compressionType == null)
{ {
@ -483,12 +487,21 @@ public class GzipFilter extends UserAgentFilter
_allocatedDeflater.reset(); _allocatedDeflater.reset();
} }
// acquire buffer
_allocatedBuffer = _buffer.get();
if (_allocatedBuffer==null)
_allocatedBuffer = new byte[_bufferSize];
else
{
_buffer.remove();
}
switch (compressionType) switch (compressionType)
{ {
case GZIP: case GZIP:
return new GzipOutputStream(_response.getOutputStream(),_allocatedDeflater,_bufferSize); return new GzipOutputStream(_response.getOutputStream(),_allocatedDeflater,_allocatedBuffer);
case DEFLATE: case DEFLATE:
return new DeflaterOutputStream(_response.getOutputStream(),_allocatedDeflater,_bufferSize); return new DeflatedOutputStream(_response.getOutputStream(),_allocatedDeflater,_allocatedBuffer);
} }
throw new IllegalStateException(compressionType + " not supported"); throw new IllegalStateException(compressionType + " not supported");
} }
@ -501,6 +514,10 @@ public class GzipFilter extends UserAgentFilter
{ {
_deflater.set(_allocatedDeflater); _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.OutputStreamWriter;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.zip.DeflaterOutputStream;
import javax.servlet.ServletOutputStream; import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener; import javax.servlet.WriteListener;
@ -46,7 +45,7 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
protected final HttpServletResponse _response; protected final HttpServletResponse _response;
protected OutputStream _out; protected OutputStream _out;
protected ByteArrayOutputStream2 _bOut; protected ByteArrayOutputStream2 _bOut;
protected DeflaterOutputStream _compressedOutputStream; protected OutputStream _compressedOutputStream;
protected boolean _closed; protected boolean _closed;
protected boolean _doNotCompress; protected boolean _doNotCompress;
@ -392,7 +391,7 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
* @throws IOException * @throws IOException
* Signals that an I/O exception has occurred. * 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.io.OutputStream;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import java.util.zip.Deflater; import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
/** /**
* Reimplementation of {@link java.util.zip.GZIPOutputStream} that supports reusing a {@link Deflater} instance. * 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[] private final static byte[] GZIP_HEADER = new byte[]
@ -35,9 +34,9 @@ public class GzipOutputStream extends DeflaterOutputStream
private final CRC32 _crc = new CRC32(); 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); out.write(GZIP_HEADER);
} }
@ -51,23 +50,15 @@ public class GzipOutputStream extends DeflaterOutputStream
@Override @Override
public synchronized void finish() throws IOException public synchronized void finish() throws IOException
{ {
if (!def.finished()) if (!_def.finished())
{ {
super.finish(); super.finish();
byte[] trailer = new byte[8]; byte[] trailer = new byte[8];
writeInt((int)_crc.getValue(),trailer,0); writeInt((int)_crc.getValue(),trailer,0);
writeInt(def.getTotalIn(),trailer,4); writeInt(_def.getTotalIn(),trailer,4);
out.write(trailer); out.write(trailer);
} }
} }
@Override
public synchronized void close() throws IOException
{
super.close();
}
private void writeInt(int i, byte[] buf, int offset) private void writeInt(int i, byte[] buf, int offset)
{ {