added direct buffer configuration
This commit is contained in:
parent
96ebeed9d9
commit
f6cfe07a69
|
@ -39,11 +39,14 @@ import org.eclipse.jetty.server.Request;
|
|||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
|
||||
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AdvancedRunner.class)
|
||||
public class GzipHandlerTest
|
||||
{
|
||||
private static String __content =
|
||||
|
|
|
@ -48,6 +48,12 @@ public class HttpTransportOverFCGI implements HttpTransport
|
|||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptimizedForDirectBuffers()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(MetaData.Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback)
|
||||
{
|
||||
|
|
|
@ -54,6 +54,14 @@ public class HttpTransportOverHTTP2 implements HttpTransport
|
|||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptimizedForDirectBuffers()
|
||||
{
|
||||
// Because sent buffers are passed directly to the endpoint without
|
||||
// copying we can defer to the endpoint
|
||||
return connection.getEndPoint().isOptimizedForDirectBuffers();
|
||||
}
|
||||
|
||||
public IStream getStream()
|
||||
{
|
||||
return stream;
|
||||
|
|
|
@ -91,6 +91,12 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
|
|||
_connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptimizedForDirectBuffers()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
|
|
|
@ -55,6 +55,12 @@ public class ChannelEndPoint extends AbstractEndPoint
|
|||
_gathering=_channel instanceof GatheringByteChannel?((GatheringByteChannel)_channel):null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptimizedForDirectBuffers()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen()
|
||||
{
|
||||
|
|
|
@ -237,5 +237,10 @@ public interface EndPoint extends Closeable
|
|||
*/
|
||||
void onClose();
|
||||
|
||||
/** Is the endpoint optimized for DirectBuffer usage
|
||||
* @return True if direct buffers can be used optimally.
|
||||
*/
|
||||
boolean isOptimizedForDirectBuffers();
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ public class SslConnection extends AbstractConnection
|
|||
private ByteBuffer _decryptedInput;
|
||||
private ByteBuffer _encryptedInput;
|
||||
private ByteBuffer _encryptedOutput;
|
||||
private final boolean _encryptedDirectBuffers = false;
|
||||
private final boolean _encryptedDirectBuffers = true;
|
||||
private final boolean _decryptedDirectBuffers = false;
|
||||
private boolean _renegotiationAllowed;
|
||||
private final Runnable _runCompletWrite = new Runnable()
|
||||
|
|
|
@ -186,6 +186,12 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
|||
return _configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptimizedForDirectBuffers()
|
||||
{
|
||||
return getHttpTransport().isOptimizedForDirectBuffers();
|
||||
}
|
||||
|
||||
public Server getServer()
|
||||
{
|
||||
return _connector.getServer();
|
||||
|
|
|
@ -152,6 +152,12 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
return _generator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptimizedForDirectBuffers()
|
||||
{
|
||||
return getEndPoint().isOptimizedForDirectBuffers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMessagesIn()
|
||||
{
|
||||
|
|
|
@ -58,13 +58,14 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
{
|
||||
void write(ByteBuffer content, boolean complete, Callback callback);
|
||||
Interceptor getNextInterceptor();
|
||||
boolean isOptimizedForDirectBuffers();
|
||||
}
|
||||
|
||||
private static Logger LOG = Log.getLogger(HttpOutput.class);
|
||||
|
||||
private final HttpChannel _channel;
|
||||
private final SharedBlockingCallback _writeBlock;
|
||||
private Interceptor _filter;
|
||||
private Interceptor _interceptor;
|
||||
|
||||
/** Bytes written via the write API (excludes bytes written via sendContent). Used to autocommit once content length is written. */
|
||||
private long _written;
|
||||
|
@ -90,7 +91,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
public HttpOutput(HttpChannel channel)
|
||||
{
|
||||
_channel = channel;
|
||||
_filter = channel;
|
||||
_interceptor = channel;
|
||||
_writeBlock = new SharedBlockingCallback()
|
||||
{
|
||||
@Override
|
||||
|
@ -111,12 +112,12 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
|
||||
public Interceptor getInterceptor()
|
||||
{
|
||||
return _filter;
|
||||
return _interceptor;
|
||||
}
|
||||
|
||||
public void setInterceptor(Interceptor filter)
|
||||
{
|
||||
_filter=filter;
|
||||
_interceptor=filter;
|
||||
}
|
||||
|
||||
public boolean isWritten()
|
||||
|
@ -162,7 +163,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
|
||||
protected void write(ByteBuffer content, boolean complete, Callback callback)
|
||||
{
|
||||
_filter.write(content, complete, callback);
|
||||
_interceptor.write(content, complete, callback);
|
||||
}
|
||||
|
||||
private void abort(Throwable failure)
|
||||
|
@ -336,7 +337,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
if (!complete && len<=_commitSize)
|
||||
{
|
||||
if (_aggregate == null)
|
||||
_aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), false);
|
||||
_aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), _interceptor.isOptimizedForDirectBuffers());
|
||||
|
||||
// YES - fill the aggregate with content from the buffer
|
||||
int filled = BufferUtil.fill(_aggregate, b, off, len);
|
||||
|
@ -381,7 +382,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
if (!complete && len<=_commitSize)
|
||||
{
|
||||
if (_aggregate == null)
|
||||
_aggregate = _channel.getByteBufferPool().acquire(capacity, false);
|
||||
_aggregate = _channel.getByteBufferPool().acquire(capacity, _interceptor.isOptimizedForDirectBuffers());
|
||||
|
||||
// YES - fill the aggregate with content from the buffer
|
||||
int filled = BufferUtil.fill(_aggregate, b, off, len);
|
||||
|
@ -509,7 +510,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
{
|
||||
case OPEN:
|
||||
if (_aggregate == null)
|
||||
_aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), false);
|
||||
_aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), _interceptor.isOptimizedForDirectBuffers());
|
||||
BufferUtil.append(_aggregate, (byte)b);
|
||||
|
||||
// Check if all written or full
|
||||
|
@ -529,7 +530,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
continue;
|
||||
|
||||
if (_aggregate == null)
|
||||
_aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), false);
|
||||
_aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), _interceptor.isOptimizedForDirectBuffers());
|
||||
BufferUtil.append(_aggregate, (byte)b);
|
||||
|
||||
// Check if all written or full
|
||||
|
@ -795,7 +796,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
public void recycle()
|
||||
{
|
||||
resetBuffer();
|
||||
_filter=_channel;
|
||||
_interceptor=_channel;
|
||||
}
|
||||
|
||||
public void resetBuffer()
|
||||
|
|
|
@ -23,6 +23,10 @@ import java.nio.ByteBuffer;
|
|||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Abstraction of the outbound HTTP transport.
|
||||
*/
|
||||
public interface HttpTransport
|
||||
{
|
||||
void send(MetaData.Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback);
|
||||
|
@ -47,4 +51,10 @@ public interface HttpTransport
|
|||
* @param failure the failure that caused the abort.
|
||||
*/
|
||||
void abort(Throwable failure);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Is the underlying transport optimized for DirectBuffer usage
|
||||
* @return True if direct buffers can be used optimally.
|
||||
*/
|
||||
boolean isOptimizedForDirectBuffers();
|
||||
}
|
||||
|
|
|
@ -232,6 +232,12 @@ public class ProxyConnectionFactory extends AbstractConnectionFactory
|
|||
_remote=remote;
|
||||
_local=local;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptimizedForDirectBuffers()
|
||||
{
|
||||
return _endp.isOptimizedForDirectBuffers();
|
||||
}
|
||||
|
||||
public InetSocketAddress getLocalAddress()
|
||||
{
|
||||
|
|
|
@ -37,7 +37,6 @@ import org.eclipse.jetty.http.HttpMethod;
|
|||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.PathMap;
|
||||
import org.eclipse.jetty.server.HttpChannel;
|
||||
import org.eclipse.jetty.server.HttpOutput;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
|
@ -51,7 +50,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
/**
|
||||
* A Handler that can dynamically GZIP compress responses. Unlike
|
||||
* previous and 3rd party GzipFilters, this mechanism works with asynchronously
|
||||
* generated responses and does not need to wrap the response or it's ownput
|
||||
* generated responses and does not need to wrap the response or it's output
|
||||
* stream. Instead it uses the efficient {@link HttpOutput.Interceptor} mechanism.
|
||||
* <p>
|
||||
* The handler can be applied to the entire server (a gzip.mod is included in
|
||||
|
|
|
@ -84,6 +84,13 @@ public class GzipHttpOutputInterceptor implements HttpOutput.Interceptor
|
|||
return _interceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptimizedForDirectBuffers()
|
||||
{
|
||||
return false; // No point as deflator is in user space.
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer content, boolean complete, Callback callback)
|
||||
{
|
||||
|
@ -133,12 +140,7 @@ public class GzipHttpOutputInterceptor implements HttpOutput.Interceptor
|
|||
private void gzip(ByteBuffer content, boolean complete, final Callback callback)
|
||||
{
|
||||
if (content.hasRemaining() || complete)
|
||||
{
|
||||
if (content.hasArray())
|
||||
new GzipArrayCB(content,complete,callback).iterate();
|
||||
else
|
||||
new GzipBufferCB(content,complete,callback).iterate();
|
||||
}
|
||||
new GzipBufferCB(content,complete,callback).iterate();
|
||||
else
|
||||
callback.succeeded();
|
||||
}
|
||||
|
@ -215,7 +217,6 @@ public class GzipHttpOutputInterceptor implements HttpOutput.Interceptor
|
|||
fields.put(HttpHeader.ETAG,etag);
|
||||
}
|
||||
|
||||
|
||||
LOG.debug("{} compressing {}",this,_deflater);
|
||||
_state.set(GZState.COMPRESSING);
|
||||
|
||||
|
@ -270,67 +271,15 @@ public class GzipHttpOutputInterceptor implements HttpOutput.Interceptor
|
|||
{
|
||||
return _state.get()==GZState.MIGHT_COMPRESS;
|
||||
}
|
||||
private class GzipArrayCB extends IteratingNestedCallback
|
||||
{
|
||||
private final boolean _complete;
|
||||
public GzipArrayCB(ByteBuffer content, boolean complete, Callback callback)
|
||||
{
|
||||
super(callback);
|
||||
_complete=complete;
|
||||
|
||||
byte[] array=content.array();
|
||||
int off=content.arrayOffset()+content.position();
|
||||
int len=content.remaining();
|
||||
_crc.update(array,off,len);
|
||||
_deflater.setInput(array,off,len);
|
||||
if (complete)
|
||||
_deflater.finish();
|
||||
content.position(content.limit());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Action process() throws Exception
|
||||
{
|
||||
if (_deflater.needsInput())
|
||||
{
|
||||
if (_deflater.finished())
|
||||
{
|
||||
_factory.recycle(_deflater);
|
||||
_deflater=null;
|
||||
_channel.getByteBufferPool().release(_buffer);
|
||||
_buffer=null;
|
||||
return Action.SUCCEEDED;
|
||||
}
|
||||
|
||||
if (!_complete)
|
||||
return Action.SUCCEEDED;
|
||||
|
||||
_deflater.finish();
|
||||
}
|
||||
|
||||
BufferUtil.compact(_buffer);
|
||||
int off=_buffer.arrayOffset()+_buffer.limit();
|
||||
int len=_buffer.capacity()-_buffer.limit()- (_complete?8:0);
|
||||
int produced=_deflater.deflate(_buffer.array(),off,len,Deflater.NO_FLUSH);
|
||||
_buffer.limit(_buffer.limit()+produced);
|
||||
boolean complete=_deflater.finished();
|
||||
if (complete)
|
||||
addTrailer();
|
||||
|
||||
_interceptor.write(_buffer,complete,this);
|
||||
return Action.SCHEDULED;
|
||||
}
|
||||
}
|
||||
|
||||
private class GzipBufferCB extends IteratingNestedCallback
|
||||
{
|
||||
private final ByteBuffer _input;
|
||||
private ByteBuffer _copy;
|
||||
private final ByteBuffer _content;
|
||||
private final boolean _last;
|
||||
public GzipBufferCB(ByteBuffer content, boolean complete, Callback callback)
|
||||
{
|
||||
super(callback);
|
||||
_input=_channel.getByteBufferPool().acquire(Math.min(_bufferSize,content.remaining()),false);
|
||||
_content=content;
|
||||
_last=complete;
|
||||
}
|
||||
|
@ -348,6 +297,11 @@ public class GzipHttpOutputInterceptor implements HttpOutput.Interceptor
|
|||
_deflater=null;
|
||||
_channel.getByteBufferPool().release(_buffer);
|
||||
_buffer=null;
|
||||
if (_copy!=null)
|
||||
{
|
||||
_channel.getByteBufferPool().release(_copy);
|
||||
_copy=null;
|
||||
}
|
||||
return Action.SUCCEEDED;
|
||||
}
|
||||
|
||||
|
@ -358,17 +312,31 @@ public class GzipHttpOutputInterceptor implements HttpOutput.Interceptor
|
|||
|
||||
_deflater.finish();
|
||||
}
|
||||
else if (_content.hasArray())
|
||||
{
|
||||
byte[] array=_content.array();
|
||||
int off=_content.arrayOffset()+_content.position();
|
||||
int len=_content.remaining();
|
||||
BufferUtil.clear(_content);
|
||||
|
||||
_crc.update(array,off,len);
|
||||
_deflater.setInput(array,off,len);
|
||||
if (_last)
|
||||
_deflater.finish();
|
||||
}
|
||||
else
|
||||
{
|
||||
BufferUtil.clearToFill(_input);
|
||||
int took=BufferUtil.put(_content,_input);
|
||||
BufferUtil.flipToFlush(_input,0);
|
||||
if (_copy==null)
|
||||
_copy=_channel.getByteBufferPool().acquire(_bufferSize,false);
|
||||
BufferUtil.clearToFill(_copy);
|
||||
int took=BufferUtil.put(_content,_copy);
|
||||
BufferUtil.flipToFlush(_copy,0);
|
||||
if (took==0)
|
||||
throw new IllegalStateException();
|
||||
|
||||
byte[] array=_input.array();
|
||||
int off=_input.arrayOffset()+_input.position();
|
||||
int len=_input.remaining();
|
||||
byte[] array=_copy.array();
|
||||
int off=_copy.arrayOffset()+_copy.position();
|
||||
int len=_copy.remaining();
|
||||
|
||||
_crc.update(array,off,len);
|
||||
_deflater.setInput(array,off,len);
|
||||
|
|
|
@ -110,6 +110,11 @@ public class ResponseTest
|
|||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptimizedForDirectBuffers()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.net.Socket;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
|
@ -518,8 +519,6 @@ public class AsyncIOServletTest
|
|||
|
||||
in.setReadListener(new ReadListener()
|
||||
{
|
||||
transient int _i=0;
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t)
|
||||
{
|
||||
|
@ -575,6 +574,8 @@ public class AsyncIOServletTest
|
|||
{
|
||||
OutputStream output = client.getOutputStream();
|
||||
output.write(request.getBytes("UTF-8"));
|
||||
output.flush();
|
||||
Thread.sleep(100);
|
||||
output.write(data);
|
||||
output.flush();
|
||||
|
||||
|
|
|
@ -80,6 +80,12 @@ public class HttpTransportOverSPDY implements HttpTransport
|
|||
this.version = session.getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptimizedForDirectBuffers()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Stream getStream()
|
||||
{
|
||||
return stream;
|
||||
|
|
Loading…
Reference in New Issue