diff options
author | Greg Wilkins | 2015-02-04 23:02:01 +0000 |
---|---|---|
committer | Greg Wilkins | 2015-02-04 23:02:01 +0000 |
commit | f6cfe07a69669197accb166fc7359a4e2a810871 (patch) | |
tree | 7fb4344e27cbcc328c96b67925479d6593ff3791 | |
parent | 96ebeed9d969f93c4650b95d25e2801b9c328148 (diff) | |
download | org.eclipse.jetty.project-f6cfe07a69669197accb166fc7359a4e2a810871.tar.gz org.eclipse.jetty.project-f6cfe07a69669197accb166fc7359a4e2a810871.tar.xz org.eclipse.jetty.project-f6cfe07a69669197accb166fc7359a4e2a810871.zip |
added direct buffer configuration
17 files changed, 123 insertions, 81 deletions
diff --git a/examples/embedded/src/test/java/org/eclipse/jetty/embedded/GzipHandlerTest.java b/examples/embedded/src/test/java/org/eclipse/jetty/embedded/GzipHandlerTest.java index 5eb898a297..0edc528b17 100644 --- a/examples/embedded/src/test/java/org/eclipse/jetty/embedded/GzipHandlerTest.java +++ b/examples/embedded/src/test/java/org/eclipse/jetty/embedded/GzipHandlerTest.java @@ -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 = diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java index 7e15adf80d..73f0a30bc2 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java @@ -49,6 +49,12 @@ public class HttpTransportOverFCGI implements HttpTransport } @Override + public boolean isOptimizedForDirectBuffers() + { + return false; + } + + @Override public void send(MetaData.Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback) { if (info!=null) diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index aaa2832ce6..e71356064e 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -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; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java index e0a17b5627..d9bbae3c95 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java @@ -92,6 +92,12 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint } @Override + public boolean isOptimizedForDirectBuffers() + { + return false; + } + + @Override public void onOpen() { if (LOG.isDebugEnabled()) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java index 62850f0cc4..1e0d7cb4c6 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java @@ -56,6 +56,12 @@ public class ChannelEndPoint extends AbstractEndPoint } @Override + public boolean isOptimizedForDirectBuffers() + { + return true; + } + + @Override public boolean isOpen() { return _channel.isOpen(); diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java index 92997bea83..b6115a4f8b 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java @@ -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(); + } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java index 153af8b579..ab132bd8a6 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java @@ -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() diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index 691ecc9c0b..f94a44288f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -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(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index d19a4127ff..1e98077006 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -153,6 +153,12 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http } @Override + public boolean isOptimizedForDirectBuffers() + { + return getEndPoint().isOptimizedForDirectBuffers(); + } + + @Override public int getMessagesIn() { return getHttpChannel().getRequests(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java index b7e31c75ee..22ed5421f6 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java @@ -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() diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java index 4c560806c5..45dc188ff8 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java @@ -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(); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java index 761bf07a2b..3f34f4f415 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java @@ -232,6 +232,12 @@ public class ProxyConnectionFactory extends AbstractConnectionFactory _remote=remote; _local=local; } + + @Override + public boolean isOptimizedForDirectBuffers() + { + return _endp.isOptimizedForDirectBuffers(); + } public InetSocketAddress getLocalAddress() { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java index a8908bc824..00bd5d76f9 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java @@ -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 diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpOutputInterceptor.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpOutputInterceptor.java index d205afe7fa..64e4b4a3af 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpOutputInterceptor.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpOutputInterceptor.java @@ -85,6 +85,13 @@ public class GzipHttpOutputInterceptor implements HttpOutput.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) { switch (_state.get()) @@ -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); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index f5b08e3180..4c8f8b1276 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -110,6 +110,11 @@ public class ResponseTest { } + @Override + public boolean isOptimizedForDirectBuffers() + { + return false; + } }); } diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncIOServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncIOServletTest.java index ce8962d408..2818d1b618 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncIOServletTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncIOServletTest.java @@ -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(); diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java index c8e3e1cf08..06ec9620c1 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java @@ -80,6 +80,12 @@ public class HttpTransportOverSPDY implements HttpTransport this.version = session.getVersion(); } + @Override + public boolean isOptimizedForDirectBuffers() + { + return false; + } + protected Stream getStream() { return stream; |