Author: markt
Date: Tue May 20 19:02:46 2014
New Revision: 1596367
URL: http://svn.apache.org/r1596367
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/tc7.0.x/trunk/ (props changed)
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Protocol.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AprProcessor.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AprServletOutputStream.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/BioProcessor.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/BioServletOutputStream.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/NioProcessor.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/NioServletOutputStream.java
tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
tomcat/tc7.0.x/trunk/webapps/docs/config/http.xml
Propchange: tomcat/tc7.0.x/trunk/
------------------------------------------------------------------------------
Merged /tomcat/trunk:r1596275
Modified:
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java?rev=1596367&r1=1596366&r2=1596367&view=diff
==============================================================================
---
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
(original)
+++
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
Tue May 20 19:02:46 2014
@@ -174,6 +174,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/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java?rev=1596367&r1=1596366&r2=1596367&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java
(original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java
Tue May 20 19:02:46 2014
@@ -339,7 +339,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/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java?rev=1596367&r1=1596366&r2=1596367&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java
(original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java
Tue May 20 19:02:46 2014
@@ -298,7 +298,8 @@ public class Http11NioProtocol extends A
HttpUpgradeHandler httpUpgradeProcessor)
throws IOException {
return new NioProcessor(socket, httpUpgradeProcessor,
- ((Http11NioProtocol)
getProtocol()).getEndpoint().getSelectorPool());
+ proto.getEndpoint().getSelectorPool(),
+ proto.getUpgradeAsyncWriteBufferSize());
}
}
}
Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Protocol.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Protocol.java?rev=1596367&r1=1596366&r2=1596367&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Protocol.java
(original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Protocol.java Tue
May 20 19:02:46 2014
@@ -203,7 +203,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());
}
}
}
Modified:
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java?rev=1596367&r1=1596366&r2=1596367&view=diff
==============================================================================
---
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java
(original)
+++
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java
Tue May 20 19:02:46 2014
@@ -56,6 +56,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(int asyncWriteBufferSize) {
+ this.asyncWriteBufferSize = asyncWriteBufferSize;
+ buffer = new byte[asyncWriteBufferSize];
+ }
+
/**
* New Servlet 3.1 method.
@@ -69,7 +79,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;
}
@@ -120,9 +130,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"));
}
}
@@ -143,12 +152,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;
}
}
}
@@ -157,8 +179,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) {
@@ -176,7 +198,7 @@ public abstract class AbstractServletOut
boolean fire = false;
synchronized (fireListenerLock) {
- if (buffer == null && fireListener) {
+ if (bufferLimit == 0 && fireListener) {
fireListener = false;
fire = true;
}
Modified:
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AprProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AprProcessor.java?rev=1596367&r1=1596366&r2=1596367&view=diff
==============================================================================
---
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AprProcessor.java
(original)
+++
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AprProcessor.java
Tue May 20 19:02:46 2014
@@ -32,10 +32,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/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AprServletOutputStream.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AprServletOutputStream.java?rev=1596367&r1=1596366&r2=1596367&view=diff
==============================================================================
---
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AprServletOutputStream.java
(original)
+++
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AprServletOutputStream.java
Tue May 20 19:02:46 2014
@@ -39,7 +39,8 @@ public class AprServletOutputStream exte
private final ByteBuffer sslOutputBuffer;
public AprServletOutputStream(SocketWrapper<Long> wrapper,
- AprEndpoint endpoint) {
+ int asyncWriteBufferSize, AprEndpoint endpoint) {
+ super(asyncWriteBufferSize);
this.endpoint = endpoint;
this.wrapper = wrapper;
this.socket = wrapper.getSocket().longValue();
Modified:
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/BioProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/BioProcessor.java?rev=1596367&r1=1596366&r2=1596367&view=diff
==============================================================================
---
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/BioProcessor.java
(original)
+++
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/BioProcessor.java
Tue May 20 19:02:46 2014
@@ -33,9 +33,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/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/BioServletOutputStream.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/BioServletOutputStream.java?rev=1596367&r1=1596366&r2=1596367&view=diff
==============================================================================
---
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/BioServletOutputStream.java
(original)
+++
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/BioServletOutputStream.java
Tue May 20 19:02:46 2014
@@ -26,9 +26,10 @@ public class BioServletOutputStream exte
private final OutputStream os;
- public BioServletOutputStream(SocketWrapper<Socket> wrapper)
- throws IOException {
- os = wrapper.getSocket().getOutputStream();
+ public BioServletOutputStream(SocketWrapper<Socket> socketWrapper,
+ int asyncWriteBufferSize) throws IOException {
+ super(asyncWriteBufferSize);
+ os = socketWrapper.getSocket().getOutputStream();
}
@Override
Modified:
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/NioProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/NioProcessor.java?rev=1596367&r1=1596366&r2=1596367&view=diff
==============================================================================
---
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/NioProcessor.java
(original)
+++
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/NioProcessor.java
Tue May 20 19:02:46 2014
@@ -32,10 +32,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/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/NioServletOutputStream.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/NioServletOutputStream.java?rev=1596367&r1=1596366&r2=1596367&view=diff
==============================================================================
---
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/NioServletOutputStream.java
(original)
+++
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/NioServletOutputStream.java
Tue May 20 19:02:46 2014
@@ -32,9 +32,10 @@ public class NioServletOutputStream exte
private final int maxWrite;
- public NioServletOutputStream(
- SocketWrapper<NioChannel> wrapper, NioSelectorPool pool) {
- channel = wrapper.getSocket();
+ public NioServletOutputStream(SocketWrapper<NioChannel> socketWrapper,
+ int asyncWriteBufferSize, NioSelectorPool pool) {
+ super(asyncWriteBufferSize);
+ channel = socketWrapper.getSocket();
this.pool = pool;
maxWrite = channel.getBufHandler().getWriteBuffer().capacity();
}
Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1596367&r1=1596366&r2=1596367&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Tue May 20 19:02:46 2014
@@ -59,15 +59,26 @@
<subsection name="Catalina">
<changelog>
<add>
- <bug>56526</bug>: Improved the <code>StuckThreadDetectionValve</code>
to
- optionally interrupt stuck threads to attempt to unblock them.
- (slaurent)
- </add>
- <add>
<bug>56461</bug>: New <code>failCtxIfServletStartFails</code> attribute
on Context and Host configuration to force the context startup to fail
if a load-on-startup servlet fails its startup. (slaurent)
</add>
+ <add>
+ <bug>56526</bug>: Improved the <code>StuckThreadDetectionValve</code>
to
+ optionally interrupt stuck threads to attempt to unblock them.
+ (slaurent)
+ </add>
+ </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>
</section>
Modified: tomcat/tc7.0.x/trunk/webapps/docs/config/http.xml
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/config/http.xml?rev=1596367&r1=1596366&r2=1596367&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/config/http.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/config/http.xml Tue May 20 19:02:46 2014
@@ -523,6 +523,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]