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: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to