Author: markt
Date: Tue May 20 14:46:48 2014
New Revision: 1596275
URL: http://svn.apache.org/r1596275
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=56521
Implement a TODO
Reuse the async write buffer between writes to reduce allocation and GC
overhead. Based on a patch by leonzhx.
Also:
- don't re-allocate the buffer / move the data in the buffer if the buffer is
partially written on a subsequent write
- make the buffer size configurable, defaulting to 8k
Modified:
tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java
tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Protocol.java
tomcat/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java
tomcat/trunk/java/org/apache/coyote/http11/Http11Protocol.java
tomcat/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java
tomcat/trunk/java/org/apache/coyote/http11/upgrade/AprProcessor.java
tomcat/trunk/java/org/apache/coyote/http11/upgrade/AprServletOutputStream.java
tomcat/trunk/java/org/apache/coyote/http11/upgrade/BioProcessor.java
tomcat/trunk/java/org/apache/coyote/http11/upgrade/BioServletOutputStream.java
tomcat/trunk/java/org/apache/coyote/http11/upgrade/Nio2Processor.java
tomcat/trunk/java/org/apache/coyote/http11/upgrade/Nio2ServletInputStream.java
tomcat/trunk/java/org/apache/coyote/http11/upgrade/Nio2ServletOutputStream.java
tomcat/trunk/java/org/apache/coyote/http11/upgrade/NioProcessor.java
tomcat/trunk/java/org/apache/coyote/http11/upgrade/NioServletOutputStream.java
tomcat/trunk/webapps/docs/changelog.xml
tomcat/trunk/webapps/docs/config/http.xml
Modified: tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java Tue
May 20 14:46:48 2014
@@ -166,6 +166,17 @@ public abstract class AbstractHttp11Prot
}
+ /**
+ * The size of the buffer used by the ServletOutputStream when performing
+ * delayed asynchronous writes using HTTP upgraded connections.
+ */
+ private int upgradeAsyncWriteBufferSize = 8192;
+ public int getUpgradeAsyncWriteBufferSize() { return
upgradeAsyncWriteBufferSize; }
+ public void setUpgradeAsyncWriteBufferSize(int
upgradeAsyncWriteBufferSize) {
+ this.upgradeAsyncWriteBufferSize = upgradeAsyncWriteBufferSize;
+ }
+
+
// ------------------------------------------------ HTTP specific
properties
// ------------------------------------------ passed through to the
EndPoint
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java Tue May
20 14:46:48 2014
@@ -345,7 +345,8 @@ public class Http11AprProtocol extends A
HttpUpgradeHandler httpUpgradeProcessor)
throws IOException {
return new AprProcessor(socket, httpUpgradeProcessor,
- (AprEndpoint) proto.endpoint);
+ (AprEndpoint) proto.endpoint,
+ proto.getUpgradeAsyncWriteBufferSize());
}
}
}
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Protocol.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Protocol.java?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Protocol.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Protocol.java Tue May
20 14:46:48 2014
@@ -265,7 +265,8 @@ public class Http11Nio2Protocol extends
SocketWrapper<Nio2Channel> socket,
HttpUpgradeHandler httpUpgradeProcessor)
throws IOException {
- return new Nio2Processor(proto.endpoint, socket,
httpUpgradeProcessor);
+ return new Nio2Processor(proto.endpoint, socket,
httpUpgradeProcessor,
+ proto.getUpgradeAsyncWriteBufferSize());
}
@Override
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java Tue May
20 14:46:48 2014
@@ -305,7 +305,8 @@ public class Http11NioProtocol extends A
HttpUpgradeHandler httpUpgradeProcessor)
throws IOException {
return new NioProcessor(socket, httpUpgradeProcessor,
- ((Http11NioProtocol)
getProtocol()).getEndpoint().getSelectorPool());
+ proto.getEndpoint().getSelectorPool(),
+ proto.getUpgradeAsyncWriteBufferSize());
}
@Override
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11Protocol.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11Protocol.java?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11Protocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11Protocol.java Tue May 20
14:46:48 2014
@@ -212,7 +212,8 @@ public class Http11Protocol extends Abst
SocketWrapper<Socket> socket,
HttpUpgradeHandler httpUpgradeProcessor)
throws IOException {
- return new BioProcessor(socket, httpUpgradeProcessor);
+ return new BioProcessor(socket, httpUpgradeProcessor,
+ proto.getUpgradeAsyncWriteBufferSize());
}
@Override
Modified:
tomcat/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
---
tomcat/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java
(original)
+++
tomcat/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java
Tue May 20 14:46:48 2014
@@ -57,10 +57,16 @@ public abstract class AbstractServletOut
// Writes guarded by writeLock
private volatile byte[] buffer;
+ private volatile int bufferPos;
+ private volatile int bufferLimit;
+ private final int asyncWriteBufferSize;
- public AbstractServletOutputStream(SocketWrapper<S> socketWrapper) {
+ public AbstractServletOutputStream(SocketWrapper<S> socketWrapper,
+ int asyncWriteBufferSize) {
this.socketWrapper = socketWrapper;
+ this.asyncWriteBufferSize = asyncWriteBufferSize;
+ buffer = new byte[asyncWriteBufferSize];
}
@@ -74,7 +80,7 @@ public abstract class AbstractServletOut
// Make sure isReady() and onWritePossible() have a consistent view of
// buffer and fireListener when determining if the listener should fire
synchronized (fireListenerLock) {
- boolean result = (buffer == null);
+ boolean result = (bufferLimit == 0);
fireListener = !result;
return result;
}
@@ -134,9 +140,8 @@ public abstract class AbstractServletOut
private void preWriteChecks() {
- if (buffer != null) {
- throw new IllegalStateException(
- sm.getString("upgrade.sis.write.ise"));
+ if (bufferLimit != 0) {
+ throw new
IllegalStateException(sm.getString("upgrade.sis.write.ise"));
}
}
@@ -157,12 +162,25 @@ public abstract class AbstractServletOut
// write executes.
int written = doWrite(false, b, off, len);
if (written < len) {
- // TODO: - Reuse the buffer
- // - Only reallocate if it gets too big (>8k?)
- buffer = new byte[len - written];
- System.arraycopy(b, off + written, buffer, 0, len - written);
+ if (b == buffer) {
+ // This is a partial write of the existing buffer. Just
+ // increment the current position
+ bufferPos += written;
+ } else {
+ // This is a new partial write
+ int bytesLeft = len - written;
+ if (bytesLeft > buffer.length) {
+ buffer = new byte[bytesLeft];
+ } else if (bytesLeft < asyncWriteBufferSize &&
+ buffer.length > asyncWriteBufferSize) {
+ buffer = new byte[asyncWriteBufferSize];
+ }
+ bufferPos = 0;
+ bufferLimit = bytesLeft;
+ System.arraycopy(b, off + written, buffer, bufferPos,
bufferLimit);
+ }
} else {
- buffer = null;
+ bufferLimit = 0;
}
}
}
@@ -171,8 +189,8 @@ public abstract class AbstractServletOut
protected final void onWritePossible() throws IOException {
try {
synchronized (writeLock) {
- if (buffer != null) {
- writeInternal(buffer, 0, buffer.length);
+ if (bufferLimit > 0) {
+ writeInternal(buffer, bufferPos, bufferLimit - bufferPos);
}
}
} catch (Throwable t) {
@@ -190,7 +208,7 @@ public abstract class AbstractServletOut
// should fire
boolean fire = false;
synchronized (fireListenerLock) {
- if (buffer == null && fireListener) {
+ if (bufferLimit == 0 && fireListener) {
fireListener = false;
fire = true;
}
Modified: tomcat/trunk/java/org/apache/coyote/http11/upgrade/AprProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/AprProcessor.java?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/upgrade/AprProcessor.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/upgrade/AprProcessor.java Tue
May 20 14:46:48 2014
@@ -33,10 +33,11 @@ public class AprProcessor extends Abstra
private static final int INFINITE_TIMEOUT = -1;
public AprProcessor(SocketWrapper<Long> wrapper,
- HttpUpgradeHandler httpUpgradeProcessor, AprEndpoint endpoint) {
+ HttpUpgradeHandler httpUpgradeProcessor, AprEndpoint endpoint,
+ int asyncWriteBufferSize) {
super(httpUpgradeProcessor,
new AprServletInputStream(wrapper),
- new AprServletOutputStream(wrapper, endpoint));
+ new AprServletOutputStream(wrapper, asyncWriteBufferSize,
endpoint));
Socket.timeoutSet(wrapper.getSocket().longValue(), INFINITE_TIMEOUT);
}
Modified:
tomcat/trunk/java/org/apache/coyote/http11/upgrade/AprServletOutputStream.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/AprServletOutputStream.java?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
---
tomcat/trunk/java/org/apache/coyote/http11/upgrade/AprServletOutputStream.java
(original)
+++
tomcat/trunk/java/org/apache/coyote/http11/upgrade/AprServletOutputStream.java
Tue May 20 14:46:48 2014
@@ -38,8 +38,8 @@ public class AprServletOutputStream exte
private final ByteBuffer sslOutputBuffer;
public AprServletOutputStream(SocketWrapper<Long> socketWrapper,
- AprEndpoint endpoint) {
- super(socketWrapper);
+ int asyncWriteBufferSize, AprEndpoint endpoint) {
+ super(socketWrapper, asyncWriteBufferSize);
this.endpoint = endpoint;
this.socket = socketWrapper.getSocket().longValue();
if (endpoint.isSSLEnabled()) {
Modified: tomcat/trunk/java/org/apache/coyote/http11/upgrade/BioProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/BioProcessor.java?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/upgrade/BioProcessor.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/upgrade/BioProcessor.java Tue
May 20 14:46:48 2014
@@ -34,9 +34,10 @@ public class BioProcessor extends Abstra
private static final int INFINITE_TIMEOUT = 0;
public BioProcessor(SocketWrapper<Socket> wrapper,
- HttpUpgradeHandler httpUpgradeProcessor) throws IOException {
+ HttpUpgradeHandler httpUpgradeProcessor,
+ int asyncWriteBufferSize) throws IOException {
super(httpUpgradeProcessor, new BioServletInputStream(wrapper),
- new BioServletOutputStream(wrapper));
+ new BioServletOutputStream(wrapper, asyncWriteBufferSize));
wrapper.getSocket().setSoTimeout(INFINITE_TIMEOUT);
}
Modified:
tomcat/trunk/java/org/apache/coyote/http11/upgrade/BioServletOutputStream.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/BioServletOutputStream.java?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
---
tomcat/trunk/java/org/apache/coyote/http11/upgrade/BioServletOutputStream.java
(original)
+++
tomcat/trunk/java/org/apache/coyote/http11/upgrade/BioServletOutputStream.java
Tue May 20 14:46:48 2014
@@ -26,9 +26,9 @@ public class BioServletOutputStream exte
private final OutputStream os;
- public BioServletOutputStream(SocketWrapper<Socket> socketWrapper)
- throws IOException {
- super(socketWrapper);
+ public BioServletOutputStream(SocketWrapper<Socket> socketWrapper,
+ int asyncWriteBufferSize) throws IOException {
+ super(socketWrapper, asyncWriteBufferSize);
os = socketWrapper.getSocket().getOutputStream();
}
Modified: tomcat/trunk/java/org/apache/coyote/http11/upgrade/Nio2Processor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/Nio2Processor.java?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/upgrade/Nio2Processor.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/upgrade/Nio2Processor.java Tue
May 20 14:46:48 2014
@@ -34,10 +34,11 @@ public class Nio2Processor extends Abstr
public Nio2Processor(AbstractEndpoint<Nio2Channel> endpoint,
SocketWrapper<Nio2Channel> wrapper,
- HttpUpgradeHandler httpUpgradeProcessor) {
+ HttpUpgradeHandler httpUpgradeProcessor,
+ int asyncWriteBufferSize) {
super(httpUpgradeProcessor,
- new Nio2ServletInputStream(endpoint, wrapper),
- new Nio2ServletOutputStream(endpoint, wrapper));
+ new Nio2ServletInputStream(wrapper, endpoint),
+ new Nio2ServletOutputStream(wrapper, asyncWriteBufferSize,
endpoint));
wrapper.setTimeout(INFINITE_TIMEOUT);
}
Modified:
tomcat/trunk/java/org/apache/coyote/http11/upgrade/Nio2ServletInputStream.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/Nio2ServletInputStream.java?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
---
tomcat/trunk/java/org/apache/coyote/http11/upgrade/Nio2ServletInputStream.java
(original)
+++
tomcat/trunk/java/org/apache/coyote/http11/upgrade/Nio2ServletInputStream.java
Tue May 20 14:46:48 2014
@@ -41,7 +41,7 @@ public class Nio2ServletInputStream exte
private boolean flipped = false;
private volatile boolean readPending = false;
- public Nio2ServletInputStream(AbstractEndpoint<Nio2Channel> endpoint0,
SocketWrapper<Nio2Channel> wrapper) {
+ public Nio2ServletInputStream(SocketWrapper<Nio2Channel> wrapper,
AbstractEndpoint<Nio2Channel> endpoint0) {
this.endpoint = endpoint0;
this.wrapper = wrapper;
this.channel = wrapper.getSocket();
Modified:
tomcat/trunk/java/org/apache/coyote/http11/upgrade/Nio2ServletOutputStream.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/Nio2ServletOutputStream.java?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
---
tomcat/trunk/java/org/apache/coyote/http11/upgrade/Nio2ServletOutputStream.java
(original)
+++
tomcat/trunk/java/org/apache/coyote/http11/upgrade/Nio2ServletOutputStream.java
Tue May 20 14:46:48 2014
@@ -41,8 +41,9 @@ public class Nio2ServletOutputStream ext
private final CompletionHandler<Integer, ByteBuffer> completionHandler;
private final Semaphore writePending = new Semaphore(1);
- public Nio2ServletOutputStream(AbstractEndpoint<Nio2Channel> endpoint0,
SocketWrapper<Nio2Channel> socketWrapper0) {
- super(socketWrapper0);
+ public Nio2ServletOutputStream(SocketWrapper<Nio2Channel> socketWrapper0,
+ int asyncWriteBufferSize, AbstractEndpoint<Nio2Channel> endpoint0)
{
+ super(socketWrapper0, asyncWriteBufferSize);
this.endpoint = endpoint0;
channel = socketWrapper0.getSocket();
maxWrite = channel.getBufHandler().getWriteBuffer().capacity();
Modified: tomcat/trunk/java/org/apache/coyote/http11/upgrade/NioProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/NioProcessor.java?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/upgrade/NioProcessor.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/upgrade/NioProcessor.java Tue
May 20 14:46:48 2014
@@ -33,10 +33,11 @@ public class NioProcessor extends Abstra
private static final int INFINITE_TIMEOUT = -1;
public NioProcessor(SocketWrapper<NioChannel> wrapper,
- HttpUpgradeHandler httpUpgradeProcessor, NioSelectorPool pool) {
+ HttpUpgradeHandler httpUpgradeProcessor, NioSelectorPool pool,
+ int asyncWriteBufferSize) {
super(httpUpgradeProcessor,
new NioServletInputStream(wrapper, pool),
- new NioServletOutputStream(wrapper, pool));
+ new NioServletOutputStream(wrapper, asyncWriteBufferSize,
pool));
wrapper.setTimeout(INFINITE_TIMEOUT);
}
Modified:
tomcat/trunk/java/org/apache/coyote/http11/upgrade/NioServletOutputStream.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/NioServletOutputStream.java?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
---
tomcat/trunk/java/org/apache/coyote/http11/upgrade/NioServletOutputStream.java
(original)
+++
tomcat/trunk/java/org/apache/coyote/http11/upgrade/NioServletOutputStream.java
Tue May 20 14:46:48 2014
@@ -32,9 +32,9 @@ public class NioServletOutputStream exte
private final int maxWrite;
- public NioServletOutputStream(
- SocketWrapper<NioChannel> socketWrapper, NioSelectorPool pool) {
- super(socketWrapper);
+ public NioServletOutputStream(SocketWrapper<NioChannel> socketWrapper,
+ int asyncWriteBufferSize, NioSelectorPool pool) {
+ super(socketWrapper, asyncWriteBufferSize);
channel = socketWrapper.getSocket();
this.pool = pool;
maxWrite = channel.getBufHandler().getWriteBuffer().capacity();
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Tue May 20 14:46:48 2014
@@ -85,6 +85,17 @@
</scode>
</changelog>
</subsection>
+ <subsection name="Coyote">
+ <changelog>
+ <fix>
+ <bug>56521</bug>: Re-use the asynchronous write buffer between writes
to
+ reduce allocation and GC overhead. Based on a patch by leonzhx. Also
+ make the buffer size configurable and remove copying of data within
+ buffer when the buffer is only partially written on a subsequent write.
+ (markt)
+ </fix>
+ </changelog>
+ </subsection>
<subsection name="Jasper">
<changelog>
<update>
Modified: tomcat/trunk/webapps/docs/config/http.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/http.xml?rev=1596275&r1=1596274&r2=1596275&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/http.xml (original)
+++ tomcat/trunk/webapps/docs/config/http.xml Tue May 20 14:46:48 2014
@@ -530,6 +530,14 @@
</p>
</attribute>
+ <attribute name="upgradeAsyncWriteBufferSize" required="false">
+ <p>The default size of the buffer to allocate to for asynchronous writes
+ that can not be completed in a single operation. Data that can't be
+ written immediately will be stored in this buffer until it can be
written.
+ If more data needs to be stored than space is available in the buffer
than
+ the size of the buffer will be increased for the duration of the write.
If
+ not specified the default value of 8192 will be used.</p>
+ </attribute>
</attributes>
</subsection>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]